Skip to main content

rustc_attr_parsing/
template.rs

1use rustc_ast::ast::Safety;
2use rustc_span::Symbol;
3
4use crate::ParsedDescription;
5
6/// A template to suggest the correct syntax of an attribute.
7///
8/// This is not used to *check* attributes. The attribute's parser is responsible for that.
9/// Only top-level shape (`#[attr]` vs `#[attr(...)]` vs `#[attr = ...]`) is considered now.
10#[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)]
11pub struct AttributeTemplate {
12    /// If `true`, the attribute is allowed to be a bare word like `#[test]`.
13    pub word: bool,
14    /// If `Some`, the attribute is allowed to take a list of items like `#[allow(..)]`.
15    pub list: Option<&'static [&'static str]>,
16    /// If non-empty, the attribute is allowed to take a list containing exactly
17    /// one of the listed words, like `#[coverage(off)]`.
18    pub one_of: &'static [Symbol],
19    /// If `Some`, the attribute is allowed to be a name/value pair where the
20    /// value is a string, like `#[must_use = "reason"]`.
21    pub name_value_str: Option<&'static [&'static str]>,
22    /// A link to the document for this attribute.
23    pub docs: Option<&'static str>,
24}
25
26impl AttributeTemplate {
27    pub fn suggestions(
28        &self,
29        description: ParsedDescription,
30        safety: Safety,
31        name: impl std::fmt::Display,
32    ) -> Vec<String> {
33        let macro_call = match description {
34            ParsedDescription::Macro => "!",
35            ParsedDescription::Attribute => "",
36        };
37
38        let mut suggestions = ::alloc::vec::Vec::new()vec![];
39
40        let (safety_start, safety_end) = match safety {
41            Safety::Unsafe(_) => ("unsafe(", ")"),
42            _ => ("", ""),
43        };
44
45        if self.word {
46            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");
47            suggestions.push(::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0}{1}{2}", safety_start, name,
                safety_end))
    })format!("{safety_start}{name}{safety_end}"));
48        }
49        if let Some(descr) = self.list {
50            for descr in descr {
51                suggestions.push(::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0}{1}{2}({3}){4}", safety_start,
                name, macro_call, descr, safety_end))
    })format!("{safety_start}{name}{macro_call}({descr}){safety_end}"));
52            }
53        }
54        suggestions.extend(
55            self.one_of.iter().map(|&word| ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0}{1}({2}){3}", safety_start,
                name, word, safety_end))
    })format!("{safety_start}{name}({word}){safety_end}")),
56        );
57        if let Some(descr) = self.name_value_str {
58            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");
59            for descr in descr {
60                suggestions.push(::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0}{1} = \"{2}\"{3}", safety_start,
                name, descr, safety_end))
    })format!("{safety_start}{name} = \"{descr}\"{safety_end}"));
61            }
62        }
63        suggestions.sort();
64
65        suggestions
66    }
67}
68
69/// A convenience macro for constructing attribute templates.
70/// E.g., `template!(Word, List: "description")` means that the attribute
71/// supports forms `#[attr]` and `#[attr(description)]`.
72#[macro_export]
73macro_rules! template {
74    (Word) => { $crate::template!(@ true, None, &[], None, None) };
75    (Word, $link: literal) => { $crate::template!(@ true, None, &[], None, Some($link)) };
76    (List: $descr: expr) => { $crate::template!(@ false, Some($descr), &[], None, None) };
77    (List: $descr: expr, $link: literal) => { $crate::template!(@ false, Some($descr), &[], None, Some($link)) };
78    (OneOf: $one_of: expr) => { $crate::template!(@ false, None, $one_of, None, None) };
79    (NameValueStr: [$($descr: literal),* $(,)?]) => { $crate::template!(@ false, None, &[], Some(&[$($descr,)*]), None) };
80    (NameValueStr: [$($descr: literal),* $(,)?], $link: literal) => { $crate::template!(@ false, None, &[], Some(&[$($descr,)*]), Some($link)) };
81    (NameValueStr: $descr: literal) => { $crate::template!(@ false, None, &[], Some(&[$descr]), None) };
82    (NameValueStr: $descr: literal, $link: literal) => { $crate::template!(@ false, None, &[], Some(&[$descr]), Some($link)) };
83    (Word, List: $descr: expr) => { $crate::template!(@ true, Some($descr), &[], None, None) };
84    (Word, List: $descr: expr, $link: literal) => { $crate::template!(@ true, Some($descr), &[], None, Some($link)) };
85    (Word, NameValueStr: $descr: expr) => { $crate::template!(@ true, None, &[], Some(&[$descr]), None) };
86    (Word, NameValueStr: $descr: expr, $link: literal) => { $crate::template!(@ true, None, &[], Some(&[$descr]), Some($link)) };
87    (List: $descr1: expr, NameValueStr: $descr2: expr) => {
88        $crate::template!(@ false, Some($descr1), &[], Some(&[$descr2]), None)
89    };
90    (List: $descr1: expr, NameValueStr: $descr2: expr, $link: literal) => {
91        $crate::template!(@ false, Some($descr1), &[], Some(&[$descr2]), Some($link))
92    };
93    (Word, List: $descr1: expr, NameValueStr: $descr2: expr) => {
94        $crate::template!(@ true, Some($descr1), &[], Some(&[$descr2]), None)
95    };
96    (Word, List: $descr1: expr, NameValueStr: $descr2: expr, $link: literal) => {
97        $crate::template!(@ true, Some($descr1), &[], Some(&[$descr2]), Some($link))
98    };
99    (@ $word: expr, $list: expr, $one_of: expr, $name_value_str: expr, $link: expr) => { $crate::AttributeTemplate {
100        word: $word, list: $list, one_of: $one_of, name_value_str: $name_value_str, docs: $link,
101    } };
102}