migrate rustc_macros to syn 2.0
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
use crate::diagnostics::error::{
|
||||
span_err, throw_invalid_attr, throw_invalid_nested_attr, throw_span_err, DiagnosticDeriveError,
|
||||
span_err, throw_invalid_attr, throw_span_err, DiagnosticDeriveError,
|
||||
};
|
||||
use proc_macro::Span;
|
||||
use proc_macro2::{Ident, TokenStream};
|
||||
@@ -8,11 +8,13 @@ use std::cell::RefCell;
|
||||
use std::collections::{BTreeSet, HashMap};
|
||||
use std::fmt;
|
||||
use std::str::FromStr;
|
||||
use syn::meta::ParseNestedMeta;
|
||||
use syn::punctuated::Punctuated;
|
||||
use syn::{parenthesized, LitStr, Path, Token};
|
||||
use syn::{spanned::Spanned, Attribute, Field, Meta, Type, TypeTuple};
|
||||
use syn::{MetaList, MetaNameValue, NestedMeta, Path};
|
||||
use synstructure::{BindingInfo, VariantInfo};
|
||||
|
||||
use super::error::{invalid_attr, invalid_nested_attr};
|
||||
use super::error::invalid_attr;
|
||||
|
||||
thread_local! {
|
||||
pub static CODE_IDENT_COUNT: RefCell<u32> = RefCell::new(0);
|
||||
@@ -60,8 +62,8 @@ pub(crate) fn report_type_error(
|
||||
attr: &Attribute,
|
||||
ty_name: &str,
|
||||
) -> Result<!, DiagnosticDeriveError> {
|
||||
let name = attr.path.segments.last().unwrap().ident.to_string();
|
||||
let meta = attr.parse_meta()?;
|
||||
let name = attr.path().segments.last().unwrap().ident.to_string();
|
||||
let meta = &attr.meta;
|
||||
|
||||
throw_span_err!(
|
||||
attr.span().unwrap(),
|
||||
@@ -422,55 +424,53 @@ pub(super) enum AllowMultipleAlternatives {
|
||||
/// `#[suggestion*(code("foo", "bar"))]` attribute field
|
||||
pub(super) fn build_suggestion_code(
|
||||
code_field: &Ident,
|
||||
meta: &Meta,
|
||||
nested: ParseNestedMeta<'_>,
|
||||
fields: &impl HasFieldMap,
|
||||
allow_multiple: AllowMultipleAlternatives,
|
||||
) -> TokenStream {
|
||||
let values = match meta {
|
||||
// `code = "foo"`
|
||||
Meta::NameValue(MetaNameValue { lit: syn::Lit::Str(s), .. }) => vec![s],
|
||||
// `code("foo", "bar")`
|
||||
Meta::List(MetaList { nested, .. }) => {
|
||||
let values = match (|| {
|
||||
let values: Vec<LitStr> = if let Ok(val) = nested.value() {
|
||||
vec![val.parse()?]
|
||||
} else {
|
||||
let content;
|
||||
parenthesized!(content in nested.input);
|
||||
|
||||
if let AllowMultipleAlternatives::No = allow_multiple {
|
||||
span_err(
|
||||
meta.span().unwrap(),
|
||||
nested.input.span().unwrap(),
|
||||
"expected exactly one string literal for `code = ...`",
|
||||
)
|
||||
.emit();
|
||||
vec![]
|
||||
} else if nested.is_empty() {
|
||||
span_err(
|
||||
meta.span().unwrap(),
|
||||
"expected at least one string literal for `code(...)`",
|
||||
)
|
||||
.emit();
|
||||
vec![]
|
||||
} else {
|
||||
nested
|
||||
.into_iter()
|
||||
.filter_map(|item| {
|
||||
if let NestedMeta::Lit(syn::Lit::Str(s)) = item {
|
||||
Some(s)
|
||||
} else {
|
||||
span_err(
|
||||
item.span().unwrap(),
|
||||
"`code(...)` must contain only string literals",
|
||||
)
|
||||
.emit();
|
||||
None
|
||||
}
|
||||
})
|
||||
.collect()
|
||||
let literals = Punctuated::<LitStr, Token![,]>::parse_terminated(&content);
|
||||
|
||||
match literals {
|
||||
Ok(p) if p.is_empty() => {
|
||||
span_err(
|
||||
content.span().unwrap(),
|
||||
"expected at least one string literal for `code(...)`",
|
||||
)
|
||||
.emit();
|
||||
vec![]
|
||||
}
|
||||
Ok(p) => p.into_iter().collect(),
|
||||
Err(_) => {
|
||||
span_err(
|
||||
content.span().unwrap(),
|
||||
"`code(...)` must contain only string literals",
|
||||
)
|
||||
.emit();
|
||||
vec![]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
span_err(
|
||||
meta.span().unwrap(),
|
||||
r#"`code = "..."`/`code(...)` must contain only string literals"#,
|
||||
)
|
||||
.emit();
|
||||
vec![]
|
||||
}
|
||||
};
|
||||
|
||||
Ok(values)
|
||||
})() {
|
||||
Ok(x) => x,
|
||||
Err(e) => return e.into_compile_error(),
|
||||
};
|
||||
|
||||
if let AllowMultipleAlternatives::Yes = allow_multiple {
|
||||
@@ -601,11 +601,9 @@ impl SubdiagnosticKind {
|
||||
|
||||
let span = attr.span().unwrap();
|
||||
|
||||
let name = attr.path.segments.last().unwrap().ident.to_string();
|
||||
let name = attr.path().segments.last().unwrap().ident.to_string();
|
||||
let name = name.as_str();
|
||||
|
||||
let meta = attr.parse_meta()?;
|
||||
|
||||
let mut kind = match name {
|
||||
"label" => SubdiagnosticKind::Label,
|
||||
"note" => SubdiagnosticKind::Note,
|
||||
@@ -618,7 +616,7 @@ impl SubdiagnosticKind {
|
||||
name.strip_prefix("suggestion").and_then(SuggestionKind::from_suffix)
|
||||
{
|
||||
if suggestion_kind != SuggestionKind::Normal {
|
||||
invalid_attr(attr, &meta)
|
||||
invalid_attr(attr)
|
||||
.help(format!(
|
||||
r#"Use `#[suggestion(..., style = "{suggestion_kind}")]` instead"#
|
||||
))
|
||||
@@ -635,7 +633,7 @@ impl SubdiagnosticKind {
|
||||
name.strip_prefix("multipart_suggestion").and_then(SuggestionKind::from_suffix)
|
||||
{
|
||||
if suggestion_kind != SuggestionKind::Normal {
|
||||
invalid_attr(attr, &meta)
|
||||
invalid_attr(attr)
|
||||
.help(format!(
|
||||
r#"Use `#[multipart_suggestion(..., style = "{suggestion_kind}")]` instead"#
|
||||
))
|
||||
@@ -647,16 +645,16 @@ impl SubdiagnosticKind {
|
||||
applicability: None,
|
||||
}
|
||||
} else {
|
||||
throw_invalid_attr!(attr, &meta);
|
||||
throw_invalid_attr!(attr);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let nested = match meta {
|
||||
Meta::List(MetaList { ref nested, .. }) => {
|
||||
let list = match &attr.meta {
|
||||
Meta::List(list) => {
|
||||
// An attribute with properties, such as `#[suggestion(code = "...")]` or
|
||||
// `#[error(some::slug)]`
|
||||
nested
|
||||
list
|
||||
}
|
||||
Meta::Path(_) => {
|
||||
// An attribute without a slug or other properties, such as `#[note]` - return
|
||||
@@ -678,52 +676,51 @@ impl SubdiagnosticKind {
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
throw_invalid_attr!(attr, &meta)
|
||||
throw_invalid_attr!(attr)
|
||||
}
|
||||
};
|
||||
|
||||
let mut code = None;
|
||||
let mut suggestion_kind = None;
|
||||
|
||||
let mut nested_iter = nested.into_iter().peekable();
|
||||
let mut first = true;
|
||||
let mut slug = None;
|
||||
|
||||
// Peek at the first nested attribute: if it's a slug path, consume it.
|
||||
let slug = if let Some(NestedMeta::Meta(Meta::Path(path))) = nested_iter.peek() {
|
||||
let path = path.clone();
|
||||
// Advance the iterator.
|
||||
nested_iter.next();
|
||||
Some(path)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
for nested_attr in nested_iter {
|
||||
let meta = match nested_attr {
|
||||
NestedMeta::Meta(ref meta) => meta,
|
||||
NestedMeta::Lit(_) => {
|
||||
invalid_nested_attr(attr, nested_attr).emit();
|
||||
continue;
|
||||
list.parse_nested_meta(|nested| {
|
||||
if nested.input.is_empty() || nested.input.peek(Token![,]) {
|
||||
if first {
|
||||
slug = Some(nested.path);
|
||||
} else {
|
||||
span_err(nested.input.span().unwrap(), "a diagnostic slug must be the first argument to the attribute").emit();
|
||||
}
|
||||
};
|
||||
|
||||
let span = meta.span().unwrap();
|
||||
let nested_name = meta.path().segments.last().unwrap().ident.to_string();
|
||||
first = false;
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
first = false;
|
||||
|
||||
let nested_name = nested.path.segments.last().unwrap().ident.to_string();
|
||||
let nested_name = nested_name.as_str();
|
||||
|
||||
let string_value = match meta {
|
||||
Meta::NameValue(MetaNameValue { lit: syn::Lit::Str(value), .. }) => Some(value),
|
||||
let path_span = nested.path.span().unwrap();
|
||||
let val_span = nested.input.span().unwrap();
|
||||
|
||||
Meta::Path(_) => throw_invalid_nested_attr!(attr, nested_attr, |diag| {
|
||||
diag.help("a diagnostic slug must be the first argument to the attribute")
|
||||
}),
|
||||
_ => None,
|
||||
};
|
||||
macro get_string() {
|
||||
{
|
||||
let Ok(value) = nested.value().and_then(|x| x.parse::<LitStr>()) else {
|
||||
span_err(val_span, "expected `= \"xxx\"`").emit();
|
||||
return Ok(());
|
||||
};
|
||||
value
|
||||
}
|
||||
}
|
||||
|
||||
match (nested_name, &mut kind) {
|
||||
("code", SubdiagnosticKind::Suggestion { code_field, .. }) => {
|
||||
let code_init = build_suggestion_code(
|
||||
code_field,
|
||||
meta,
|
||||
nested,
|
||||
fields,
|
||||
AllowMultipleAlternatives::Yes,
|
||||
);
|
||||
@@ -734,13 +731,9 @@ impl SubdiagnosticKind {
|
||||
SubdiagnosticKind::Suggestion { ref mut applicability, .. }
|
||||
| SubdiagnosticKind::MultipartSuggestion { ref mut applicability, .. },
|
||||
) => {
|
||||
let Some(value) = string_value else {
|
||||
invalid_nested_attr(attr, nested_attr).emit();
|
||||
continue;
|
||||
};
|
||||
|
||||
let value = get_string!();
|
||||
let value = Applicability::from_str(&value.value()).unwrap_or_else(|()| {
|
||||
span_err(span, "invalid applicability").emit();
|
||||
span_err(value.span().unwrap(), "invalid applicability").emit();
|
||||
Applicability::Unspecified
|
||||
});
|
||||
applicability.set_once(value, span);
|
||||
@@ -750,10 +743,7 @@ impl SubdiagnosticKind {
|
||||
SubdiagnosticKind::Suggestion { .. }
|
||||
| SubdiagnosticKind::MultipartSuggestion { .. },
|
||||
) => {
|
||||
let Some(value) = string_value else {
|
||||
invalid_nested_attr(attr, nested_attr).emit();
|
||||
continue;
|
||||
};
|
||||
let value = get_string!();
|
||||
|
||||
let value = value.value().parse().unwrap_or_else(|()| {
|
||||
span_err(value.span().unwrap(), "invalid suggestion style")
|
||||
@@ -767,22 +757,24 @@ impl SubdiagnosticKind {
|
||||
|
||||
// Invalid nested attribute
|
||||
(_, SubdiagnosticKind::Suggestion { .. }) => {
|
||||
invalid_nested_attr(attr, nested_attr)
|
||||
span_err(path_span, "invalid nested attribute")
|
||||
.help(
|
||||
"only `style`, `code` and `applicability` are valid nested attributes",
|
||||
)
|
||||
.emit();
|
||||
}
|
||||
(_, SubdiagnosticKind::MultipartSuggestion { .. }) => {
|
||||
invalid_nested_attr(attr, nested_attr)
|
||||
span_err(path_span, "invalid nested attribute")
|
||||
.help("only `style` and `applicability` are valid nested attributes")
|
||||
.emit()
|
||||
.emit();
|
||||
}
|
||||
_ => {
|
||||
invalid_nested_attr(attr, nested_attr).emit();
|
||||
span_err(path_span, "invalid nested attribute").emit();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
match kind {
|
||||
SubdiagnosticKind::Suggestion {
|
||||
@@ -845,5 +837,5 @@ pub(super) fn should_generate_set_arg(field: &Field) -> bool {
|
||||
}
|
||||
|
||||
pub(super) fn is_doc_comment(attr: &Attribute) -> bool {
|
||||
attr.path.segments.last().unwrap().ident == "doc"
|
||||
attr.path().segments.last().unwrap().ident == "doc"
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user