1 //! Meta-syntax validation logic of attributes for post-expansion.
5 use rustc_ast
::tokenstream
::DelimSpan
;
6 use rustc_ast
::{self as ast, Attribute, MacArgs, MacDelimiter, MetaItem, MetaItemKind}
;
7 use rustc_errors
::{Applicability, PResult}
;
8 use rustc_feature
::{AttributeTemplate, BUILTIN_ATTRIBUTE_MAP}
;
9 use rustc_session
::lint
::builtin
::ILL_FORMED_ATTRIBUTE_INPUT
;
10 use rustc_session
::parse
::ParseSess
;
11 use rustc_span
::{sym, Symbol}
;
13 pub fn check_meta(sess
: &ParseSess
, attr
: &Attribute
) {
14 if attr
.is_doc_comment() {
19 attr
.ident().and_then(|ident
| BUILTIN_ATTRIBUTE_MAP
.get(&ident
.name
)).map(|a
| **a
);
21 // Check input tokens for built-in and key-value attributes.
23 // `rustc_dummy` doesn't have any restrictions specific to built-in attributes.
24 Some((name
, _
, template
, _
)) if name
!= sym
::rustc_dummy
=> {
25 check_builtin_attribute(sess
, attr
, name
, template
)
28 if let MacArgs
::Eq(..) = attr
.get_normal_item().args
{
29 // All key-value attributes are restricted to meta-item syntax.
30 parse_meta(sess
, attr
)
40 pub fn parse_meta
<'a
>(sess
: &'a ParseSess
, attr
: &Attribute
) -> PResult
<'a
, MetaItem
> {
41 let item
= attr
.get_normal_item();
44 path
: item
.path
.clone(),
45 kind
: match &item
.args
{
46 MacArgs
::Empty
=> MetaItemKind
::Word
,
47 MacArgs
::Eq(_
, t
) => {
48 let v
= parse_in(sess
, t
.clone(), "name value", |p
| p
.parse_unsuffixed_lit())?
;
49 MetaItemKind
::NameValue(v
)
51 MacArgs
::Delimited(dspan
, delim
, t
) => {
52 check_meta_bad_delim(sess
, *dspan
, *delim
, "wrong meta list delimiters");
53 let nmis
= parse_in(sess
, t
.clone(), "meta list", |p
| p
.parse_meta_seq_top())?
;
54 MetaItemKind
::List(nmis
)
60 pub fn check_meta_bad_delim(sess
: &ParseSess
, span
: DelimSpan
, delim
: MacDelimiter
, msg
: &str) {
61 if let ast
::MacDelimiter
::Parenthesis
= delim
{
66 .struct_span_err(span
.entire(), msg
)
67 .multipart_suggestion(
68 "the delimiters should be `(` and `)`",
69 vec
![(span
.open
, "(".to_string()), (span
.close
, ")".to_string())],
70 Applicability
::MachineApplicable
,
75 /// Checks that the given meta-item is compatible with this `AttributeTemplate`.
76 fn is_attr_template_compatible(template
: &AttributeTemplate
, meta
: &ast
::MetaItemKind
) -> bool
{
78 MetaItemKind
::Word
=> template
.word
,
79 MetaItemKind
::List(..) => template
.list
.is_some(),
80 MetaItemKind
::NameValue(lit
) if lit
.kind
.is_str() => template
.name_value_str
.is_some(),
81 MetaItemKind
::NameValue(..) => false,
85 pub fn check_builtin_attribute(
89 template
: AttributeTemplate
,
91 // Some special attributes like `cfg` must be checked
92 // before the generic check, so we skip them here.
93 let should_skip
= |name
| name
== sym
::cfg
;
94 // Some of previously accepted forms were used in practice,
95 // report them as warnings for now.
96 let should_warn
= |name
| {
98 || name
== sym
::ignore
99 || name
== sym
::inline
102 || name
== sym
::bench
105 match parse_meta(sess
, attr
) {
107 if !should_skip(name
) && !is_attr_template_compatible(&template
, &meta
.kind
) {
108 let error_msg
= format
!("malformed `{}` attribute input", name
);
109 let mut msg
= "attribute must be of the form ".to_owned();
110 let mut suggestions
= vec
![];
111 let mut first
= true;
114 let code
= format
!("#[{}]", name
);
115 msg
.push_str(&format
!("`{}`", &code
));
116 suggestions
.push(code
);
118 if let Some(descr
) = template
.list
{
120 msg
.push_str(" or ");
123 let code
= format
!("#[{}({})]", name
, descr
);
124 msg
.push_str(&format
!("`{}`", &code
));
125 suggestions
.push(code
);
127 if let Some(descr
) = template
.name_value_str
{
129 msg
.push_str(" or ");
131 let code
= format
!("#[{} = \"{}\"]", name
, descr
);
132 msg
.push_str(&format
!("`{}`", &code
));
133 suggestions
.push(code
);
135 if should_warn(name
) {
137 &ILL_FORMED_ATTRIBUTE_INPUT
,
144 .struct_span_err(meta
.span
, &error_msg
)
147 if suggestions
.len() == 1 {
148 "must be of the form"
150 "the following are the possible correct uses"
152 suggestions
.into_iter(),
153 Applicability
::HasPlaceholders
,