Skip to main content

rustc_attr_parsing/
template.rs

1use rustc_ast::ast::Safety;
2use rustc_hir::AttrStyle;
3use rustc_span::Symbol;
4
5/// A template to suggest the correct syntax of an attribute.
6///
7/// This is not used to *check* attributes. The attribute's parser is responsible for that.
8/// Only top-level shape (`#[attr]` vs `#[attr(...)]` vs `#[attr = ...]`) is considered now.
9#[derive(#[automatically_derived]
impl ::core::clone::Clone for AttributeTemplate {
    #[inline]
    fn clone(&self) -> AttributeTemplate {
        let _: ::core::clone::AssertParamIsClone<bool>;
        let _:
                ::core::clone::AssertParamIsClone<Option<&'static [&'static str]>>;
        let _: ::core::clone::AssertParamIsClone<&'static [Symbol]>;
        let _:
                ::core::clone::AssertParamIsClone<Option<&'static [&'static str]>>;
        let _: ::core::clone::AssertParamIsClone<Option<&'static str>>;
        *self
    }
}Clone, #[automatically_derived]
impl ::core::marker::Copy for AttributeTemplate { }Copy, #[automatically_derived]
impl ::core::default::Default for AttributeTemplate {
    #[inline]
    fn default() -> AttributeTemplate {
        AttributeTemplate {
            word: ::core::default::Default::default(),
            list: ::core::default::Default::default(),
            one_of: ::core::default::Default::default(),
            name_value_str: ::core::default::Default::default(),
            docs: ::core::default::Default::default(),
        }
    }
}Default)]
10pub struct AttributeTemplate {
11    /// If `true`, the attribute is allowed to be a bare word like `#[test]`.
12    pub word: bool,
13    /// If `Some`, the attribute is allowed to take a list of items like `#[allow(..)]`.
14    pub list: Option<&'static [&'static str]>,
15    /// If non-empty, the attribute is allowed to take a list containing exactly
16    /// one of the listed words, like `#[coverage(off)]`.
17    pub one_of: &'static [Symbol],
18    /// If `Some`, the attribute is allowed to be a name/value pair where the
19    /// value is a string, like `#[must_use = "reason"]`.
20    pub name_value_str: Option<&'static [&'static str]>,
21    /// A link to the document for this attribute.
22    pub docs: Option<&'static str>,
23}
24
25pub enum AttrSuggestionStyle {
26    /// The suggestion is styled for a normal attribute.
27    /// The `AttrStyle` determines whether this is an inner or outer attribute.
28    Attribute(AttrStyle),
29    /// The suggestion is styled for an attribute embedded into another attribute.
30    /// For example, attributes inside `#[cfg_attr(true, attr(...)]`.
31    EmbeddedAttribute,
32    /// The suggestion is styled for macros that are parsed with attribute parsers.
33    /// For example, the `cfg!(predicate)` macro.
34    Macro,
35}
36
37impl AttributeTemplate {
38    pub fn suggestions(
39        &self,
40        style: AttrSuggestionStyle,
41        safety: Safety,
42        name: impl std::fmt::Display,
43    ) -> Vec<String> {
44        let (start, macro_call, end) = match style {
45            AttrSuggestionStyle::Attribute(AttrStyle::Outer) => ("#[", "", "]"),
46            AttrSuggestionStyle::Attribute(AttrStyle::Inner) => ("#![", "", "]"),
47            AttrSuggestionStyle::Macro => ("", "!", ""),
48            AttrSuggestionStyle::EmbeddedAttribute => ("", "", ""),
49        };
50
51        let mut suggestions = ::alloc::vec::Vec::new()vec![];
52
53        let (safety_start, safety_end) = match safety {
54            Safety::Unsafe(_) => ("unsafe(", ")"),
55            _ => ("", ""),
56        };
57
58        if self.word {
59            if true {
    if !macro_call.is_empty() {
        {
            ::core::panicking::panic_fmt(format_args!("Macro suggestions use list style"));
        }
    };
};debug_assert!(macro_call.is_empty(), "Macro suggestions use list style");
60            suggestions.push(::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0}{1}{2}{3}{4}", start,
                safety_start, name, safety_end, end))
    })format!("{start}{safety_start}{name}{safety_end}{end}"));
