migrate rustc_macros to syn 2.0
This commit is contained in:
parent
33289132ec
commit
af74ef8993
11 changed files with 275 additions and 344 deletions
24
Cargo.lock
24
Cargo.lock
|
@ -632,7 +632,7 @@ dependencies = [
|
|||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 1.0.102",
|
||||
"synstructure",
|
||||
"synstructure 0.12.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -4994,8 +4994,8 @@ dependencies = [
|
|||
"fluent-syntax",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 1.0.102",
|
||||
"synstructure",
|
||||
"syn 2.0.8",
|
||||
"synstructure 0.13.0",
|
||||
"unic-langid",
|
||||
]
|
||||
|
||||
|
@ -6131,6 +6131,18 @@ dependencies = [
|
|||
"unicode-xid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "synstructure"
|
||||
version = "0.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "285ba80e733fac80aa4270fbcdf83772a79b80aa35c97075320abfee4a915b06"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.8",
|
||||
"unicode-xid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tar"
|
||||
version = "0.4.38"
|
||||
|
@ -7154,7 +7166,7 @@ dependencies = [
|
|||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 1.0.102",
|
||||
"synstructure",
|
||||
"synstructure 0.12.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -7175,7 +7187,7 @@ dependencies = [
|
|||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 1.0.102",
|
||||
"synstructure",
|
||||
"synstructure 0.12.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -7204,5 +7216,5 @@ dependencies = [
|
|||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 1.0.102",
|
||||
"synstructure",
|
||||
"synstructure 0.12.6",
|
||||
]
|
||||
|
|
|
@ -10,8 +10,8 @@ proc-macro = true
|
|||
annotate-snippets = "0.9"
|
||||
fluent-bundle = "0.15.2"
|
||||
fluent-syntax = "0.11"
|
||||
synstructure = "0.12.1"
|
||||
syn = { version = "1", features = ["full"] }
|
||||
synstructure = "0.13.0"
|
||||
syn = { version = "2", features = ["full"] }
|
||||
proc-macro2 = "1"
|
||||
quote = "1"
|
||||
unic-langid = { version = "0.9.0", features = ["macros"] }
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
#![deny(unused_must_use)]
|
||||
|
||||
use crate::diagnostics::error::{
|
||||
invalid_nested_attr, span_err, throw_invalid_attr, throw_invalid_nested_attr, throw_span_err,
|
||||
DiagnosticDeriveError,
|
||||
span_err, throw_invalid_attr, throw_span_err, DiagnosticDeriveError,
|
||||
};
|
||||
use crate::diagnostics::utils::{
|
||||
build_field_mapping, is_doc_comment, report_error_if_not_applied_to_span, report_type_error,
|
||||
|
@ -11,9 +10,8 @@ use crate::diagnostics::utils::{
|
|||
};
|
||||
use proc_macro2::{Ident, Span, TokenStream};
|
||||
use quote::{format_ident, quote};
|
||||
use syn::{
|
||||
parse_quote, spanned::Spanned, Attribute, Meta, MetaList, MetaNameValue, NestedMeta, Path, Type,
|
||||
};
|
||||
use syn::Token;
|
||||
use syn::{parse_quote, spanned::Spanned, Attribute, Meta, Path, Type};
|
||||
use synstructure::{BindingInfo, Structure, VariantInfo};
|
||||
|
||||
/// What kind of diagnostic is being derived - a fatal/error/warning or a lint?
|
||||
|
@ -77,7 +75,7 @@ impl DiagnosticDeriveBuilder {
|
|||
match ast.data {
|
||||
syn::Data::Struct(..) | syn::Data::Enum(..) => (),
|
||||
syn::Data::Union(..) => {
|
||||
span_err(span, "diagnostic derives can only be used on structs and enums");
|
||||
span_err(span, "diagnostic derives can only be used on structs and enums").emit();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -160,8 +158,7 @@ impl<'a> DiagnosticDeriveVariantBuilder<'a> {
|
|||
};
|
||||
|
||||
if let SubdiagnosticKind::MultipartSuggestion { .. } = subdiag {
|
||||
let meta = attr.parse_meta()?;
|
||||
throw_invalid_attr!(attr, &meta, |diag| diag
|
||||
throw_invalid_attr!(attr, |diag| diag
|
||||
.help("consider creating a `Subdiagnostic` instead"));
|
||||
}
|
||||
|
||||
|
@ -191,71 +188,39 @@ impl<'a> DiagnosticDeriveVariantBuilder<'a> {
|
|||
return Ok(quote! {});
|
||||
}
|
||||
|
||||
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 first = true;
|
||||
|
||||
if name == "diag" {
|
||||
let Meta::List(MetaList { ref nested, .. }) = meta else {
|
||||
throw_invalid_attr!(
|
||||
attr,
|
||||
&meta
|
||||
);
|
||||
};
|
||||
|
||||
let mut nested_iter = nested.into_iter().peekable();
|
||||
|
||||
match nested_iter.peek() {
|
||||
Some(NestedMeta::Meta(Meta::Path(slug))) => {
|
||||
self.slug.set_once(slug.clone(), slug.span().unwrap());
|
||||
nested_iter.next();
|
||||
}
|
||||
Some(NestedMeta::Meta(Meta::NameValue { .. })) => {}
|
||||
Some(nested_attr) => throw_invalid_nested_attr!(attr, nested_attr, |diag| diag
|
||||
.help("a diagnostic slug is required as the first argument")),
|
||||
None => throw_invalid_attr!(attr, &meta, |diag| diag
|
||||
.help("a diagnostic slug is required as the first argument")),
|
||||
};
|
||||
|
||||
// Remaining attributes are optional, only `code = ".."` at the moment.
|
||||
let mut tokens = TokenStream::new();
|
||||
for nested_attr in nested_iter {
|
||||
let (value, path) = match nested_attr {
|
||||
NestedMeta::Meta(Meta::NameValue(MetaNameValue {
|
||||
lit: syn::Lit::Str(value),
|
||||
path,
|
||||
..
|
||||
})) => (value, path),
|
||||
NestedMeta::Meta(Meta::Path(_)) => {
|
||||
invalid_nested_attr(attr, nested_attr)
|
||||
.help("diagnostic slug must be the first argument")
|
||||
.emit();
|
||||
continue;
|
||||
}
|
||||
_ => {
|
||||
invalid_nested_attr(attr, nested_attr).emit();
|
||||
continue;
|
||||
}
|
||||
attr.parse_nested_meta(|nested| {
|
||||
let path = &nested.path;
|
||||
|
||||
if first && (nested.input.is_empty() || nested.input.peek(Token![,])) {
|
||||
self.slug.set_once(path.clone(), path.span().unwrap());
|
||||
first = false;
|
||||
return Ok(())
|
||||
}
|
||||
|
||||
first = false;
|
||||
|
||||
let Ok(nested) = nested.value() else {
|
||||
span_err(nested.input.span().unwrap(), "diagnostic slug must be the first argument").emit();
|
||||
return Ok(())
|
||||
};
|
||||
|
||||
let nested_name = path.segments.last().unwrap().ident.to_string();
|
||||
// Struct attributes are only allowed to be applied once, and the diagnostic
|
||||
// changes will be set in the initialisation code.
|
||||
let span = value.span().unwrap();
|
||||
match nested_name.as_str() {
|
||||
"code" => {
|
||||
self.code.set_once((), span);
|
||||
if path.is_ident("code") {
|
||||
self.code.set_once((), path.span().unwrap());
|
||||
|
||||
let code = value.value();
|
||||
tokens.extend(quote! {
|
||||
#diag.code(rustc_errors::DiagnosticId::Error(#code.to_string()));
|
||||
});
|
||||
}
|
||||
_ => invalid_nested_attr(attr, nested_attr)
|
||||
.help("only `code` is a valid nested attributes following the slug")
|
||||
.emit(),
|
||||
let code = nested.parse::<TokenStream>()?;
|
||||
tokens.extend(quote! {
|
||||
#diag.code(rustc_errors::DiagnosticId::Error(#code.to_string()));
|
||||
});
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
})?;
|
||||
return Ok(tokens);
|
||||
}
|
||||
|
||||
|
@ -270,7 +235,7 @@ impl<'a> DiagnosticDeriveVariantBuilder<'a> {
|
|||
Ok(self.add_subdiagnostic(&fn_ident, slug))
|
||||
}
|
||||
SubdiagnosticKind::Label | SubdiagnosticKind::Suggestion { .. } => {
|
||||
throw_invalid_attr!(attr, &meta, |diag| diag
|
||||
throw_invalid_attr!(attr, |diag| diag
|
||||
.help("`#[label]` and `#[suggestion]` can only be applied to fields"));
|
||||
}
|
||||
SubdiagnosticKind::MultipartSuggestion { .. } => unreachable!(),
|
||||
|
@ -309,7 +274,7 @@ impl<'a> DiagnosticDeriveVariantBuilder<'a> {
|
|||
return quote! {};
|
||||
}
|
||||
|
||||
let name = attr.path.segments.last().unwrap().ident.to_string();
|
||||
let name = attr.path().segments.last().unwrap().ident.to_string();
|
||||
let needs_clone =
|
||||
name == "primary_span" && matches!(inner_ty, FieldInnerTy::Vec(_));
|
||||
let (binding, needs_destructure) = if needs_clone {
|
||||
|
@ -343,11 +308,10 @@ impl<'a> DiagnosticDeriveVariantBuilder<'a> {
|
|||
binding: TokenStream,
|
||||
) -> Result<TokenStream, DiagnosticDeriveError> {
|
||||
let diag = &self.parent.diag;
|
||||
let meta = attr.parse_meta()?;
|
||||
|
||||
let ident = &attr.path.segments.last().unwrap().ident;
|
||||
let ident = &attr.path().segments.last().unwrap().ident;
|
||||
let name = ident.to_string();
|
||||
match (&meta, name.as_str()) {
|
||||
match (&attr.meta, name.as_str()) {
|
||||
// Don't need to do anything - by virtue of the attribute existing, the
|
||||
// `set_arg` call will not be generated.
|
||||
(Meta::Path(_), "skip_arg") => return Ok(quote! {}),
|
||||
|
@ -361,7 +325,7 @@ impl<'a> DiagnosticDeriveVariantBuilder<'a> {
|
|||
});
|
||||
}
|
||||
DiagnosticDeriveKind::LintDiagnostic => {
|
||||
throw_invalid_attr!(attr, &meta, |diag| {
|
||||
throw_invalid_attr!(attr, |diag| {
|
||||
diag.help("the `primary_span` field attribute is not valid for lint diagnostics")
|
||||
})
|
||||
}
|
||||
|
@ -378,26 +342,34 @@ impl<'a> DiagnosticDeriveVariantBuilder<'a> {
|
|||
return Ok(quote! { #diag.subdiagnostic(#binding); });
|
||||
}
|
||||
}
|
||||
(Meta::List(MetaList { ref nested, .. }), "subdiagnostic") => {
|
||||
if nested.len() == 1
|
||||
&& let Some(NestedMeta::Meta(Meta::Path(path))) = nested.first()
|
||||
&& path.is_ident("eager") {
|
||||
let handler = match &self.parent.kind {
|
||||
DiagnosticDeriveKind::Diagnostic { handler } => handler,
|
||||
DiagnosticDeriveKind::LintDiagnostic => {
|
||||
throw_invalid_attr!(attr, &meta, |diag| {
|
||||
diag.help("eager subdiagnostics are not supported on lints")
|
||||
})
|
||||
}
|
||||
};
|
||||
return Ok(quote! { #diag.eager_subdiagnostic(#handler, #binding); });
|
||||
} else {
|
||||
throw_invalid_attr!(attr, &meta, |diag| {
|
||||
diag.help(
|
||||
"`eager` is the only supported nested attribute for `subdiagnostic`",
|
||||
)
|
||||
})
|
||||
(Meta::List(meta_list), "subdiagnostic") => {
|
||||
let err = || {
|
||||
span_err(
|
||||
meta_list.span().unwrap(),
|
||||
"`eager` is the only supported nested attribute for `subdiagnostic`",
|
||||
)
|
||||
.emit();
|
||||
};
|
||||
|
||||
let Ok(p): Result<Path, _> = meta_list.parse_args() else {
|
||||
err();
|
||||
return Ok(quote! {});
|
||||
};
|
||||
|
||||
if !p.is_ident("eager") {
|
||||
err();
|
||||
return Ok(quote! {});
|
||||
}
|
||||
|
||||
let handler = match &self.parent.kind {
|
||||
DiagnosticDeriveKind::Diagnostic { handler } => handler,
|
||||
DiagnosticDeriveKind::LintDiagnostic => {
|
||||
throw_invalid_attr!(attr, |diag| {
|
||||
diag.help("eager subdiagnostics are not supported on lints")
|
||||
})
|
||||
}
|
||||
};
|
||||
return Ok(quote! { #diag.eager_subdiagnostic(#handler, #binding); });
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
|
@ -432,7 +404,7 @@ impl<'a> DiagnosticDeriveVariantBuilder<'a> {
|
|||
code_init,
|
||||
} => {
|
||||
if let FieldInnerTy::Vec(_) = info.ty {
|
||||
throw_invalid_attr!(attr, &meta, |diag| {
|
||||
throw_invalid_attr!(attr, |diag| {
|
||||
diag
|
||||
.note("`#[suggestion(...)]` applied to `Vec` field is ambiguous")
|
||||
.help("to show a suggestion consisting of multiple parts, use a `Subdiagnostic` annotated with `#[multipart_suggestion(...)]`")
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use proc_macro::{Diagnostic, Level, MultiSpan};
|
||||
use proc_macro2::TokenStream;
|
||||
use quote::quote;
|
||||
use syn::{spanned::Spanned, Attribute, Error as SynError, Meta, NestedMeta};
|
||||
use syn::{spanned::Spanned, Attribute, Error as SynError, Meta};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) enum DiagnosticDeriveError {
|
||||
|
@ -53,6 +53,7 @@ fn path_to_string(path: &syn::Path) -> String {
|
|||
}
|
||||
|
||||
/// Returns an error diagnostic on span `span` with msg `msg`.
|
||||
#[must_use]
|
||||
pub(crate) fn span_err(span: impl MultiSpan, msg: &str) -> Diagnostic {
|
||||
Diagnostic::spanned(span, Level::Error, msg)
|
||||
}
|
||||
|
@ -72,10 +73,10 @@ macro_rules! throw_span_err {
|
|||
pub(crate) use throw_span_err;
|
||||
|
||||
/// Returns an error diagnostic for an invalid attribute.
|
||||
pub(crate) fn invalid_attr(attr: &Attribute, meta: &Meta) -> Diagnostic {
|
||||
pub(crate) fn invalid_attr(attr: &Attribute) -> Diagnostic {
|
||||
let span = attr.span().unwrap();
|
||||
let path = path_to_string(&attr.path);
|
||||
match meta {
|
||||
let path = path_to_string(attr.path());
|
||||
match attr.meta {
|
||||
Meta::Path(_) => span_err(span, &format!("`#[{path}]` is not a valid attribute")),
|
||||
Meta::NameValue(_) => {
|
||||
span_err(span, &format!("`#[{path} = ...]` is not a valid attribute"))
|
||||
|
@ -89,51 +90,11 @@ pub(crate) fn invalid_attr(attr: &Attribute, meta: &Meta) -> Diagnostic {
|
|||
///
|
||||
/// For methods that return a `Result<_, DiagnosticDeriveError>`:
|
||||
macro_rules! throw_invalid_attr {
|
||||
($attr:expr, $meta:expr) => {{ throw_invalid_attr!($attr, $meta, |diag| diag) }};
|
||||
($attr:expr, $meta:expr, $f:expr) => {{
|
||||
let diag = crate::diagnostics::error::invalid_attr($attr, $meta);
|
||||
($attr:expr) => {{ throw_invalid_attr!($attr, |diag| diag) }};
|
||||
($attr:expr, $f:expr) => {{
|
||||
let diag = crate::diagnostics::error::invalid_attr($attr);
|
||||
return Err(crate::diagnostics::error::_throw_err(diag, $f));
|
||||
}};
|
||||
}
|
||||
|
||||
pub(crate) use throw_invalid_attr;
|
||||
|
||||
/// Returns an error diagnostic for an invalid nested attribute.
|
||||
pub(crate) fn invalid_nested_attr(attr: &Attribute, nested: &NestedMeta) -> Diagnostic {
|
||||
let name = attr.path.segments.last().unwrap().ident.to_string();
|
||||
let name = name.as_str();
|
||||
|
||||
let span = nested.span().unwrap();
|
||||
let meta = match nested {
|
||||
syn::NestedMeta::Meta(meta) => meta,
|
||||
syn::NestedMeta::Lit(_) => {
|
||||
return span_err(span, &format!("`#[{name}(\"...\")]` is not a valid attribute"));
|
||||
}
|
||||
};
|
||||
|
||||
let span = meta.span().unwrap();
|
||||
let path = path_to_string(meta.path());
|
||||
match meta {
|
||||
Meta::NameValue(..) => {
|
||||
span_err(span, &format!("`#[{name}({path} = ...)]` is not a valid attribute"))
|
||||
}
|
||||
Meta::Path(..) => span_err(span, &format!("`#[{name}({path})]` is not a valid attribute")),
|
||||
Meta::List(..) => {
|
||||
span_err(span, &format!("`#[{name}({path}(...))]` is not a valid attribute"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Emit an error diagnostic for an invalid nested attribute (optionally performing additional
|
||||
/// decoration using the `FnOnce` passed in `diag`) and return `Err(ErrorHandled)`.
|
||||
///
|
||||
/// For methods that return a `Result<_, DiagnosticDeriveError>`:
|
||||
macro_rules! throw_invalid_nested_attr {
|
||||
($attr:expr, $nested_attr:expr) => {{ throw_invalid_nested_attr!($attr, $nested_attr, |diag| diag) }};
|
||||
($attr:expr, $nested_attr:expr, $f:expr) => {{
|
||||
let diag = crate::diagnostics::error::invalid_nested_attr($attr, $nested_attr);
|
||||
return Err(crate::diagnostics::error::_throw_err(diag, $f));
|
||||
}};
|
||||
}
|
||||
|
||||
pub(crate) use throw_invalid_nested_attr;
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
#![deny(unused_must_use)]
|
||||
|
||||
use crate::diagnostics::error::{
|
||||
invalid_attr, span_err, throw_invalid_attr, throw_invalid_nested_attr, throw_span_err,
|
||||
DiagnosticDeriveError,
|
||||
invalid_attr, span_err, throw_invalid_attr, throw_span_err, DiagnosticDeriveError,
|
||||
};
|
||||
use crate::diagnostics::utils::{
|
||||
build_field_mapping, is_doc_comment, new_code_ident,
|
||||
|
@ -11,7 +10,7 @@ use crate::diagnostics::utils::{
|
|||
};
|
||||
use proc_macro2::TokenStream;
|
||||
use quote::{format_ident, quote};
|
||||
use syn::{spanned::Spanned, Attribute, Meta, MetaList, NestedMeta, Path};
|
||||
use syn::{spanned::Spanned, Attribute, Meta, MetaList, Path};
|
||||
use synstructure::{BindingInfo, Structure, VariantInfo};
|
||||
|
||||
use super::utils::{build_suggestion_code, AllowMultipleAlternatives};
|
||||
|
@ -39,7 +38,8 @@ impl SubdiagnosticDeriveBuilder {
|
|||
span_err(
|
||||
span,
|
||||
"`#[derive(Subdiagnostic)]` can only be used on structs and enums",
|
||||
);
|
||||
)
|
||||
.emit();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -192,7 +192,7 @@ impl<'parent, 'a> SubdiagnosticDeriveVariantBuilder<'parent, 'a> {
|
|||
};
|
||||
|
||||
let Some(slug) = slug else {
|
||||
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();
|
||||
|
||||
throw_span_err!(
|
||||
|
@ -265,17 +265,18 @@ impl<'parent, 'a> SubdiagnosticDeriveVariantBuilder<'parent, 'a> {
|
|||
info: FieldInfo<'_>,
|
||||
clone_suggestion_code: bool,
|
||||
) -> Result<TokenStream, DiagnosticDeriveError> {
|
||||
let meta = attr.parse_meta()?;
|
||||
match meta {
|
||||
Meta::Path(path) => self.generate_field_code_inner_path(kind_stats, attr, info, path),
|
||||
Meta::List(list @ MetaList { .. }) => self.generate_field_code_inner_list(
|
||||
match &attr.meta {
|
||||
Meta::Path(path) => {
|
||||
self.generate_field_code_inner_path(kind_stats, attr, info, path.clone())
|
||||
}
|
||||
Meta::List(list) => self.generate_field_code_inner_list(
|
||||
kind_stats,
|
||||
attr,
|
||||
info,
|
||||
list,
|
||||
clone_suggestion_code,
|
||||
),
|
||||
_ => throw_invalid_attr!(attr, &meta),
|
||||
_ => throw_invalid_attr!(attr),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -296,7 +297,7 @@ impl<'parent, 'a> SubdiagnosticDeriveVariantBuilder<'parent, 'a> {
|
|||
"skip_arg" => Ok(quote! {}),
|
||||
"primary_span" => {
|
||||
if kind_stats.has_multipart_suggestion {
|
||||
invalid_attr(attr, &Meta::Path(path))
|
||||
invalid_attr(attr)
|
||||
.help(
|
||||
"multipart suggestions use one or more `#[suggestion_part]`s rather \
|
||||
than one `#[primary_span]`",
|
||||
|
@ -309,7 +310,7 @@ impl<'parent, 'a> SubdiagnosticDeriveVariantBuilder<'parent, 'a> {
|
|||
// FIXME(#100717): support `Option<Span>` on `primary_span` like in the
|
||||
// diagnostic derive
|
||||
if !matches!(info.ty, FieldInnerTy::Plain(_)) {
|
||||
throw_invalid_attr!(attr, &Meta::Path(path), |diag| {
|
||||
throw_invalid_attr!(attr, |diag| {
|
||||
let diag = diag.note("there must be exactly one primary span");
|
||||
|
||||
if kind_stats.has_normal_suggestion {
|
||||
|
@ -335,7 +336,7 @@ impl<'parent, 'a> SubdiagnosticDeriveVariantBuilder<'parent, 'a> {
|
|||
span_err(span, "`#[suggestion_part(...)]` attribute without `code = \"...\"`")
|
||||
.emit();
|
||||
} else {
|
||||
invalid_attr(attr, &Meta::Path(path))
|
||||
invalid_attr(attr)
|
||||
.help(
|
||||
"`#[suggestion_part(...)]` is only valid in multipart suggestions, \
|
||||
use `#[primary_span]` instead",
|
||||
|
@ -375,7 +376,7 @@ impl<'parent, 'a> SubdiagnosticDeriveVariantBuilder<'parent, 'a> {
|
|||
span_attrs.push("primary_span")
|
||||
}
|
||||
|
||||
invalid_attr(attr, &Meta::Path(path))
|
||||
invalid_attr(attr)
|
||||
.help(format!(
|
||||
"only `{}`, `applicability` and `skip_arg` are valid field attributes",
|
||||
span_attrs.join(", ")
|
||||
|
@ -394,7 +395,7 @@ impl<'parent, 'a> SubdiagnosticDeriveVariantBuilder<'parent, 'a> {
|
|||
kind_stats: KindsStatistics,
|
||||
attr: &Attribute,
|
||||
info: FieldInfo<'_>,
|
||||
list: MetaList,
|
||||
list: &MetaList,
|
||||
clone_suggestion_code: bool,
|
||||
) -> Result<TokenStream, DiagnosticDeriveError> {
|
||||
let span = attr.span().unwrap();
|
||||
|
@ -405,7 +406,7 @@ impl<'parent, 'a> SubdiagnosticDeriveVariantBuilder<'parent, 'a> {
|
|||
match name {
|
||||
"suggestion_part" => {
|
||||
if !kind_stats.has_multipart_suggestion {
|
||||
throw_invalid_attr!(attr, &Meta::List(list), |diag| {
|
||||
throw_invalid_attr!(attr, |diag| {
|
||||
diag.help(
|
||||
"`#[suggestion_part(...)]` is only valid in multipart suggestions",
|
||||
)
|
||||
|
@ -417,31 +418,26 @@ impl<'parent, 'a> SubdiagnosticDeriveVariantBuilder<'parent, 'a> {
|
|||
report_error_if_not_applied_to_span(attr, &info)?;
|
||||
|
||||
let mut code = None;
|
||||
for nested_attr in list.nested.iter() {
|
||||
let NestedMeta::Meta(ref meta) = nested_attr else {
|
||||
throw_invalid_nested_attr!(attr, nested_attr);
|
||||
};
|
||||
|
||||
let span = meta.span().unwrap();
|
||||
let nested_name = meta.path().segments.last().unwrap().ident.to_string();
|
||||
let nested_name = nested_name.as_str();
|
||||
|
||||
match nested_name {
|
||||
"code" => {
|
||||
let code_field = new_code_ident();
|
||||
let formatting_init = build_suggestion_code(
|
||||
&code_field,
|
||||
meta,
|
||||
self,
|
||||
AllowMultipleAlternatives::No,
|
||||
);
|
||||
code.set_once((code_field, formatting_init), span);
|
||||
}
|
||||
_ => throw_invalid_nested_attr!(attr, nested_attr, |diag| {
|
||||
diag.help("`code` is the only valid nested attribute")
|
||||
}),
|
||||
list.parse_nested_meta(|nested| {
|
||||
if nested.path.is_ident("code") {
|
||||
let code_field = new_code_ident();
|
||||
let formatting_init = build_suggestion_code(
|
||||
&code_field,
|
||||
nested,
|
||||
self,
|
||||
AllowMultipleAlternatives::No,
|
||||
);
|
||||
code.set_once((code_field, formatting_init), span);
|
||||
} else {
|
||||
span_err(
|
||||
nested.path.span().unwrap(),
|
||||
"`code` is the only valid nested attribute",
|
||||
)
|
||||
.emit();
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
let Some((code_field, formatting_init)) = code.value() else {
|
||||
span_err(span, "`#[suggestion_part(...)]` attribute without `code = \"...\"`")
|
||||
|
@ -458,7 +454,7 @@ impl<'parent, 'a> SubdiagnosticDeriveVariantBuilder<'parent, 'a> {
|
|||
};
|
||||
Ok(quote! { suggestions.push((#binding, #code_field)); })
|
||||
}
|
||||
_ => throw_invalid_attr!(attr, &Meta::List(list), |diag| {
|
||||
_ => throw_invalid_attr!(attr, |diag| {
|
||||
let mut span_attrs = vec![];
|
||||
if kind_stats.has_multipart_suggestion {
|
||||
span_attrs.push("suggestion_part");
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use proc_macro2::{self, Ident};
|
||||
use quote::quote;
|
||||
use syn::{self, parse_quote, Meta, NestedMeta};
|
||||
use syn::{self, parse_quote};
|
||||
|
||||
struct Attributes {
|
||||
ignore: bool,
|
||||
|
@ -10,32 +10,29 @@ struct Attributes {
|
|||
fn parse_attributes(field: &syn::Field) -> Attributes {
|
||||
let mut attrs = Attributes { ignore: false, project: None };
|
||||
for attr in &field.attrs {
|
||||
if let Ok(meta) = attr.parse_meta() {
|
||||
if !meta.path().is_ident("stable_hasher") {
|
||||
continue;
|
||||
let meta = &attr.meta;
|
||||
if !meta.path().is_ident("stable_hasher") {
|
||||
continue;
|
||||
}
|
||||
let mut any_attr = false;
|
||||
let _ = attr.parse_nested_meta(|nested| {
|
||||
if nested.path.is_ident("ignore") {
|
||||
attrs.ignore = true;
|
||||
any_attr = true;
|
||||
}
|
||||
let mut any_attr = false;
|
||||
if let Meta::List(list) = meta {
|
||||
for nested in list.nested.iter() {
|
||||
if let NestedMeta::Meta(meta) = nested {
|
||||
if meta.path().is_ident("ignore") {
|
||||
attrs.ignore = true;
|
||||
any_attr = true;
|
||||
}
|
||||
if meta.path().is_ident("project") {
|
||||
if let Meta::List(list) = meta {
|
||||
if let Some(NestedMeta::Meta(meta)) = list.nested.iter().next() {
|
||||
attrs.project = meta.path().get_ident().cloned();
|
||||
any_attr = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if nested.path.is_ident("project") {
|
||||
let _ = nested.parse_nested_meta(|meta| {
|
||||
if attrs.project.is_none() {
|
||||
attrs.project = meta.path.get_ident().cloned();
|
||||
}
|
||||
}
|
||||
}
|
||||
if !any_attr {
|
||||
panic!("error parsing stable_hasher");
|
||||
any_attr = true;
|
||||
Ok(())
|
||||
});
|
||||
}
|
||||
Ok(())
|
||||
});
|
||||
if !any_attr {
|
||||
panic!("error parsing stable_hasher");
|
||||
}
|
||||
}
|
||||
attrs
|
||||
|
|
|
@ -25,7 +25,7 @@ impl Parse for Newtype {
|
|||
let mut encodable = true;
|
||||
let mut ord = true;
|
||||
|
||||
attrs.retain(|attr| match attr.path.get_ident() {
|
||||
attrs.retain(|attr| match attr.path().get_ident() {
|
||||
Some(ident) => match &*ident.to_string() {
|
||||
"custom_encodable" => {
|
||||
encodable = false;
|
||||
|
@ -36,22 +36,22 @@ impl Parse for Newtype {
|
|||
false
|
||||
}
|
||||
"max" => {
|
||||
let Ok(Meta::NameValue(literal) )= attr.parse_meta() else {
|
||||
let Meta::NameValue(MetaNameValue { value: Expr::Lit(lit), .. }) = &attr.meta else {
|
||||
panic!("#[max = NUMBER] attribute requires max value");
|
||||
};
|
||||
|
||||
if let Some(old) = max.replace(literal.lit) {
|
||||
if let Some(old) = max.replace(lit.lit.clone()) {
|
||||
panic!("Specified multiple max: {old:?}");
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
"debug_format" => {
|
||||
let Ok(Meta::NameValue(literal) )= attr.parse_meta() else {
|
||||
let Meta::NameValue(MetaNameValue { value: Expr::Lit(lit), .. } ) = &attr.meta else {
|
||||
panic!("#[debug_format = FMT] attribute requires a format");
|
||||
};
|
||||
|
||||
if let Some(old) = debug_format.replace(literal.lit) {
|
||||
if let Some(old) = debug_format.replace(lit.lit.clone()) {
|
||||
panic!("Specified multiple debug format options: {old:?}");
|
||||
}
|
||||
|
||||
|
|
|
@ -15,7 +15,7 @@ mod kw {
|
|||
/// Ensures only doc comment attributes are used
|
||||
fn check_attributes(attrs: Vec<Attribute>) -> Result<Vec<Attribute>> {
|
||||
let inner = |attr: Attribute| {
|
||||
if !attr.path.is_ident("doc") {
|
||||
if !attr.path().is_ident("doc") {
|
||||
Err(Error::new(attr.span(), "attributes not supported on queries"))
|
||||
} else if attr.style != AttrStyle::Outer {
|
||||
Err(Error::new(
|
||||
|
@ -48,7 +48,7 @@ impl Parse for Query {
|
|||
let name: Ident = input.parse()?;
|
||||
let arg_content;
|
||||
parenthesized!(arg_content in input);
|
||||
let key = arg_content.parse()?;
|
||||
let key = Pat::parse_single(&arg_content)?;
|
||||
arg_content.parse::<Token![:]>()?;
|
||||
let arg = arg_content.parse()?;
|
||||
let result = input.parse()?;
|
||||
|
@ -158,7 +158,7 @@ fn parse_query_modifiers(input: ParseStream<'_>) -> Result<QueryModifiers> {
|
|||
} else {
|
||||
None
|
||||
};
|
||||
let list = attr_content.parse_terminated(Expr::parse)?;
|
||||
let list = attr_content.parse_terminated(Expr::parse, Token![,])?;
|
||||
try_insert!(desc = (tcx, list));
|
||||
} else if modifier == "cache_on_disk_if" {
|
||||
// Parse a cache modifier like:
|
||||
|
@ -166,7 +166,7 @@ fn parse_query_modifiers(input: ParseStream<'_>) -> Result<QueryModifiers> {
|
|||
let args = if input.peek(token::Paren) {
|
||||
let args;
|
||||
parenthesized!(args in input);
|
||||
let tcx = args.parse()?;
|
||||
let tcx = Pat::parse_single(&args)?;
|
||||
Some(tcx)
|
||||
} else {
|
||||
None
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use quote::{quote, ToTokens};
|
||||
use syn::{parse_quote, Attribute, Meta, NestedMeta};
|
||||
use syn::parse_quote;
|
||||
|
||||
pub fn type_foldable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::TokenStream {
|
||||
if let syn::Data::Union(_) = s.ast().data {
|
||||
|
@ -17,21 +17,20 @@ pub fn type_foldable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::
|
|||
vi.construct(|_, index| {
|
||||
let bind = &bindings[index];
|
||||
|
||||
let mut fixed = false;
|
||||
|
||||
// retain value of fields with #[type_foldable(identity)]
|
||||
let fixed = bind
|
||||
.ast()
|
||||
.attrs
|
||||
.iter()
|
||||
.map(Attribute::parse_meta)
|
||||
.filter_map(Result::ok)
|
||||
.flat_map(|attr| match attr {
|
||||
Meta::List(list) if list.path.is_ident("type_foldable") => list.nested,
|
||||
_ => Default::default(),
|
||||
})
|
||||
.any(|nested| match nested {
|
||||
NestedMeta::Meta(Meta::Path(path)) => path.is_ident("identity"),
|
||||
_ => false,
|
||||
bind.ast().attrs.iter().for_each(|x| {
|
||||
if !x.path().is_ident("type_foldable") {
|
||||
return;
|
||||
}
|
||||
let _ = x.parse_nested_meta(|nested| {
|
||||
if nested.path.is_ident("identity") {
|
||||
fixed = true;
|
||||
}
|
||||
Ok(())
|
||||
});
|
||||
});
|
||||
|
||||
if fixed {
|
||||
bind.to_token_stream()
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use quote::quote;
|
||||
use syn::{parse_quote, Attribute, Meta, NestedMeta};
|
||||
use syn::parse_quote;
|
||||
|
||||
pub fn type_visitable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::TokenStream {
|
||||
if let syn::Data::Union(_) = s.ast().data {
|
||||
|
@ -8,19 +8,21 @@ pub fn type_visitable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2:
|
|||
|
||||
// ignore fields with #[type_visitable(ignore)]
|
||||
s.filter(|bi| {
|
||||
!bi.ast()
|
||||
.attrs
|
||||
.iter()
|
||||
.map(Attribute::parse_meta)
|
||||
.filter_map(Result::ok)
|
||||
.flat_map(|attr| match attr {
|
||||
Meta::List(list) if list.path.is_ident("type_visitable") => list.nested,
|
||||
_ => Default::default(),
|
||||
})
|
||||
.any(|nested| match nested {
|
||||
NestedMeta::Meta(Meta::Path(path)) => path.is_ident("ignore"),
|
||||
_ => false,
|
||||
})
|
||||
let mut ignored = false;
|
||||
|
||||
bi.ast().attrs.iter().for_each(|attr| {
|
||||
if !attr.path().is_ident("type_visitable") {
|
||||
return;
|
||||
}
|
||||
let _ = attr.parse_nested_meta(|nested| {
|
||||
if nested.path.is_ident("ignore") {
|
||||
ignored = true;
|
||||
}
|
||||
Ok(())
|
||||
});
|
||||
});
|
||||
|
||||
!ignored
|
||||
});
|
||||
|
||||
if !s.ast().generics.lifetimes().any(|lt| lt.lifetime.ident == "tcx") {
|
||||
|
|
Loading…
Add table
Reference in a new issue