rustc_attr_parsing/attributes/
macro_attrs.rs

1use rustc_errors::DiagArgValue;
2use rustc_hir::attrs::MacroUseArgs;
3
4use super::prelude::*;
5use crate::session_diagnostics::IllFormedAttributeInputLint;
6
7pub(crate) struct MacroEscapeParser;
8impl<S: Stage> NoArgsAttributeParser<S> for MacroEscapeParser {
9    const PATH: &[Symbol] = &[sym::macro_escape];
10    const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
11    const ALLOWED_TARGETS: AllowedTargets = MACRO_USE_ALLOWED_TARGETS;
12    const CREATE: fn(Span) -> AttributeKind = AttributeKind::MacroEscape;
13}
14
15/// `#[macro_use]` attributes can either:
16/// - Use all macros from a crate, if provided without arguments
17/// - Use specific macros from a crate, if provided with arguments `#[macro_use(macro1, macro2)]`
18/// A warning should be provided if an use all is combined with specific uses, or if multiple use-alls are used.
19#[derive(Default)]
20pub(crate) struct MacroUseParser {
21    state: MacroUseArgs,
22
23    /// Spans of all `#[macro_use]` arguments with arguments, used for linting
24    uses_attr_spans: ThinVec<Span>,
25    /// If `state` is `UseSpecific`, stores the span of the first `#[macro_use]` argument, used as the span for this attribute
26    /// If `state` is `UseAll`, stores the span of the first `#[macro_use]` arguments without arguments
27    first_span: Option<Span>,
28}
29
30const MACRO_USE_TEMPLATE: AttributeTemplate = template!(
31    Word, List: &["name1, name2, ..."],
32    "https://doc.rust-lang.org/reference/macros-by-example.html#the-macro_use-attribute"
33);
34const MACRO_USE_ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowListWarnRest(&[
35    Allow(Target::Mod),
36    Allow(Target::ExternCrate),
37    Allow(Target::Crate),
38    Error(Target::WherePredicate),
39]);
40
41impl<S: Stage> AttributeParser<S> for MacroUseParser {
42    const ATTRIBUTES: AcceptMapping<Self, S> = &[(
43        &[sym::macro_use],
44        MACRO_USE_TEMPLATE,
45        |group: &mut Self, cx: &mut AcceptContext<'_, '_, S>, args| {
46            let span = cx.attr_span;
47            group.first_span.get_or_insert(span);
48            match args {
49                ArgParser::NoArgs => {
50                    match group.state {
51                        MacroUseArgs::UseAll => {
52                            let first_span = group.first_span.expect(
53                                "State is UseAll is some so this is not the first attribute",
54                            );
55                            // Since there is a `#[macro_use]` import already, give a warning
56                            cx.warn_unused_duplicate(first_span, span);
57                        }
58                        MacroUseArgs::UseSpecific(_) => {
59                            group.state = MacroUseArgs::UseAll;
60                            group.first_span = Some(span);
61                            // If there is a `#[macro_use]` attribute, warn on all `#[macro_use(...)]` attributes since everything is already imported
62                            for specific_use in group.uses_attr_spans.drain(..) {
63                                cx.warn_unused_duplicate(span, specific_use);
64                            }
65                        }
66                    }
67                }
68                ArgParser::List(list) => {
69                    if list.is_empty() {
70                        cx.warn_empty_attribute(list.span);
71                        return;
72                    }
73
74                    match &mut group.state {
75                        MacroUseArgs::UseAll => {
76                            let first_span = group.first_span.expect(
77                                "State is UseAll is some so this is not the first attribute",
78                            );
79                            cx.warn_unused_duplicate(first_span, span);
80                        }
81                        MacroUseArgs::UseSpecific(arguments) => {
82                            // Store here so if we encounter a `UseAll` later we can still lint this attribute
83                            group.uses_attr_spans.push(cx.attr_span);
84
85                            for item in list.mixed() {
86                                let Some(item) = item.meta_item() else {
87                                    cx.expected_identifier(item.span());
88                                    continue;
89                                };
90                                if let Err(err_span) = item.args().no_args() {
91                                    cx.expected_no_args(err_span);
92                                    continue;
93                                }
94                                let Some(item) = item.path().word() else {
95                                    cx.expected_identifier(item.span());
96                                    continue;
97                                };
98                                arguments.push(item);
99                            }
100                        }
101                    }
102                }
103                ArgParser::NameValue(_) => {
104                    let suggestions = MACRO_USE_TEMPLATE.suggestions(cx.attr_style, sym::macro_use);
105                    cx.emit_err(IllFormedAttributeInputLint {
106                        num_suggestions: suggestions.len(),
107                        suggestions: DiagArgValue::StrListSepByAnd(
108                            suggestions.into_iter().map(|s| format!("`{s}`").into()).collect(),
109                        ),
110                        span,
111                    });
112                }
113            }
114        },
115    )];
116    const ALLOWED_TARGETS: AllowedTargets = MACRO_USE_ALLOWED_TARGETS;
117
118    fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> {
119        Some(AttributeKind::MacroUse { span: self.first_span?, arguments: self.state })
120    }
121}
122
123pub(crate) struct AllowInternalUnsafeParser;
124
125impl<S: Stage> NoArgsAttributeParser<S> for AllowInternalUnsafeParser {
126    const PATH: &[Symbol] = &[sym::allow_internal_unsafe];
127    const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Ignore;
128    const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
129        Allow(Target::Fn),
130        Allow(Target::MacroDef),
131        Warn(Target::Field),
132        Warn(Target::Arm),
133    ]);
134    const CREATE: fn(Span) -> AttributeKind = |span| AttributeKind::AllowInternalUnsafe(span);
135}