1+ //! Utility functions for attributes, including Clippy's built-in ones 
2+ 
13use  crate :: source:: SpanRangeExt ; 
24use  crate :: { sym,  tokenize_with_text} ; 
35use  rustc_ast:: attr; 
@@ -12,131 +14,59 @@ use rustc_session::Session;
1214use  rustc_span:: { Span ,  Symbol } ; 
1315use  std:: str:: FromStr ; 
1416
15- /// Deprecation status of attributes known by Clippy. 
16- pub  enum  DeprecationStatus  { 
17-     /// Attribute is deprecated 
18-      Deprecated , 
19-     /// Attribute is deprecated and was replaced by the named attribute 
20-      Replaced ( & ' static  str ) , 
21-     None , 
22- } 
23- 
24- #[ rustfmt:: skip]  
25- pub  const  BUILTIN_ATTRIBUTES :  & [ ( Symbol ,  DeprecationStatus ) ]  = & [ 
26-     ( sym:: author,                 DeprecationStatus :: None ) , 
27-     ( sym:: version,                DeprecationStatus :: None ) , 
28-     ( sym:: cognitive_complexity,   DeprecationStatus :: None ) , 
29-     ( sym:: cyclomatic_complexity,  DeprecationStatus :: Replaced ( "cognitive_complexity" ) ) , 
30-     ( sym:: dump,                   DeprecationStatus :: None ) , 
31-     ( sym:: msrv,                   DeprecationStatus :: None ) , 
32-     // The following attributes are for the 3rd party crate authors. 
33-     // See book/src/attribs.md 
34-     ( sym:: has_significant_drop,   DeprecationStatus :: None ) , 
35-     ( sym:: format_args,            DeprecationStatus :: None ) , 
36- ] ; 
37- 
38- pub  struct  LimitStack  { 
39-     stack :  Vec < u64 > , 
40- } 
41- 
42- impl  Drop  for  LimitStack  { 
43-     fn  drop ( & mut  self )  { 
44-         assert_eq ! ( self . stack. len( ) ,  1 ) ; 
45-     } 
46- } 
47- 
48- impl  LimitStack  { 
49-     #[ must_use]  
50-     pub  fn  new ( limit :  u64 )  -> Self  { 
51-         Self  {  stack :  vec ! [ limit]  } 
52-     } 
53-     pub  fn  limit ( & self )  -> u64  { 
54-         * self . stack . last ( ) . expect ( "there should always be a value in the stack" ) 
55-     } 
56-     pub  fn  push_attrs ( & mut  self ,  sess :  & Session ,  attrs :  & [ impl  AttributeExt ] ,  name :  Symbol )  { 
57-         let  stack = & mut  self . stack ; 
58-         parse_attrs ( sess,  attrs,  name,  |val| stack. push ( val) ) ; 
59-     } 
60-     pub  fn  pop_attrs ( & mut  self ,  sess :  & Session ,  attrs :  & [ impl  AttributeExt ] ,  name :  Symbol )  { 
61-         let  stack = & mut  self . stack ; 
62-         parse_attrs ( sess,  attrs,  name,  |val| assert_eq ! ( stack. pop( ) ,  Some ( val) ) ) ; 
63-     } 
64- } 
65- 
66- pub  fn  get_attr < ' a ,  A :  AttributeExt  + ' a > ( 
17+ /// Given `attrs`, extract all the instances of a built-in Clippy attribute called `name` 
18+ pub  fn  get_builtin_attr < ' a ,  A :  AttributeExt  + ' a > ( 
6719    sess :  & ' a  Session , 
6820    attrs :  & ' a  [ A ] , 
6921    name :  Symbol , 
7022)  -> impl  Iterator < Item  = & ' a  A >  { 
7123    attrs. iter ( ) . filter ( move  |attr| { 
72-         let  Some ( attr_segments)  = attr. ident_path ( )  else  { 
73-             return  false ; 
74-         } ; 
24+         if  let  Some ( [ clippy,  segment2] )  = attr. ident_path ( ) . as_deref ( ) 
25+             && clippy. name  == sym:: clippy
26+         { 
27+             let  new_name = match  segment2. name  { 
28+                 sym:: cyclomatic_complexity => Some ( "cognitive_complexity" ) , 
29+                 sym:: author
30+                 | sym:: version
31+                 | sym:: cognitive_complexity
32+                 | sym:: dump
33+                 | sym:: msrv
34+                 // The following attributes are for the 3rd party crate authors. 
35+                 // See book/src/attribs.md 
36+                 | sym:: has_significant_drop
37+                 | sym:: format_args => None , 
38+                 _ => { 
39+                     sess. dcx ( ) . span_err ( segment2. span ,  "usage of unknown attribute" ) ; 
40+                     return  false ; 
41+                 } , 
42+             } ; 
7543
76-         if  attr_segments. len ( )  == 2  && attr_segments[ 0 ] . name  == sym:: clippy { 
77-             BUILTIN_ATTRIBUTES 
78-                 . iter ( ) 
79-                 . find_map ( |( builtin_name,  deprecation_status) | { 
80-                     if  attr_segments[ 1 ] . name  == * builtin_name { 
81-                         Some ( deprecation_status) 
82-                     }  else  { 
83-                         None 
84-                     } 
85-                 } ) 
86-                 . map_or_else ( 
87-                     || { 
88-                         sess. dcx ( ) . span_err ( attr_segments[ 1 ] . span ,  "usage of unknown attribute" ) ; 
89-                         false 
90-                     } , 
91-                     |deprecation_status| { 
92-                         let  mut  diag = sess
93-                             . dcx ( ) 
94-                             . struct_span_err ( attr_segments[ 1 ] . span ,  "usage of deprecated attribute" ) ; 
95-                         match  * deprecation_status { 
96-                             DeprecationStatus :: Deprecated  => { 
97-                                 diag. emit ( ) ; 
98-                                 false 
99-                             } , 
100-                             DeprecationStatus :: Replaced ( new_name)  => { 
101-                                 diag. span_suggestion ( 
102-                                     attr_segments[ 1 ] . span , 
103-                                     "consider using" , 
104-                                     new_name, 
105-                                     Applicability :: MachineApplicable , 
106-                                 ) ; 
107-                                 diag. emit ( ) ; 
108-                                 false 
109-                             } , 
110-                             DeprecationStatus :: None  => { 
111-                                 diag. cancel ( ) ; 
112-                                 attr_segments[ 1 ] . name  == name
113-                             } , 
114-                         } 
115-                     } , 
116-                 ) 
44+             match  new_name { 
45+                 Some ( new_name)  => { 
46+                     sess. dcx ( ) 
47+                         . struct_span_err ( segment2. span ,  "usage of deprecated attribute" ) 
48+                         . with_span_suggestion ( 
49+                             segment2. span , 
50+                             "consider using" , 
51+                             new_name, 
52+                             Applicability :: MachineApplicable , 
53+                         ) 
54+                         . emit ( ) ; 
55+                     false 
56+                 } , 
57+                 None  => segment2. name  == name, 
58+             } 
11759        }  else  { 
11860            false 
11961        } 
12062    } ) 
12163} 
12264
123- fn  parse_attrs < F :  FnMut ( u64 ) > ( sess :  & Session ,  attrs :  & [ impl  AttributeExt ] ,  name :  Symbol ,  mut  f :  F )  { 
124-     for  attr in  get_attr ( sess,  attrs,  name)  { 
125-         if  let  Some ( value)  = attr. value_str ( )  { 
126-             if  let  Ok ( value)  = FromStr :: from_str ( value. as_str ( ) )  { 
127-                 f ( value) ; 
128-             }  else  { 
129-                 sess. dcx ( ) . span_err ( attr. span ( ) ,  "not a number" ) ; 
130-             } 
131-         }  else  { 
132-             sess. dcx ( ) . span_err ( attr. span ( ) ,  "bad clippy attribute" ) ; 
133-         } 
134-     } 
135- } 
136- 
137- pub  fn  get_unique_attr < ' a ,  A :  AttributeExt > ( sess :  & ' a  Session ,  attrs :  & ' a  [ A ] ,  name :  Symbol )  -> Option < & ' a  A >  { 
65+ /// If `attrs` contain exactly one instance of a built-in Clippy attribute called `name`, 
66+ /// returns that attribute, and `None` otherwise 
67+ pub  fn  get_unique_builtin_attr < ' a ,  A :  AttributeExt > ( sess :  & ' a  Session ,  attrs :  & ' a  [ A ] ,  name :  Symbol )  -> Option < & ' a  A >  { 
13868    let  mut  unique_attr:  Option < & A >  = None ; 
139-     for  attr in  get_attr ( sess,  attrs,  name)  { 
69+     for  attr in  get_builtin_attr ( sess,  attrs,  name)  { 
14070        if  let  Some ( duplicate)  = unique_attr { 
14171            sess. dcx ( ) 
14272                . struct_span_err ( attr. span ( ) ,  format ! ( "`{name}` is defined multiple times" ) ) 
@@ -149,13 +79,13 @@ pub fn get_unique_attr<'a, A: AttributeExt>(sess: &'a Session, attrs: &'a [A], n
14979    unique_attr
15080} 
15181
152- /// Returns true if the attributes  contain any of `proc_macro`, 
153- /// `proc_macro_derive` or ` proc_macro_attribute`, false otherwise  
82+ /// Checks whether `attrs`  contain any of `proc_macro`, `proc_macro_derive` or  
83+ /// `proc_macro_attribute` 
15484pub  fn  is_proc_macro ( attrs :  & [ impl  AttributeExt ] )  -> bool  { 
15585    attrs. iter ( ) . any ( AttributeExt :: is_proc_macro_attr) 
15686} 
15787
158- /// Returns true if the attributes  contain `#[doc(hidden)]` 
88+ /// Checks whether `attrs`  contain `#[doc(hidden)]` 
15989pub  fn  is_doc_hidden ( attrs :  & [ impl  AttributeExt ] )  -> bool  { 
16090    attrs
16191        . iter ( ) 
@@ -164,6 +94,7 @@ pub fn is_doc_hidden(attrs: &[impl AttributeExt]) -> bool {
16494        . any ( |l| attr:: list_contains_name ( & l,  sym:: hidden) ) 
16595} 
16696
97+ /// Checks whether the given ADT, or any of its fields/variants, are marked as `#[non_exhaustive]` 
16798pub  fn  has_non_exhaustive_attr ( tcx :  TyCtxt < ' _ > ,  adt :  AdtDef < ' _ > )  -> bool  { 
16899    adt. is_variant_list_non_exhaustive ( ) 
169100        || find_attr ! ( tcx. get_all_attrs( adt. did( ) ) ,  AttributeKind :: NonExhaustive ( ..) ) 
@@ -176,7 +107,7 @@ pub fn has_non_exhaustive_attr(tcx: TyCtxt<'_>, adt: AdtDef<'_>) -> bool {
176107            . any ( |field_def| find_attr ! ( tcx. get_all_attrs( field_def. did) ,  AttributeKind :: NonExhaustive ( ..) ) ) 
177108} 
178109
179- /// Checks if  the given span contains a `#[cfg(..)]` attribute 
110+ /// Checks whether  the given span contains a `#[cfg(..)]` attribute 
180111pub  fn  span_contains_cfg ( cx :  & LateContext < ' _ > ,  s :  Span )  -> bool  { 
181112    s. check_source_text ( cx,  |src| { 
182113        let  mut  iter = tokenize_with_text ( src) ; 
@@ -198,3 +129,52 @@ pub fn span_contains_cfg(cx: &LateContext<'_>, s: Span) -> bool {
198129        false 
199130    } ) 
200131} 
132+ 
133+ /// Currently used to keep track of the current value of `#[clippy::cognitive_complexity(N)]` 
134+ pub  struct  LimitStack  { 
135+     default :  u64 , 
136+     stack :  Vec < u64 > , 
137+ } 
138+ 
139+ impl  Drop  for  LimitStack  { 
140+     fn  drop ( & mut  self )  { 
141+         debug_assert_eq ! ( self . stack,  Vec :: <u64 >:: new( ) ) ;  // avoid `.is_empty()`, for a nicer error message 
142+     } 
143+ } 
144+ 
145+ #[ expect( missing_docs,  reason = "they're all trivial..." ) ]  
146+ impl  LimitStack  { 
147+     #[ must_use]  
148+     /// Initialize the stack starting with a default value, which usually comes from configuration 
149+      pub  fn  new ( limit :  u64 )  -> Self  { 
150+         Self  { 
151+             default :  limit, 
152+             stack :  vec ! [ ] , 
153+         } 
154+     } 
155+     pub  fn  limit ( & self )  -> u64  { 
156+         self . stack . last ( ) . copied ( ) . unwrap_or ( self . default ) 
157+     } 
158+     pub  fn  push_attrs ( & mut  self ,  sess :  & Session ,  attrs :  & [ impl  AttributeExt ] ,  name :  Symbol )  { 
159+         let  stack = & mut  self . stack ; 
160+         parse_attrs ( sess,  attrs,  name,  |val| stack. push ( val) ) ; 
161+     } 
162+     pub  fn  pop_attrs ( & mut  self ,  sess :  & Session ,  attrs :  & [ impl  AttributeExt ] ,  name :  Symbol )  { 
163+         let  stack = & mut  self . stack ; 
164+         parse_attrs ( sess,  attrs,  name,  |val| debug_assert_eq ! ( stack. pop( ) ,  Some ( val) ) ) ; 
165+     } 
166+ } 
167+ 
168+ fn  parse_attrs < F :  FnMut ( u64 ) > ( sess :  & Session ,  attrs :  & [ impl  AttributeExt ] ,  name :  Symbol ,  mut  f :  F )  { 
169+     for  attr in  get_builtin_attr ( sess,  attrs,  name)  { 
170+         let  Some ( value)  = attr. value_str ( )  else  { 
171+             sess. dcx ( ) . span_err ( attr. span ( ) ,  "bad clippy attribute" ) ; 
172+             continue ; 
173+         } ; 
174+         let  Ok ( value)  = u64:: from_str ( value. as_str ( ) )  else  { 
175+             sess. dcx ( ) . span_err ( attr. span ( ) ,  "not a number" ) ; 
176+             continue ; 
177+         } ; 
178+         f ( value) ; 
179+     } 
180+ } 
0 commit comments