rustc_attr_parsing/attributes/
lint.rs1use rustc_attr_ir::AttributeKind;
2use rustc_attr_ir::lint::{LintCheck, LintCheckKind};
3use rustc_attr_ir::target::{AssocCtxt, MethodKind, Target};
4use rustc_lint_defs::builtin::UNUSED_ATTRIBUTES;
5use rustc_span::sym;
6use thin_vec::ThinVec;
7
8use crate::attributes::{AcceptMapping, AttributeParser, AttributeStability};
9use crate::context::{AcceptContext, ExpectStringLiteral, FinalizeContext};
10use crate::parser::ArgParser;
11use crate::target_checking::AllowedTargets;
12use crate::target_checking::Policy::{Allow, Warn};
13use crate::{AttributeTemplate, diagnostics, template};
14
15const LINT_TEMPLATE: AttributeTemplate = crate::AttributeTemplate {
word: false,
list: Some(&["lint1", "lint1, lint2, ...",
r#"lint1, lint2, lint3, reason = "...""#]),
one_of: &[],
name_value_str: None,
docs: Some("https://doc.rust-lang.org/reference/attributes/diagnostics.html#lint-check-attributes"),
}template!(
16 List: &["lint1", "lint1, lint2, ...", r#"lint1, lint2, lint3, reason = "...""#],
17 "https://doc.rust-lang.org/reference/attributes/diagnostics.html#lint-check-attributes"
18);
19
20#[derive(#[automatically_derived]
impl ::core::default::Default for LintParser {
#[inline]
fn default() -> Self {
LintParser { lints: ::core::default::Default::default() }
}
}Default, #[automatically_derived]
impl ::core::fmt::Debug for LintParser {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::debug_struct_field1_finish(f, "LintParser",
"lints", &&self.lints)
}
}Debug)]
21pub(crate) struct LintParser {
22 lints: ThinVec<LintCheck>,
23}
24
25impl LintParser {
26 fn parse(&mut self, kind: LintCheckKind, cx: &mut AcceptContext<'_, '_>, args: &ArgParser) {
27 let attr_span = cx.attr_span;
28 let attr_id = cx.attr_id.expect("no `AttrId` for lint attribute");
29
30 if let Some(list) = cx.expect_list(args, cx.attr_span) {
31 let mut parsers = list.sub_parsers();
32 let reason = try {
35 let p = parsers.last()?.meta_item()?;
36 let nv = p.args().as_name_value()?;
37 if !p.path().word_is(sym::reason) {
38 cx.emit_err(diagnostics::MalformedAttribute {
39 span: p.span(),
40 sub: diagnostics::MalformedAttributeSub::BadAttributeArgument(p.span()),
41 });
42 } else {
43 parsers = &parsers[..(parsers.len() - 1)];
44 }
45
46 let reason = nv.expect_string_literal(cx)?;
47 reason
48 };
49
50 for item in parsers {
51 if let Some(p) = item.meta_item() {
52 match p.args() {
53 ArgParser::NoArgs => {
54 let (tool, lint_name, rest) = match &*p.path().0.segments {
55 [] => ::core::panicking::panic("internal error: entered unreachable code")unreachable!(),
56 [lint_name] => (None, lint_name.ident.name, None),
57 [tool, lint_name] => (Some(tool.ident), lint_name.ident.name, None),
58 [tool, lint_name, rest @ ..] => {
59 let rest = rest
60 .iter()
61 .map(|s| s.ident.name)
62 .collect::<Vec<_>>()
63 .into();
64 (Some(tool.ident), lint_name.ident.name, Some(rest))
65 }
66 };
67
68 self.lints.push(LintCheck {
69 tool,
70 lint_name,
71 lint_span: p.span(),
72 kind,
73 attr_id,
74 reason,
75 attr_span,
76 rest,
77 })
78 }
79 ArgParser::NameValue(nv) if p.path().word_is(sym::reason) => {
81 cx.emit_err(diagnostics::MalformedAttribute {
82 span: p.span(),
83 sub: diagnostics::MalformedAttributeSub::ReasonMustComeLast(
84 item.span(),
85 ),
86 });
87 nv.expect_string_literal(cx);
88 }
89 ArgParser::NameValue(_) | ArgParser::List(_) => {
90 cx.emit_err(diagnostics::MalformedAttribute {
91 span: p.span(),
92 sub: diagnostics::MalformedAttributeSub::BadAttributeArgument(
93 item.span(),
94 ),
95 });
96 }
97 }
98 } else {
99 cx.emit_err(diagnostics::MalformedAttribute {
100 span: item.span(),
101 sub: diagnostics::MalformedAttributeSub::BadAttributeArgument(item.span()),
102 });
103 }
104 }
105 if parsers.is_empty() {
106 cx.emit_lint(
107 UNUSED_ATTRIBUTES,
108 diagnostics::Unused {
109 attr_span,
110 note: if list.is_empty() {
111 diagnostics::UnusedNote::EmptyList { name: kind.sym() }
112 } else {
113 diagnostics::UnusedNote::NoLints { name: kind.sym() }
114 },
115 },
116 attr_span,
117 );
118 }
119 }
120 }
121}
122
123impl AttributeParser for LintParser {
124 const ATTRIBUTES: AcceptMapping<Self> = &[
125 (&[sym::allow], LINT_TEMPLATE, AttributeStability::Stable, |this, cx, args| {
126 this.parse(LintCheckKind::Allow, cx, args)
127 }),
128 (&[sym::warn], LINT_TEMPLATE, AttributeStability::Stable, |this, cx, args| {
129 this.parse(LintCheckKind::Warn, cx, args)
130 }),
131 (&[sym::deny], LINT_TEMPLATE, AttributeStability::Stable, |this, cx, args| {
132 this.parse(LintCheckKind::Deny, cx, args)
133 }),
134 (&[sym::forbid], LINT_TEMPLATE, AttributeStability::Stable, |this, cx, args| {
135 this.parse(LintCheckKind::Forbid, cx, args)
136 }),
137 (&[sym::expect], LINT_TEMPLATE, AttributeStability::Stable, |this, cx, args| {
138 this.parse(LintCheckKind::Expect, cx, args)
139 }),
140 ];
141 const ALLOWED_TARGETS: AllowedTargets<'_> = {
142 AllowedTargets::AllowList(&[
143 Allow(Target::ExternCrate),
144 Allow(Target::Use),
145 Allow(Target::Static),
146 Allow(Target::Const),
147 Allow(Target::Fn),
148 Allow(Target::Closure),
149 Allow(Target::Mod),
150 Allow(Target::ForeignMod),
151 Allow(Target::GlobalAsm),
152 Allow(Target::TyAlias),
153 Allow(Target::Enum),
154 Allow(Target::Variant),
155 Allow(Target::Struct),
156 Allow(Target::Field),
157 Allow(Target::Union),
158 Allow(Target::Trait),
159 Allow(Target::TraitAlias),
160 Allow(Target::Impl { of_trait: false }),
161 Allow(Target::Impl { of_trait: true }),
162 Allow(Target::Expression),
163 Allow(Target::Statement),
164 Allow(Target::Arm),
165 Allow(Target::AssocConst(AssocCtxt::Impl { of_trait: false })),
166 Allow(Target::AssocConst(AssocCtxt::Trait)),
167 Allow(Target::AssocConst(AssocCtxt::Impl { of_trait: true })),
168 Allow(Target::Method(MethodKind::Inherent)),
169 Allow(Target::Method(MethodKind::Trait { body: false })),
170 Allow(Target::Method(MethodKind::Trait { body: true })),
171 Allow(Target::Method(MethodKind::TraitImpl)),
172 Allow(Target::AssocTy(AssocCtxt::Impl { of_trait: false })),
173 Allow(Target::AssocTy(AssocCtxt::Trait)),
174 Allow(Target::AssocTy(AssocCtxt::Impl { of_trait: true })),
175 Allow(Target::ForeignFn),
176 Allow(Target::ForeignStatic),
177 Allow(Target::ForeignTy),
178 Allow(Target::MacroDef),
179 Allow(Target::Param),
180 Allow(Target::PatField),
181 Allow(Target::ExprField),
182 Allow(Target::Crate),
183 Allow(Target::Delegation { mac: false }),
184 Allow(Target::Delegation { mac: true }),
185 Allow(Target::ConstParam),
186 Allow(Target::LifetimeParam),
187 Allow(Target::TypeParam),
188 Allow(Target::Loop),
189 Allow(Target::ForLoop),
190 Allow(Target::While),
191 Allow(Target::Break),
192 Warn(Target::MacroCall),
193 ])
194 };
195 fn finalize(self, _cx: &FinalizeContext<'_, '_>) -> Option<AttributeKind> {
196 if self.lints.is_empty() { None } else { Some(AttributeKind::LintCheck(self.lints)) }
197 }
198}