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