61        }
62        if let Some(descr) = self.list {
63            for descr in descr {
64                suggestions.push(::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0}{1}{2}{3}({4}){5}{6}", start,
                safety_start, name, macro_call, descr, safety_end, end))
    })format!(
65                    "{start}{safety_start}{name}{macro_call}({descr}){safety_end}{end}"
66                ));
67            }
68        }
69        suggestions.extend(
70            self.one_of
71                .iter()
72                .map(|&word| ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0}{1}{2}({3}){4}{5}", start,
                safety_start, name, word, safety_end, end))
    })format!("{start}{safety_start}{name}({word}){safety_end}{end}")),
73        );
74        if let Some(descr) = self.name_value_str {
75            if true {
    if !macro_call.is_empty() {
        {
            ::core::panicking::panic_fmt(format_args!("Macro suggestions use list style"));
        }
    };
};debug_assert!(macro_call.is_empty(), "Macro suggestions use list style");
76            for descr in descr {
77                suggestions
78                    .push(::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0}{1}{2} = \"{3}\"{4}{5}", start,
                safety_start, name, descr, safety_end, end))
    })format!("{start}{safety_start}{name} = \"{descr}\"{safety_end}{end}"));
79            }
80        }
81        suggestions.sort();
82
83        suggestions
84    }
85}
86
87/// A convenience macro for constructing attribute templates.
88/// E.g., `template!(Word, List: "description")` means that the attribute
89/// supports forms `#[attr]` and `#[attr(description)]`.
90#[macro_export]
91macro_rules! template {
92    (Word) => { $crate::template!(@ true, None, &[], None, None) };
93    (Word, $link: literal) => { $crate::template!(@ true, None, &[], None, Some($link)) };
94    (List: $descr: expr) => { $crate::template!(@ false, Some($descr), &[], None, None) };
95    (List: $descr: expr, $link: literal) => { $crate::template!(@ false, Some($descr), &[], None, Some($link)) };
96    (OneOf: $one_of: expr) => { $crate::template!(@ false, None, $one_of, None, None) };
97    (NameValueStr: [$($descr: literal),* $(,)?]) => { $crate::template!(@ false, None, &[], Some(&[$($descr,)*]), None) };
98    (NameValueStr: [$($descr: literal),* $(,)?], $link: literal) => { $crate::template!(@ false, None, &[], Some(&[$($descr,)*]), Some($link)) };
99    (NameValueStr: $descr: literal) => { $crate::template!(@ false, None, &[], Some(&[$descr]), None) };
100    (NameValueStr: $descr: literal, $link: literal) => { $crate::template!(@ false, None, &[], Some(&[$descr]), Some($link)) };
101    (Word, List: $descr: expr) => { $crate::template!(@ true, Some($descr), &[], None, None) };
102    (Word, List: $descr: expr, $link: literal) => { $crate::template!(@ true, Some($descr), &[], None, Some($link)) };
103    (Word, NameValueStr: $descr: expr) => { $crate::template!(@ true, None, &[], Some(&[$descr]), None) };
104    (Word, NameValueStr: $descr: expr, $link: literal) => { $crate::template!(@ true, None, &[], Some(&[$descr]), Some($link)) };
105    (List: $descr1: expr, NameValueStr: $descr2: expr) => {
106        $crate::template!(@ false, Some($descr1), &[], Some(&[$descr2]), None)
107    };
108    (List: $descr1: expr, NameValueStr: $descr2: expr, $link: literal) => {
109        $crate::template!(@ false, Some($descr1), &[], Some(&[$descr2]), Some($link))
110    };
111    (Word, List: $descr1: expr, NameValueStr: $descr2: expr) => {
112        $crate::template!(@ true, Some($descr1), &[], Some(&[$descr2]), None)
113    };
114    (Word, List: $descr1: expr, NameValueStr: $descr2: expr, $link: literal) => {
115        $crate::template!(@ true, Some($descr1), &[], Some(&[$descr2]), Some($link))
116    };
117    (@ $word: expr, $list: expr, $one_of: expr, $name_value_str: expr, $link: expr) => { $crate::AttributeTemplate {
118        word: $word, list: $list, one_of: $one_of, name_value_str: $name_value_str, docs: $link,
119    } };
120}