rustc_attr_parsing/attributes/
macro_attrs.rs

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