1+ use std:: marker:: PhantomData ;
2+
3+ use rustc_ast:: AttrStyle ;
14use rustc_hir:: HashIgnoredAttrId ;
25use rustc_hir:: attrs:: { LintAttrIdsInformation , LintAttributeKind } ;
36use rustc_hir:: lints:: { AttributeLintKind , RenamedLintSuggestion } ;
@@ -9,7 +12,9 @@ use super::prelude::*;
912use crate :: session_diagnostics:: UnknownToolInScopedLint ;
1013use crate :: target_checking:: Policy ;
1114
12- const ALLOWED_TARGETS : & ' static [ Policy ] = & [
15+ const ALLOWED_TARGETS : & ' static [ Policy ] = {
16+ use super :: prelude:: { Allow , Warn } ;
17+ & [
1318 Allow ( Target :: ExternCrate ) ,
1419 Allow ( Target :: Use ) ,
1520 Allow ( Target :: Static ) ,
@@ -45,49 +50,62 @@ const ALLOWED_TARGETS: &'static [Policy] = &[
4550 Allow ( Target :: Param ) ,
4651 Allow ( Target :: PatField ) ,
4752 Allow ( Target :: ExprField ) ,
48- Allow ( Target :: MacroCall ) ,
4953 Allow ( Target :: Crate ) ,
5054 Allow ( Target :: Delegation { mac : false } ) ,
5155 Allow ( Target :: Delegation { mac : true } ) ,
52- ]
56+ Warn ( Target :: MacroCall ) ,
57+ ] }
5358;
5459
60+
61+ pub ( crate ) trait Lint {
62+ fn lint_level < S : Stage > ( cx : & FinalizeContext < ' _ , ' _ , S > , ) -> LintAttributeKind ;
63+ const ATTR_SYMBOL : Symbol ;
64+ }
65+
5566#[ derive( Default ) ]
56- pub ( crate ) struct AllowParser {
67+ pub ( crate ) struct LintParser < T : Lint > {
5768 lint_ids : ThinVec < LintAttrIdsInformation > ,
5869 reason : Option < Symbol > ,
5970 errored : bool ,
6071 attr_span : Option < Span > ,
72+ attr_style : Option < AttrStyle > ,
73+ phantom : PhantomData < T > ,
6174}
6275
63- // Needs to be manually impl:ed as `AttributeParser`, because otherwise deduplication occurs
64- impl < S : Stage > AttributeParser < S > for AllowParser {
76+ impl < S : Stage , T : Lint + ' static + Default > AttributeParser < S > for LintParser < T > {
6577 const ATTRIBUTES : AcceptMapping < Self , S > = & [ (
66- & [ sym :: allow ] ,
78+ & [ T :: ATTR_SYMBOL ] ,
6779 template ! (
6880 List : & [ "lint1" , "lint1, lint2, ..." , r#"lint1, lint2, lint3, reason = "...""# ] ,
6981 "https://doc.rust-lang.org/reference/attributes/diagnostics.html#lint-check-attributes"
7082 ) ,
7183 |this, cx, args| {
84+ * this = Self :: default ( ) ;
7285 this. attr_span = Some ( cx. attr_span ) ;
86+ this. attr_style = Some ( cx. attr_style ) ;
7387 validate_lint_attr (
7488 cx,
7589 args,
7690 & mut this. lint_ids ,
7791 & mut this. errored ,
7892 & mut this. reason ,
79- sym :: allow ,
93+ T :: ATTR_SYMBOL ,
8094 ) ;
8195 } ,
8296 ) ] ;
8397
84- fn finalize ( self , _cx : & FinalizeContext < ' _ , ' _ , S > ) -> Option < AttributeKind > {
85- if !self . errored && !self . attr_span . is_none ( ) {
98+ fn finalize ( self , cx : & FinalizeContext < ' _ , ' _ , S > ) -> Option < AttributeKind > {
99+ let ( Some ( attr_span) , Some ( attr_style) ) = ( self . attr_span , self . attr_style ) else {
100+ return None ;
101+ } ;
102+ if !self . errored {
86103 Some ( AttributeKind :: LintAttribute {
87104 lint_groups : self . lint_ids ,
88105 reason : self . reason ,
89- kind : LintAttributeKind :: Allow ,
90- attr_span : self . attr_span . unwrap ( ) ,
106+ kind : T :: lint_level ( cx) ,
107+ attr_span,
108+ attr_style,
91109 } )
92110 } else {
93111 None
@@ -96,178 +114,63 @@ impl<S: Stage> AttributeParser<S> for AllowParser {
96114
97115 const ALLOWED_TARGETS : AllowedTargets = AllowedTargets :: AllowList ( ALLOWED_TARGETS ) ;
98116}
99- #[ derive( Default ) ]
100- pub ( crate ) struct DenyParser {
101- lint_ids : ThinVec < LintAttrIdsInformation > ,
102- reason : Option < Symbol > ,
103- errored : bool ,
104- attr_span : Option < Span > ,
105117
106- }
107- impl < S : Stage > AttributeParser < S > for DenyParser {
108- const ATTRIBUTES : AcceptMapping < Self , S > = & [ (
109- & [ sym:: deny] ,
110- template ! (
111- List : & [ "lint1" , "lint1, lint2, ..." , r#"lint1, lint2, lint3, reason = "...""# ] ,
112- "https://doc.rust-lang.org/reference/attributes/diagnostics.html#lint-check-attributes"
113- ) ,
114- |this, cx, args| {
115- this. attr_span = Some ( cx. attr_span ) ;
116- validate_lint_attr (
117- cx,
118- args,
119- & mut this. lint_ids ,
120- & mut this. errored ,
121- & mut this. reason ,
122- sym:: deny,
123- ) ;
124- } ,
125- ) ] ;
118+ #[ derive( Default ) ]
119+ pub ( crate ) struct Expect ;
120+ pub ( crate ) type ExpectParser = LintParser < Expect > ;
126121
127- fn finalize ( self , _cx : & FinalizeContext < ' _ , ' _ , S > ) -> Option < AttributeKind > {
128- if !self . errored && !self . attr_span . is_none ( ) {
129- Some ( AttributeKind :: LintAttribute {
130- lint_groups : self . lint_ids ,
131- reason : self . reason ,
132- kind : LintAttributeKind :: Deny , attr_span : self . attr_span . unwrap ( ) ,
133- } )
134- } else {
135- None
136- }
122+ impl Lint for Expect {
123+ fn lint_level < S : Stage > ( cx : & FinalizeContext < ' _ , ' _ , S > ) -> LintAttributeKind {
124+ LintAttributeKind :: Expect ( HashIgnoredAttrId { attr_id : cx. attr_id } )
137125 }
138-
139- const ALLOWED_TARGETS : AllowedTargets = AllowedTargets :: AllowList ( ALLOWED_TARGETS ) ;
140- }
126+ const ATTR_SYMBOL : Symbol = sym:: expect;
127+ }
141128
142129#[ derive( Default ) ]
143- pub ( crate ) struct ForbidParser {
144- lint_ids : ThinVec < LintAttrIdsInformation > ,
145- reason : Option < Symbol > ,
146- errored : bool ,
147- attr_span : Option < Span > ,
130+ pub ( crate ) struct Allow ;
131+ pub ( crate ) type AllowParser = LintParser < Allow > ;
148132
149- }
150- impl < S : Stage > AttributeParser < S > for ForbidParser {
151- const ATTRIBUTES : AcceptMapping < Self , S > = & [ (
152- & [ sym:: forbid] ,
153- template ! (
154- List : & [ "lint1" , "lint1, lint2, ..." , r#"lint1, lint2, lint3, reason = "...""# ] ,
155- "https://doc.rust-lang.org/reference/attributes/diagnostics.html#lint-check-attributes"
156- ) ,
157- |this, cx, args| {
158- this. attr_span = Some ( cx. attr_span ) ;
159- validate_lint_attr (
160- cx,
161- args,
162- & mut this. lint_ids ,
163- & mut this. errored ,
164- & mut this. reason ,
165- sym:: forbid,
166- ) ;
167- } ,
168- ) ] ;
169-
170- fn finalize ( self , _cx : & FinalizeContext < ' _ , ' _ , S > ) -> Option < AttributeKind > {
171- if !self . errored {
172- Some ( AttributeKind :: LintAttribute {
173- lint_groups : self . lint_ids ,
174- reason : self . reason ,
175- kind : LintAttributeKind :: Forbid , attr_span : self . attr_span . unwrap ( ) ,
176- } )
177- } else {
178- None
179- }
133+ impl Lint for Allow {
134+ fn lint_level < S : Stage > ( _cx : & FinalizeContext < ' _ , ' _ , S > ) -> LintAttributeKind {
135+ LintAttributeKind :: Allow
180136 }
137+ const ATTR_SYMBOL : Symbol = sym:: allow;
138+ }
139+ #[ derive( Default ) ]
140+ pub ( crate ) struct Warn ;
141+ pub ( crate ) type WarnParser = LintParser < Warn > ;
181142
182- const ALLOWED_TARGETS : AllowedTargets = AllowedTargets :: AllowList ( ALLOWED_TARGETS ) ;
183- }
143+ impl Lint for Warn {
144+ fn lint_level < S : Stage > ( _cx : & FinalizeContext < ' _ , ' _ , S > ) -> LintAttributeKind {
145+ LintAttributeKind :: Warn
146+ }
147+ const ATTR_SYMBOL : Symbol = sym:: warn;
148+ }
184149
185150#[ derive( Default ) ]
186- pub ( crate ) struct WarnParser {
187- lint_ids : ThinVec < LintAttrIdsInformation > ,
188- reason : Option < Symbol > ,
189- errored : bool ,
190- attr_span : Option < Span > ,
191-
192- }
193- impl < S : Stage > AttributeParser < S > for WarnParser {
194- const ATTRIBUTES : AcceptMapping < Self , S > = & [ (
195- & [ sym:: warn] ,
196- template ! (
197- List : & [ "lint1" , "lint1, lint2, ..." , r#"lint1, lint2, lint3, reason = "...""# ] ,
198- "https://doc.rust-lang.org/reference/attributes/diagnostics.html#lint-check-attributes"
199- ) ,
200- |this, cx, args| {
201- this. attr_span = Some ( cx. attr_span ) ;
202- validate_lint_attr (
203- cx,
204- args,
205- & mut this. lint_ids ,
206- & mut this. errored ,
207- & mut this. reason ,
208- sym:: warn,
209- ) ;
210- } ,
211- ) ] ;
151+ pub ( crate ) struct Deny ;
152+ pub ( crate ) type DenyParser = LintParser < Deny > ;
212153
213- fn finalize ( self , _cx : & FinalizeContext < ' _ , ' _ , S > ) -> Option < AttributeKind > {
214- if !self . errored && !self . attr_span . is_none ( ) {
215- Some ( AttributeKind :: LintAttribute {
216- lint_groups : self . lint_ids ,
217- reason : self . reason ,
218- kind : LintAttributeKind :: Warn , attr_span : self . attr_span . unwrap ( ) ,
219- } )
220- } else {
221- None
222- }
154+ impl Lint for Deny {
155+ fn lint_level < S : Stage > ( _cx : & FinalizeContext < ' _ , ' _ , S > ) -> LintAttributeKind {
156+ LintAttributeKind :: Deny
223157 }
224-
225- const ALLOWED_TARGETS : AllowedTargets = AllowedTargets :: AllowList ( ALLOWED_TARGETS ) ;
226- }
158+ const ATTR_SYMBOL : Symbol = sym:: deny;
159+ }
227160
228161#[ derive( Default ) ]
229- pub ( crate ) struct ExpectParser {
230- lint_ids : ThinVec < LintAttrIdsInformation > ,
231- reason : Option < Symbol > ,
232- errored : bool ,
233- attr_span : Option < Span > ,
162+ pub ( crate ) struct Forbid ;
163+ pub ( crate ) type ForbidParser = LintParser < Forbid > ;
234164
235- }
236- impl < S : Stage > AttributeParser < S > for ExpectParser {
237- const ATTRIBUTES : AcceptMapping < Self , S > = & [ (
238- & [ sym:: expect] ,
239- template ! (
240- List : & [ "lint1" , "lint1, lint2, ..." , r#"lint1, lint2, lint3, reason = "...""# ] ,
241- "https://doc.rust-lang.org/reference/attributes/diagnostics.html#lint-check-attributes"
242- ) ,
243- |this, cx, args| {
244- this. attr_span = Some ( cx. attr_span ) ;
245- validate_lint_attr (
246- cx,
247- args,
248- & mut this. lint_ids ,
249- & mut this. errored ,
250- & mut this. reason ,
251- sym:: expect,
252- ) ;
253- } ,
254- ) ] ;
255-
256- fn finalize ( self , cx : & FinalizeContext < ' _ , ' _ , S > ) -> Option < AttributeKind > {
257- if !self . errored && !self . attr_span . is_none ( ) {
258- Some ( AttributeKind :: LintAttribute {
259- lint_groups : self . lint_ids ,
260- reason : self . reason ,
261- kind : LintAttributeKind :: Expect ( HashIgnoredAttrId { attr_id : cx. attr_id } ) ,
262- attr_span : self . attr_span . unwrap ( ) ,
263- } )
264- } else {
265- None
266- }
165+ impl Lint for Forbid {
166+ fn lint_level < S : Stage > ( _cx : & FinalizeContext < ' _ , ' _ , S > ) -> LintAttributeKind {
167+ LintAttributeKind :: Forbid
267168 }
169+ const ATTR_SYMBOL : Symbol = sym:: forbid;
170+ }
171+
172+
268173
269- const ALLOWED_TARGETS : AllowedTargets = AllowedTargets :: AllowList ( ALLOWED_TARGETS ) ;
270- }
271174
272175#[ inline( always) ]
273176fn validate_lint_attr < S : Stage > (
@@ -278,18 +181,18 @@ fn validate_lint_attr<S: Stage>(
278181 reason : & mut Option < Symbol > ,
279182 attr_name : Symbol ,
280183) {
281- let Some ( list) = args. list ( ) . map ( MetaItemListParser :: mixed) else {
184+
185+ let Some ( list) = args. list ( ) else {
282186 cx. expected_list ( cx. inner_span , args) ;
283187 return ;
284188 } ;
285- let mut list = list. peekable ( ) ;
189+ let mut list = list. mixed ( ) . peekable ( ) ;
286190
287- let mut skip_empty_check = false ;
288191 let mut lint_index = 0 ;
289-
192+ let mut skip_reason_check = false ;
290193 while let Some ( item) = list. next ( ) {
291194 let Some ( meta_item) = item. meta_item ( ) else {
292- cx. expected_string_literal ( item. span ( ) , item . lit ( ) ) ;
195+ cx. expected_identifier ( item. span ( ) ) ;
293196 * errored = true ;
294197 continue ;
295198 } ;
@@ -343,14 +246,12 @@ fn validate_lint_attr<S: Stage>(
343246 {
344247 lint_ids. extend ( ids) ;
345248 } else {
346- // Since external tool lints aren't directly checked by rustc, we don't store these ids
347- // inside the parsed attr, but this still means that something *does* exist in it, so we shouldn't warn
348- skip_empty_check = true ;
249+ skip_reason_check = true
349250 }
350251 lint_index += 1 ;
351252 }
352253 }
353- if !skip_empty_check && ! * errored && lint_ids. is_empty ( ) {
254+ if !skip_reason_check && lint_ids. is_empty ( ) {
354255 cx. warn_empty_attribute ( cx. attr_span ) ;
355256 }
356257}
0 commit comments