diff options
| -rw-r--r-- | compiler/rustc_attr_data_structures/src/attributes.rs | 19 | ||||
| -rw-r--r-- | compiler/rustc_attr_data_structures/src/encode_cross_crate.rs | 2 | ||||
| -rw-r--r-- | compiler/rustc_attr_data_structures/src/lib.rs | 4 | ||||
| -rw-r--r-- | compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs | 115 | ||||
| -rw-r--r-- | compiler/rustc_attr_parsing/src/attributes/mod.rs | 1 | ||||
| -rw-r--r-- | compiler/rustc_attr_parsing/src/attributes/must_use.rs | 2 | ||||
| -rw-r--r-- | compiler/rustc_attr_parsing/src/context.rs | 14 | ||||
| -rw-r--r-- | compiler/rustc_attr_parsing/src/session_diagnostics.rs | 10 | ||||
| -rw-r--r-- | compiler/rustc_hir/src/hir.rs | 1 | ||||
| -rw-r--r-- | compiler/rustc_parse/src/validate_attr.rs | 2 | ||||
| -rw-r--r-- | compiler/rustc_passes/src/check_attr.rs | 17 | ||||
| -rw-r--r-- | compiler/rustc_resolve/messages.ftl | 2 | ||||
| -rw-r--r-- | compiler/rustc_resolve/src/build_reduced_graph.rs | 67 | ||||
| -rw-r--r-- | compiler/rustc_resolve/src/errors.rs | 7 | ||||
| -rw-r--r-- | src/tools/clippy/clippy_lints/src/macro_use.rs | 8 |
15 files changed, 206 insertions, 65 deletions
diff --git a/compiler/rustc_attr_data_structures/src/attributes.rs b/compiler/rustc_attr_data_structures/src/attributes.rs index 9f99b33adcc..1e2576bef2c 100644 --- a/compiler/rustc_attr_data_structures/src/attributes.rs +++ b/compiler/rustc_attr_data_structures/src/attributes.rs @@ -157,6 +157,19 @@ pub enum UsedBy { Linker, } +#[derive(Encodable, Decodable, Clone, Debug, PartialEq, Eq, Hash)] +#[derive(HashStable_Generic, PrintAttribute)] +pub enum MacroUseArgs { + UseAll, + UseSpecific(ThinVec<Ident>), +} + +impl Default for MacroUseArgs { + fn default() -> Self { + Self::UseSpecific(ThinVec::new()) + } +} + #[derive(Debug, Clone, Encodable, Decodable, HashStable_Generic)] pub struct StrippedCfgItem<ModId = DefId> { pub parent_module: ModId, @@ -351,9 +364,15 @@ pub enum AttributeKind { /// Represents `#[loop_match]`. LoopMatch(Span), + /// Represents `#[macro_escape]`. + MacroEscape(Span), + /// Represents `#[rustc_macro_transparency]`. MacroTransparency(Transparency), + /// Represents `#[macro_use]`. + MacroUse { span: Span, arguments: MacroUseArgs }, + /// Represents `#[marker]`. Marker(Span), diff --git a/compiler/rustc_attr_data_structures/src/encode_cross_crate.rs b/compiler/rustc_attr_data_structures/src/encode_cross_crate.rs index 86d9ddba4d2..159b807a3b2 100644 --- a/compiler/rustc_attr_data_structures/src/encode_cross_crate.rs +++ b/compiler/rustc_attr_data_structures/src/encode_cross_crate.rs @@ -45,7 +45,9 @@ impl AttributeKind { LinkOrdinal { .. } => No, LinkSection { .. } => Yes, // Needed for rustdoc LoopMatch(..) => No, + MacroEscape(..) => No, MacroTransparency(..) => Yes, + MacroUse { .. } => No, Marker(..) => No, MayDangle(..) => No, MustUse { .. } => Yes, diff --git a/compiler/rustc_attr_data_structures/src/lib.rs b/compiler/rustc_attr_data_structures/src/lib.rs index ecca0e39063..4c5af805ca9 100644 --- a/compiler/rustc_attr_data_structures/src/lib.rs +++ b/compiler/rustc_attr_data_structures/src/lib.rs @@ -24,7 +24,7 @@ use rustc_ast::token::CommentKind; use rustc_ast::{AttrStyle, IntTy, UintTy}; use rustc_ast_pretty::pp::Printer; use rustc_span::hygiene::Transparency; -use rustc_span::{ErrorGuaranteed, Span, Symbol}; +use rustc_span::{ErrorGuaranteed, Ident, Span, Symbol}; pub use stability::*; use thin_vec::ThinVec; pub use version::*; @@ -172,7 +172,7 @@ macro_rules! print_tup { print_tup!(A B C D E F G H); print_skip!(Span, (), ErrorGuaranteed); print_disp!(u16, bool, NonZero<u32>); -print_debug!(Symbol, UintTy, IntTy, Align, AttrStyle, CommentKind, Transparency); +print_debug!(Symbol, Ident, UintTy, IntTy, Align, AttrStyle, CommentKind, Transparency); /// Finds attributes in sequences of attributes by pattern matching. /// diff --git a/compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs new file mode 100644 index 00000000000..eade49180ac --- /dev/null +++ b/compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs @@ -0,0 +1,115 @@ +use rustc_attr_data_structures::{AttributeKind, MacroUseArgs}; +use rustc_errors::DiagArgValue; +use rustc_feature::{AttributeTemplate, template}; +use rustc_span::{Span, Symbol, sym}; +use thin_vec::ThinVec; + +use crate::attributes::{AcceptMapping, AttributeParser, NoArgsAttributeParser, OnDuplicate}; +use crate::context::{AcceptContext, FinalizeContext, Stage}; +use crate::parser::ArgParser; +use crate::session_diagnostics; + +pub(crate) struct MacroEscapeParser; +impl<S: Stage> NoArgsAttributeParser<S> for MacroEscapeParser { + const PATH: &[Symbol] = &[sym::macro_escape]; + const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn; + const CREATE: fn(Span) -> AttributeKind = AttributeKind::MacroEscape; +} + +/// `#[macro_use]` attributes can either: +/// - Use all macros from a crate, if provided without arguments +/// - Use specific macros from a crate, if provided with arguments `#[macro_use(macro1, macro2)]` +/// A warning should be provided if an use all is combined with specific uses, or if multiple use-alls are used. +#[derive(Default)] +pub(crate) struct MacroUseParser { + state: MacroUseArgs, + + /// Spans of all `#[macro_use]` arguments with arguments, used for linting + uses_attr_spans: ThinVec<Span>, + /// If `state` is `UseSpecific`, stores the span of the first `#[macro_use]` argument, used as the span for this attribute + /// If `state` is `UseAll`, stores the span of the first `#[macro_use]` arguments without arguments + first_span: Option<Span>, +} + +const MACRO_USE_TEMPLATE: AttributeTemplate = template!(Word, List: "name1, name2, ..."); + +impl<S: Stage> AttributeParser<S> for MacroUseParser { + const ATTRIBUTES: AcceptMapping<Self, S> = &[( + &[sym::macro_use], + MACRO_USE_TEMPLATE, + |group: &mut Self, cx: &mut AcceptContext<'_, '_, S>, args| { + let span = cx.attr_span; + group.first_span.get_or_insert(span); + match args { + ArgParser::NoArgs => { + match group.state { + MacroUseArgs::UseAll => { + let first_span = group.first_span.expect( + "State is UseAll is some so this is not the first attribute", + ); + // Since there is a `#[macro_use]` import already, give a warning + cx.warn_unused_duplicate(first_span, span); + } + MacroUseArgs::UseSpecific(_) => { + group.state = MacroUseArgs::UseAll; + group.first_span = Some(span); + // If there is a `#[macro_use]` attribute, warn on all `#[macro_use(...)]` attributes since everything is already imported + for specific_use in group.uses_attr_spans.drain(..) { + cx.warn_unused_duplicate(span, specific_use); + } + } + } + } + ArgParser::List(list) => { + if list.is_empty() { + cx.warn_empty_attribute(list.span); + return; + } + + match &mut group.state { + MacroUseArgs::UseAll => { + let first_span = group.first_span.expect( + "State is UseAll is some so this is not the first attribute", + ); + cx.warn_unused_duplicate(first_span, span); + } + MacroUseArgs::UseSpecific(arguments) => { + // Store here so if we encounter a `UseAll` later we can still lint this attribute + group.uses_attr_spans.push(cx.attr_span); + + for item in list.mixed() { + let Some(item) = item.meta_item() else { + cx.expected_identifier(item.span()); + continue; + }; + if let Err(err_span) = item.args().no_args() { + cx.expected_no_args(err_span); + continue; + } + let Some(item) = item.path().word() else { + cx.expected_identifier(item.span()); + continue; + }; + arguments.push(item); + } + } + } + } + ArgParser::NameValue(_) => { + let suggestions = MACRO_USE_TEMPLATE.suggestions(false, sym::macro_use); + cx.emit_err(session_diagnostics::IllFormedAttributeInputLint { + num_suggestions: suggestions.len(), + suggestions: DiagArgValue::StrListSepByAnd( + suggestions.into_iter().map(|s| format!("`{s}`").into()).collect(), + ), + span, + }); + } + } + }, + )]; + + fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> { + Some(AttributeKind::MacroUse { span: self.first_span?, arguments: self.state }) + } +} diff --git a/compiler/rustc_attr_parsing/src/attributes/mod.rs b/compiler/rustc_attr_parsing/src/attributes/mod.rs index 200f1381960..15b90bd2ed7 100644 --- a/compiler/rustc_attr_parsing/src/attributes/mod.rs +++ b/compiler/rustc_attr_parsing/src/attributes/mod.rs @@ -36,6 +36,7 @@ pub(crate) mod inline; pub(crate) mod link_attrs; pub(crate) mod lint_helpers; pub(crate) mod loop_match; +pub(crate) mod macro_attrs; pub(crate) mod must_use; pub(crate) mod no_implicit_prelude; pub(crate) mod non_exhaustive; diff --git a/compiler/rustc_attr_parsing/src/attributes/must_use.rs b/compiler/rustc_attr_parsing/src/attributes/must_use.rs index e0a3e675509..42af3ed0bfa 100644 --- a/compiler/rustc_attr_parsing/src/attributes/must_use.rs +++ b/compiler/rustc_attr_parsing/src/attributes/must_use.rs @@ -34,7 +34,7 @@ impl<S: Stage> SingleAttributeParser<S> for MustUseParser { ArgParser::List(_) => { let suggestions = <Self as SingleAttributeParser<S>>::TEMPLATE.suggestions(false, "must_use"); - cx.emit_err(session_diagnostics::MustUseIllFormedAttributeInput { + cx.emit_err(session_diagnostics::IllFormedAttributeInputLint { num_suggestions: suggestions.len(), suggestions: DiagArgValue::StrListSepByAnd( suggestions.into_iter().map(|s| format!("`{s}`").into()).collect(), diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index 4d692d9562c..45bfe345207 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -33,6 +33,7 @@ use crate::attributes::lint_helpers::{ AsPtrParser, AutomaticallyDerivedParser, PassByValueParser, PubTransparentParser, }; use crate::attributes::loop_match::{ConstContinueParser, LoopMatchParser}; +use crate::attributes::macro_attrs::{MacroEscapeParser, MacroUseParser}; use crate::attributes::must_use::MustUseParser; use crate::attributes::no_implicit_prelude::NoImplicitPreludeParser; use crate::attributes::non_exhaustive::NonExhaustiveParser; @@ -126,6 +127,7 @@ attribute_parsers!( BodyStabilityParser, ConfusablesParser, ConstStabilityParser, + MacroUseParser, NakedParser, StabilityParser, UsedParser, @@ -174,6 +176,7 @@ attribute_parsers!( Single<WithoutArgs<FfiPureParser>>, Single<WithoutArgs<FundamentalParser>>, Single<WithoutArgs<LoopMatchParser>>, + Single<WithoutArgs<MacroEscapeParser>>, Single<WithoutArgs<MarkerParser>>, Single<WithoutArgs<MayDangleParser>>, Single<WithoutArgs<NoImplicitPreludeParser>>, @@ -386,6 +389,17 @@ impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> { }) } + /// emit an error that a `name` was expected here + pub(crate) fn expected_identifier(&self, span: Span) -> ErrorGuaranteed { + self.emit_err(AttributeParseError { + span, + attr_span: self.attr_span, + template: self.template.clone(), + attribute: self.attr_path.clone(), + reason: AttributeParseErrorReason::ExpectedIdentifier, + }) + } + /// emit an error that a `name = value` pair was expected at this span. The symbol can be given for /// a nicer error message talking about the specific name that was found lacking a value. pub(crate) fn expected_name_value(&self, span: Span, name: Option<Symbol>) -> ErrorGuaranteed { diff --git a/compiler/rustc_attr_parsing/src/session_diagnostics.rs b/compiler/rustc_attr_parsing/src/session_diagnostics.rs index 9a400e0fe10..1de25ca252b 100644 --- a/compiler/rustc_attr_parsing/src/session_diagnostics.rs +++ b/compiler/rustc_attr_parsing/src/session_diagnostics.rs @@ -438,7 +438,7 @@ pub(crate) struct IllFormedAttributeInput { #[derive(Diagnostic)] #[diag(attr_parsing_ill_formed_attribute_input)] -pub(crate) struct MustUseIllFormedAttributeInput { +pub(crate) struct IllFormedAttributeInputLint { #[primary_span] pub span: Span, pub num_suggestions: usize, @@ -549,6 +549,7 @@ pub(crate) enum AttributeParseErrorReason { /// Should we tell the user to write a list when they didn't? list: bool, }, + ExpectedIdentifier, } pub(crate) struct AttributeParseError { @@ -600,11 +601,11 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for AttributeParseError { diag.code(E0538); } AttributeParseErrorReason::UnexpectedLiteral => { - diag.span_label(self.span, format!("didn't expect a literal here")); + diag.span_label(self.span, "didn't expect a literal here"); diag.code(E0565); } AttributeParseErrorReason::ExpectedNoArgs => { - diag.span_label(self.span, format!("didn't expect any arguments here")); + diag.span_label(self.span, "didn't expect any arguments here"); diag.code(E0565); } AttributeParseErrorReason::ExpectedNameValue(None) => { @@ -684,6 +685,9 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for AttributeParseError { } } } + AttributeParseErrorReason::ExpectedIdentifier => { + diag.span_label(self.span, "expected a valid identifier here"); + } } let suggestions = self.template.suggestions(false, &name); diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index e7898648c2b..e83f6a1df72 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -1302,6 +1302,7 @@ impl AttributeExt for Attribute { // FIXME: should not be needed anymore when all attrs are parsed Attribute::Parsed(AttributeKind::Deprecation { span, .. }) => *span, Attribute::Parsed(AttributeKind::DocComment { span, .. }) => *span, + Attribute::Parsed(AttributeKind::MacroUse { span, .. }) => *span, Attribute::Parsed(AttributeKind::MayDangle(span)) => *span, Attribute::Parsed(AttributeKind::Ignore { span, .. }) => *span, Attribute::Parsed(AttributeKind::AutomaticallyDerived(span)) => *span, diff --git a/compiler/rustc_parse/src/validate_attr.rs b/compiler/rustc_parse/src/validate_attr.rs index cca621103b5..ed7fb774908 100644 --- a/compiler/rustc_parse/src/validate_attr.rs +++ b/compiler/rustc_parse/src/validate_attr.rs @@ -303,6 +303,8 @@ pub fn check_builtin_meta_item( | sym::cold | sym::target_feature | sym::rustc_allow_const_fn_unstable + | sym::macro_use + | sym::macro_escape | sym::naked | sym::no_mangle | sym::non_exhaustive diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 96c895e71df..04c1933f243 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -227,6 +227,12 @@ impl<'tcx> CheckAttrVisitor<'tcx> { Attribute::Parsed(AttributeKind::LinkSection { span: attr_span, .. }) => { self.check_link_section(hir_id, *attr_span, span, target) } + Attribute::Parsed(AttributeKind::MacroUse { span, .. }) => { + self.check_macro_use(hir_id, sym::macro_use, *span, target) + } + Attribute::Parsed(AttributeKind::MacroEscape(span)) => { + self.check_macro_use(hir_id, sym::macro_escape, *span, target) + } Attribute::Parsed(AttributeKind::Naked(attr_span)) => { self.check_naked(hir_id, *attr_span, span, target) } @@ -362,9 +368,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { [sym::ffi_pure, ..] => self.check_ffi_pure(attr.span(), attrs, target), [sym::ffi_const, ..] => self.check_ffi_const(attr.span(), target), [sym::link, ..] => self.check_link(hir_id, attr, span, target), - [sym::macro_use, ..] | [sym::macro_escape, ..] => { - self.check_macro_use(hir_id, attr, target) - } [sym::path, ..] => self.check_generic_attr_unparsed(hir_id, attr, target, Target::Mod), [sym::macro_export, ..] => self.check_macro_export(hir_id, attr, target), [sym::should_panic, ..] => { @@ -2411,17 +2414,14 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } } - fn check_macro_use(&self, hir_id: HirId, attr: &Attribute, target: Target) { - let Some(name) = attr.name() else { - return; - }; + fn check_macro_use(&self, hir_id: HirId, name: Symbol, attr_span: Span, target: Target) { match target { Target::ExternCrate | Target::Mod => {} _ => { self.tcx.emit_node_span_lint( UNUSED_ATTRIBUTES, hir_id, - attr.span(), + attr_span, errors::MacroUse { name }, ); } @@ -2474,7 +2474,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { // Warn on useless empty attributes. // FIXME(jdonszelmann): this lint should be moved to attribute parsing, see `AcceptContext::warn_empty_attribute` let note = if attr.has_any_name(&[ - sym::macro_use, sym::allow, sym::expect, sym::warn, diff --git a/compiler/rustc_resolve/messages.ftl b/compiler/rustc_resolve/messages.ftl index aa818cc9c46..39e9a9cc58a 100644 --- a/compiler/rustc_resolve/messages.ftl +++ b/compiler/rustc_resolve/messages.ftl @@ -41,8 +41,6 @@ resolve_attempt_to_use_non_constant_value_in_constant_without_suggestion = resolve_attributes_starting_with_rustc_are_reserved = attributes starting with `rustc` are reserved for use by the `rustc` compiler -resolve_bad_macro_import = bad macro import - resolve_binding_in_never_pattern = never patterns cannot contain variable bindings .suggestion = use a wildcard `_` instead diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index 737577baa7a..fe7fa71a7fc 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -11,11 +11,14 @@ use std::sync::Arc; use rustc_ast::visit::{self, AssocCtxt, Visitor, WalkItemKind}; use rustc_ast::{ self as ast, AssocItem, AssocItemKind, Block, ConstItem, Delegation, Fn, ForeignItem, - ForeignItemKind, Impl, Item, ItemKind, MetaItemKind, NodeId, StaticItem, StmtKind, TyAlias, + ForeignItemKind, Impl, Item, ItemKind, NodeId, StaticItem, StmtKind, TyAlias, }; +use rustc_attr_data_structures::{AttributeKind, MacroUseArgs}; use rustc_attr_parsing as attr; +use rustc_attr_parsing::AttributeParser; use rustc_expand::base::ResolverExpand; use rustc_expand::expand::AstFragment; +use rustc_hir::Attribute; use rustc_hir::def::{self, *}; use rustc_hir::def_id::{CRATE_DEF_ID, DefId, LocalDefId}; use rustc_index::bit_set::DenseBitSet; @@ -25,6 +28,7 @@ use rustc_middle::metadata::ModChild; use rustc_middle::ty::{Feed, Visibility}; use rustc_span::hygiene::{ExpnId, LocalExpnId, MacroKind}; use rustc_span::{Ident, Span, Symbol, kw, sym}; +use thin_vec::ThinVec; use tracing::debug; use crate::Namespace::{MacroNS, TypeNS, ValueNS}; @@ -1019,42 +1023,31 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { /// Returns `true` if we should consider the underlying `extern crate` to be used. fn process_macro_use_imports(&mut self, item: &Item, module: Module<'ra>) -> bool { let mut import_all = None; - let mut single_imports = Vec::new(); - for attr in &item.attrs { - if attr.has_name(sym::macro_use) { - if self.parent_scope.module.parent.is_some() { - self.r.dcx().emit_err(errors::ExternCrateLoadingMacroNotAtCrateRoot { - span: item.span, - }); - } - if let ItemKind::ExternCrate(Some(orig_name), _) = item.kind - && orig_name == kw::SelfLower - { - self.r.dcx().emit_err(errors::MacroUseExternCrateSelf { span: attr.span }); - } - let ill_formed = |span| { - self.r.dcx().emit_err(errors::BadMacroImport { span }); - }; - match attr.meta() { - Some(meta) => match meta.kind { - MetaItemKind::Word => { - import_all = Some(meta.span); - break; - } - MetaItemKind::List(meta_item_inners) => { - for meta_item_inner in meta_item_inners { - match meta_item_inner.ident() { - Some(ident) if meta_item_inner.is_word() => { - single_imports.push(ident) - } - _ => ill_formed(meta_item_inner.span()), - } - } - } - MetaItemKind::NameValue(..) => ill_formed(meta.span), - }, - None => ill_formed(attr.span), - } + let mut single_imports = ThinVec::new(); + if let Some(Attribute::Parsed(AttributeKind::MacroUse { span, arguments })) = + AttributeParser::parse_limited( + self.r.tcx.sess, + &item.attrs, + sym::macro_use, + item.span, + item.id, + None, + ) + { + if self.parent_scope.module.parent.is_some() { + self.r + .dcx() + .emit_err(errors::ExternCrateLoadingMacroNotAtCrateRoot { span: item.span }); + } + if let ItemKind::ExternCrate(Some(orig_name), _) = item.kind + && orig_name == kw::SelfLower + { + self.r.dcx().emit_err(errors::MacroUseExternCrateSelf { span }); + } + + match arguments { + MacroUseArgs::UseAll => import_all = Some(span), + MacroUseArgs::UseSpecific(imports) => single_imports = imports, } } diff --git a/compiler/rustc_resolve/src/errors.rs b/compiler/rustc_resolve/src/errors.rs index b34bcb38f84..d6b1e4de6ea 100644 --- a/compiler/rustc_resolve/src/errors.rs +++ b/compiler/rustc_resolve/src/errors.rs @@ -816,13 +816,6 @@ pub(crate) struct ExternCrateLoadingMacroNotAtCrateRoot { } #[derive(Diagnostic)] -#[diag(resolve_bad_macro_import, code = E0466)] -pub(crate) struct BadMacroImport { - #[primary_span] - pub(crate) span: Span, -} - -#[derive(Diagnostic)] #[diag(resolve_extern_crate_self_requires_renaming)] pub(crate) struct ExternCrateSelfRequiresRenaming { #[primary_span] diff --git a/src/tools/clippy/clippy_lints/src/macro_use.rs b/src/tools/clippy/clippy_lints/src/macro_use.rs index c1a26c5a9c7..d1a54df988f 100644 --- a/src/tools/clippy/clippy_lints/src/macro_use.rs +++ b/src/tools/clippy/clippy_lints/src/macro_use.rs @@ -7,8 +7,9 @@ use rustc_hir::{self as hir, AmbigArg}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_session::impl_lint_pass; use rustc_span::edition::Edition; -use rustc_span::{Span, sym}; +use rustc_span::{Span}; use std::collections::BTreeMap; +use rustc_attr_data_structures::{AttributeKind, find_attr}; declare_clippy_lint! { /// ### What it does @@ -99,15 +100,14 @@ impl LateLintPass<'_> for MacroUseImports { && let hir::ItemKind::Use(path, _kind) = &item.kind && let hir_id = item.hir_id() && let attrs = cx.tcx.hir_attrs(hir_id) - && let Some(mac_attr) = attrs.iter().find(|attr| attr.has_name(sym::macro_use)) + && let Some(mac_attr_span) = find_attr!(attrs, AttributeKind::MacroUse {span, ..} => *span) && let Some(Res::Def(DefKind::Mod, id)) = path.res.type_ns && !id.is_local() { for kid in cx.tcx.module_children(id) { if let Res::Def(DefKind::Macro(_mac_type), mac_id) = kid.res { - let span = mac_attr.span(); let def_path = cx.tcx.def_path_str(mac_id); - self.imports.push((def_path, span, hir_id)); + self.imports.push((def_path, mac_attr_span, hir_id)); } } } else if item.span.from_expansion() { |
