migrate rustc_macros to syn 2.0

This commit is contained in:
Deadbeef
2023-03-27 13:44:06 +00:00
parent 33289132ec
commit af74ef8993
11 changed files with 275 additions and 344 deletions

View File

@@ -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"
}