expand: Cleanup attribute collection in invocation collector

This commit is contained in:
Vadim Petrochenkov 2020-11-19 01:51:52 +03:00
parent dfb690eaa9
commit ec547202b4

View File

@ -1016,11 +1016,9 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
fn collect_attr( fn collect_attr(
&mut self, &mut self,
attr: Option<ast::Attribute>, (attr, derives, after_derive): (Option<ast::Attribute>, Vec<Path>, bool),
derives: Vec<Path>,
item: Annotatable, item: Annotatable,
kind: AstFragmentKind, kind: AstFragmentKind,
after_derive: bool,
) -> AstFragment { ) -> AstFragment {
self.collect( self.collect(
kind, kind,
@ -1048,10 +1046,10 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
} }
/// If `item` is an attr invocation, remove and return the macro attribute and derive traits. /// If `item` is an attr invocation, remove and return the macro attribute and derive traits.
fn classify_item( fn take_first_attr(
&mut self, &mut self,
item: &mut impl HasAttrs, item: &mut impl HasAttrs,
) -> (Option<ast::Attribute>, Vec<Path>, /* after_derive */ bool) { ) -> Option<(Option<ast::Attribute>, Vec<Path>, /* after_derive */ bool)> {
let (mut attr, mut traits, mut after_derive) = (None, Vec::new(), false); let (mut attr, mut traits, mut after_derive) = (None, Vec::new(), false);
item.visit_attrs(|mut attrs| { item.visit_attrs(|mut attrs| {
@ -1059,23 +1057,23 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
traits = collect_derives(&mut self.cx, &mut attrs); traits = collect_derives(&mut self.cx, &mut attrs);
}); });
(attr, traits, after_derive) if attr.is_some() || !traits.is_empty() { Some((attr, traits, after_derive)) } else { None }
} }
/// Alternative to `classify_item()` that ignores `#[derive]` so invocations fallthrough /// Alternative to `take_first_attr()` that ignores `#[derive]` so invocations fallthrough
/// to the unused-attributes lint (making it an error on statements and expressions /// to the unused-attributes lint (making it an error on statements and expressions
/// is a breaking change) /// is a breaking change)
fn classify_nonitem( fn take_first_attr_no_derive(
&mut self, &mut self,
nonitem: &mut impl HasAttrs, nonitem: &mut impl HasAttrs,
) -> (Option<ast::Attribute>, /* after_derive */ bool) { ) -> Option<(Option<ast::Attribute>, Vec<Path>, /* after_derive */ bool)> {
let (mut attr, mut after_derive) = (None, false); let (mut attr, mut after_derive) = (None, false);
nonitem.visit_attrs(|mut attrs| { nonitem.visit_attrs(|mut attrs| {
attr = self.find_attr_invoc(&mut attrs, &mut after_derive); attr = self.find_attr_invoc(&mut attrs, &mut after_derive);
}); });
(attr, after_derive) attr.map(|attr| (Some(attr), Vec::new(), after_derive))
} }
fn configure<T: HasAttrs>(&mut self, node: T) -> Option<T> { fn configure<T: HasAttrs>(&mut self, node: T) -> Option<T> {
@ -1119,23 +1117,14 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
visit_clobber(expr.deref_mut(), |mut expr| { visit_clobber(expr.deref_mut(), |mut expr| {
self.cfg.configure_expr_kind(&mut expr.kind); self.cfg.configure_expr_kind(&mut expr.kind);
// ignore derives so they remain unused if let Some(attr) = self.take_first_attr_no_derive(&mut expr) {
let (attr, after_derive) = self.classify_nonitem(&mut expr);
if let Some(ref attr_value) = attr {
// Collect the invoc regardless of whether or not attributes are permitted here // Collect the invoc regardless of whether or not attributes are permitted here
// expansion will eat the attribute so it won't error later. // expansion will eat the attribute so it won't error later.
self.cfg.maybe_emit_expr_attr_err(attr_value); attr.0.as_ref().map(|attr| self.cfg.maybe_emit_expr_attr_err(attr));
// AstFragmentKind::Expr requires the macro to emit an expression. // AstFragmentKind::Expr requires the macro to emit an expression.
return self return self
.collect_attr( .collect_attr(attr, Annotatable::Expr(P(expr)), AstFragmentKind::Expr)
attr,
vec![],
Annotatable::Expr(P(expr)),
AstFragmentKind::Expr,
after_derive,
)
.make_expr() .make_expr()
.into_inner(); .into_inner();
} }
@ -1153,16 +1142,9 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
fn flat_map_arm(&mut self, arm: ast::Arm) -> SmallVec<[ast::Arm; 1]> { fn flat_map_arm(&mut self, arm: ast::Arm) -> SmallVec<[ast::Arm; 1]> {
let mut arm = configure!(self, arm); let mut arm = configure!(self, arm);
let (attr, traits, after_derive) = self.classify_item(&mut arm); if let Some(attr) = self.take_first_attr(&mut arm) {
if attr.is_some() || !traits.is_empty() {
return self return self
.collect_attr( .collect_attr(attr, Annotatable::Arm(arm), AstFragmentKind::Arms)
attr,
traits,
Annotatable::Arm(arm),
AstFragmentKind::Arms,
after_derive,
)
.make_arms(); .make_arms();
} }
@ -1172,16 +1154,9 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
fn flat_map_field(&mut self, field: ast::Field) -> SmallVec<[ast::Field; 1]> { fn flat_map_field(&mut self, field: ast::Field) -> SmallVec<[ast::Field; 1]> {
let mut field = configure!(self, field); let mut field = configure!(self, field);
let (attr, traits, after_derive) = self.classify_item(&mut field); if let Some(attr) = self.take_first_attr(&mut field) {
if attr.is_some() || !traits.is_empty() {
return self return self
.collect_attr( .collect_attr(attr, Annotatable::Field(field), AstFragmentKind::Fields)
attr,
traits,
Annotatable::Field(field),
AstFragmentKind::Fields,
after_derive,
)
.make_fields(); .make_fields();
} }
@ -1191,16 +1166,9 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
fn flat_map_field_pattern(&mut self, fp: ast::FieldPat) -> SmallVec<[ast::FieldPat; 1]> { fn flat_map_field_pattern(&mut self, fp: ast::FieldPat) -> SmallVec<[ast::FieldPat; 1]> {
let mut fp = configure!(self, fp); let mut fp = configure!(self, fp);
let (attr, traits, after_derive) = self.classify_item(&mut fp); if let Some(attr) = self.take_first_attr(&mut fp) {
if attr.is_some() || !traits.is_empty() {
return self return self
.collect_attr( .collect_attr(attr, Annotatable::FieldPat(fp), AstFragmentKind::FieldPats)
attr,
traits,
Annotatable::FieldPat(fp),
AstFragmentKind::FieldPats,
after_derive,
)
.make_field_patterns(); .make_field_patterns();
} }
@ -1210,16 +1178,9 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
fn flat_map_param(&mut self, p: ast::Param) -> SmallVec<[ast::Param; 1]> { fn flat_map_param(&mut self, p: ast::Param) -> SmallVec<[ast::Param; 1]> {
let mut p = configure!(self, p); let mut p = configure!(self, p);
let (attr, traits, after_derive) = self.classify_item(&mut p); if let Some(attr) = self.take_first_attr(&mut p) {
if attr.is_some() || !traits.is_empty() {
return self return self
.collect_attr( .collect_attr(attr, Annotatable::Param(p), AstFragmentKind::Params)
attr,
traits,
Annotatable::Param(p),
AstFragmentKind::Params,
after_derive,
)
.make_params(); .make_params();
} }
@ -1229,16 +1190,9 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
fn flat_map_struct_field(&mut self, sf: ast::StructField) -> SmallVec<[ast::StructField; 1]> { fn flat_map_struct_field(&mut self, sf: ast::StructField) -> SmallVec<[ast::StructField; 1]> {
let mut sf = configure!(self, sf); let mut sf = configure!(self, sf);
let (attr, traits, after_derive) = self.classify_item(&mut sf); if let Some(attr) = self.take_first_attr(&mut sf) {
if attr.is_some() || !traits.is_empty() {
return self return self
.collect_attr( .collect_attr(attr, Annotatable::StructField(sf), AstFragmentKind::StructFields)
attr,
traits,
Annotatable::StructField(sf),
AstFragmentKind::StructFields,
after_derive,
)
.make_struct_fields(); .make_struct_fields();
} }
@ -1248,16 +1202,9 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
fn flat_map_variant(&mut self, variant: ast::Variant) -> SmallVec<[ast::Variant; 1]> { fn flat_map_variant(&mut self, variant: ast::Variant) -> SmallVec<[ast::Variant; 1]> {
let mut variant = configure!(self, variant); let mut variant = configure!(self, variant);
let (attr, traits, after_derive) = self.classify_item(&mut variant); if let Some(attr) = self.take_first_attr(&mut variant) {
if attr.is_some() || !traits.is_empty() {
return self return self
.collect_attr( .collect_attr(attr, Annotatable::Variant(variant), AstFragmentKind::Variants)
attr,
traits,
Annotatable::Variant(variant),
AstFragmentKind::Variants,
after_derive,
)
.make_variants(); .make_variants();
} }
@ -1269,20 +1216,11 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
expr.filter_map(|mut expr| { expr.filter_map(|mut expr| {
self.cfg.configure_expr_kind(&mut expr.kind); self.cfg.configure_expr_kind(&mut expr.kind);
// Ignore derives so they remain unused. if let Some(attr) = self.take_first_attr_no_derive(&mut expr) {
let (attr, after_derive) = self.classify_nonitem(&mut expr); attr.0.as_ref().map(|attr| self.cfg.maybe_emit_expr_attr_err(attr));
if let Some(ref attr_value) = attr {
self.cfg.maybe_emit_expr_attr_err(attr_value);
return self return self
.collect_attr( .collect_attr(attr, Annotatable::Expr(P(expr)), AstFragmentKind::OptExpr)
attr,
vec![],
Annotatable::Expr(P(expr)),
AstFragmentKind::OptExpr,
after_derive,
)
.make_opt_expr() .make_opt_expr()
.map(|expr| expr.into_inner()); .map(|expr| expr.into_inner());
} }
@ -1321,25 +1259,13 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
// we'll expand attributes on expressions separately // we'll expand attributes on expressions separately
if !stmt.is_expr() { if !stmt.is_expr() {
let (attr, derives, after_derive) = if stmt.is_item() { // FIXME: Handle custom attributes on statements (#15701).
// FIXME: Handle custom attributes on statements (#15701) let attr =
(None, vec![], false) if stmt.is_item() { None } else { self.take_first_attr_no_derive(&mut stmt) };
} else {
// ignore derives on non-item statements so it falls through
// to the unused-attributes lint
let (attr, after_derive) = self.classify_nonitem(&mut stmt);
(attr, vec![], after_derive)
};
if attr.is_some() || !derives.is_empty() { if let Some(attr) = attr {
return self return self
.collect_attr( .collect_attr(attr, Annotatable::Stmt(P(stmt)), AstFragmentKind::Stmts)
attr,
derives,
Annotatable::Stmt(P(stmt)),
AstFragmentKind::Stmts,
after_derive,
)
.make_stmts(); .make_stmts();
} }
} }
@ -1379,16 +1305,9 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
fn flat_map_item(&mut self, item: P<ast::Item>) -> SmallVec<[P<ast::Item>; 1]> { fn flat_map_item(&mut self, item: P<ast::Item>) -> SmallVec<[P<ast::Item>; 1]> {
let mut item = configure!(self, item); let mut item = configure!(self, item);
let (attr, traits, after_derive) = self.classify_item(&mut item); if let Some(attr) = self.take_first_attr(&mut item) {
if attr.is_some() || !traits.is_empty() {
return self return self
.collect_attr( .collect_attr(attr, Annotatable::Item(item), AstFragmentKind::Items)
attr,
traits,
Annotatable::Item(item),
AstFragmentKind::Items,
after_derive,
)
.make_items(); .make_items();
} }
@ -1482,16 +1401,9 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
fn flat_map_trait_item(&mut self, item: P<ast::AssocItem>) -> SmallVec<[P<ast::AssocItem>; 1]> { fn flat_map_trait_item(&mut self, item: P<ast::AssocItem>) -> SmallVec<[P<ast::AssocItem>; 1]> {
let mut item = configure!(self, item); let mut item = configure!(self, item);
let (attr, traits, after_derive) = self.classify_item(&mut item); if let Some(attr) = self.take_first_attr(&mut item) {
if attr.is_some() || !traits.is_empty() {
return self return self
.collect_attr( .collect_attr(attr, Annotatable::TraitItem(item), AstFragmentKind::TraitItems)
attr,
traits,
Annotatable::TraitItem(item),
AstFragmentKind::TraitItems,
after_derive,
)
.make_trait_items(); .make_trait_items();
} }
@ -1512,16 +1424,9 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
fn flat_map_impl_item(&mut self, item: P<ast::AssocItem>) -> SmallVec<[P<ast::AssocItem>; 1]> { fn flat_map_impl_item(&mut self, item: P<ast::AssocItem>) -> SmallVec<[P<ast::AssocItem>; 1]> {
let mut item = configure!(self, item); let mut item = configure!(self, item);
let (attr, traits, after_derive) = self.classify_item(&mut item); if let Some(attr) = self.take_first_attr(&mut item) {
if attr.is_some() || !traits.is_empty() {
return self return self
.collect_attr( .collect_attr(attr, Annotatable::ImplItem(item), AstFragmentKind::ImplItems)
attr,
traits,
Annotatable::ImplItem(item),
AstFragmentKind::ImplItems,
after_derive,
)
.make_impl_items(); .make_impl_items();
} }
@ -1562,16 +1467,12 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
&mut self, &mut self,
mut foreign_item: P<ast::ForeignItem>, mut foreign_item: P<ast::ForeignItem>,
) -> SmallVec<[P<ast::ForeignItem>; 1]> { ) -> SmallVec<[P<ast::ForeignItem>; 1]> {
let (attr, traits, after_derive) = self.classify_item(&mut foreign_item); if let Some(attr) = self.take_first_attr(&mut foreign_item) {
if attr.is_some() || !traits.is_empty() {
return self return self
.collect_attr( .collect_attr(
attr, attr,
traits,
Annotatable::ForeignItem(foreign_item), Annotatable::ForeignItem(foreign_item),
AstFragmentKind::ForeignItems, AstFragmentKind::ForeignItems,
after_derive,
) )
.make_foreign_items(); .make_foreign_items();
} }
@ -1606,15 +1507,12 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
) -> SmallVec<[ast::GenericParam; 1]> { ) -> SmallVec<[ast::GenericParam; 1]> {
let mut param = configure!(self, param); let mut param = configure!(self, param);
let (attr, traits, after_derive) = self.classify_item(&mut param); if let Some(attr) = self.take_first_attr(&mut param) {
if attr.is_some() || !traits.is_empty() {
return self return self
.collect_attr( .collect_attr(
attr, attr,
traits,
Annotatable::GenericParam(param), Annotatable::GenericParam(param),
AstFragmentKind::GenericParams, AstFragmentKind::GenericParams,
after_derive,
) )
.make_generic_params(); .make_generic_params();
} }