@@ -3,6 +3,7 @@ use crate::utils::{ErrAction, expect_action, walk_dir_no_dot_or_target};
33use core:: ops:: Range ;
44use core:: slice;
55use rustc_data_structures:: fx:: FxHashMap ;
6+ use rustc_index:: { IndexVec , newtype_index} ;
67use rustc_lexer:: { self as lexer, FrontmatterAllowed } ;
78use std:: collections:: hash_map:: { Entry , VacantEntry } ;
89use std:: panic:: Location ;
@@ -27,13 +28,15 @@ pub enum Token<'a> {
2728 DoubleColon ,
2829 Comma ,
2930 Eq ,
31+ FatArrow ,
3032 Lifetime ,
3133 Literal ,
3234 Lt ,
3335 Gt ,
3436 OpenBrace ,
3537 OpenBracket ,
3638 OpenParen ,
39+ OptLifetimeArgs ,
3740 Pound ,
3841 Semi ,
3942}
@@ -134,6 +137,7 @@ impl<'txt> RustSearcher<'txt> {
134137
135138 /// Consumes the next token if it matches the requested value and captures the value if
136139 /// requested. Returns `true` if a token was matched.
140+ #[ expect( clippy:: too_many_lines) ]
137141 fn read_token ( & mut self , token : Token < ' _ > , captures : & mut slice:: IterMut < ' _ , Capture > ) -> bool {
138142 loop {
139143 match ( token, self . next_token . kind ) {
@@ -202,6 +206,25 @@ impl<'txt> RustSearcher<'txt> {
202206 }
203207 return false ;
204208 } ,
209+ ( Token :: FatArrow , lexer:: TokenKind :: Eq ) => {
210+ self . step ( ) ;
211+ if matches ! ( self . next_token. kind, lexer:: TokenKind :: Gt ) {
212+ self . step ( ) ;
213+ return true ;
214+ }
215+ return false ;
216+ } ,
217+ ( Token :: OptLifetimeArgs , lexer:: TokenKind :: Lt ) => {
218+ self . step ( ) ;
219+ while self . read_token ( Token :: Lifetime , captures) {
220+ if !self . read_token ( Token :: Comma , captures) {
221+ break ;
222+ }
223+ }
224+ return self . read_token ( Token :: Gt , captures) ;
225+ } ,
226+ #[ expect( clippy:: match_same_arms) ]
227+ ( Token :: OptLifetimeArgs , _) => return true ,
205228 #[ rustfmt:: skip]
206229 (
207230 Token :: CaptureLitStr ,
@@ -235,16 +258,28 @@ impl<'txt> RustSearcher<'txt> {
235258 }
236259
237260 #[ must_use]
238- pub fn find_capture_token ( & mut self , token : Token < ' _ > ) -> Option < & ' txt str > {
239- let mut capture = Capture :: EMPTY ;
240- let mut captures = slice:: from_mut ( & mut capture) . iter_mut ( ) ;
241- while !self . read_token ( token, & mut captures) {
242- self . step ( ) ;
243- if self . at_end ( ) {
244- return None ;
261+ pub fn find_any_ident ( & mut self ) -> Option < & ' txt str > {
262+ loop {
263+ match self . next_token . kind {
264+ lexer:: TokenKind :: Ident => {
265+ let res = self . peek_text ( ) ;
266+ self . step ( ) ;
267+ return Some ( res) ;
268+ } ,
269+ lexer:: TokenKind :: Eof => return None ,
270+ _ => self . step ( ) ,
245271 }
246272 }
247- Some ( & self . text [ capture. to_index ( ) ] )
273+ }
274+
275+ #[ must_use]
276+ pub fn find_ident ( & mut self , s : & str ) -> bool {
277+ while let Some ( x) = self . find_any_ident ( ) {
278+ if x == s {
279+ return true ;
280+ }
281+ }
282+ false
248283 }
249284
250285 #[ must_use]
@@ -286,9 +321,27 @@ pub struct Lint {
286321 pub name_span : Span ,
287322}
288323
324+ pub struct LintPassData {
325+ pub name : String ,
326+ /// Span of the `impl_lint_pass` or `declare_lint_pass` macro call.
327+ pub mac_span : Span ,
328+ }
329+
330+ newtype_index ! {
331+ #[ orderable]
332+ pub struct LintPass { }
333+ }
334+
335+ pub struct LintRegistration {
336+ pub name : String ,
337+ pub pass : LintPass ,
338+ }
339+
289340pub struct ParsedData {
290341 pub source_map : SourceMap ,
291342 pub lints : FxHashMap < String , Lint > ,
343+ pub lint_passes : IndexVec < LintPass , LintPassData > ,
344+ pub lint_registrations : Vec < LintRegistration > ,
292345 pub deprecated_span : Range < u32 > ,
293346 pub renamed_span : Range < u32 > ,
294347}
@@ -299,6 +352,8 @@ impl ParsedData {
299352 let mut parser = Parser {
300353 source_map : SourceMap :: with_capacity ( 8 , 1000 ) ,
301354 lints : FxHashMap :: with_capacity_and_hasher ( 1000 , Default :: default ( ) ) ,
355+ lint_passes : IndexVec :: with_capacity ( 400 ) ,
356+ lint_registrations : Vec :: with_capacity ( 1000 ) ,
302357 deprecated_span : 0 ..0 ,
303358 renamed_span : 0 ..0 ,
304359 errors : Vec :: new ( ) ,
@@ -355,6 +410,8 @@ impl ParsedData {
355410 ParsedData {
356411 source_map : parser. source_map ,
357412 lints : parser. lints ,
413+ lint_passes : parser. lint_passes ,
414+ lint_registrations : parser. lint_registrations ,
358415 deprecated_span : parser. deprecated_span ,
359416 renamed_span : parser. renamed_span ,
360417 }
@@ -399,6 +456,8 @@ impl From<ErrorKind> for Error {
399456struct Parser {
400457 source_map : SourceMap ,
401458 lints : FxHashMap < String , Lint > ,
459+ lint_passes : IndexVec < LintPass , LintPassData > ,
460+ lint_registrations : Vec < LintRegistration > ,
402461 deprecated_span : Range < u32 > ,
403462 renamed_span : Range < u32 > ,
404463 errors : Vec < Error > ,
@@ -449,7 +508,7 @@ impl Parser {
449508 #[ allow( clippy:: enum_glob_use) ]
450509 use Token :: * ;
451510 #[ rustfmt:: skip]
452- static DECL_TOKENS : & [ Token < ' _ > ] = & [
511+ static LINT_DECL_TOKENS : & [ Token < ' _ > ] = & [
453512 // { /// docs
454513 OpenBrace , AnyComment ,
455514 // #[clippy::version = "version"]
@@ -458,42 +517,89 @@ impl Parser {
458517 Ident ( "pub" ) , CaptureIdent , Comma , AnyComment , CaptureIdent , Comma , AnyComment , LitStr ,
459518 ] ;
460519 #[ rustfmt:: skip]
461- static EXTRA_TOKENS : & [ Token < ' _ > ] = & [
520+ static LINT_DECL_EXTRA_TOKENS : & [ Token < ' _ > ] = & [
462521 // , @option = value
463522 Comma , AnyComment , At , AnyIdent , Eq , Literal ,
464523 ] ;
524+ #[ rustfmt:: skip]
525+ static LINT_PASS_TOKENS : & [ Token < ' _ > ] = & [
526+ // ( name <'lt> => [
527+ OpenParen , AnyComment , CaptureIdent , OptLifetimeArgs , FatArrow , OpenBracket ,
528+ ] ;
465529
466530 let mut searcher = RustSearcher :: new ( & self . source_map . files [ file] . contents ) ;
467531 let mut captures = [ Capture :: EMPTY ; 2 ] ;
468- # [ expect ( clippy :: cast_possible_truncation ) ]
469- while searcher . find_token ( Ident ( "declare_clippy_lint" ) ) {
470- let start = searcher. pos ( ) - "declare_clippy_lint" . len ( ) as u32 ;
532+ while let Some ( ident ) = searcher . find_any_ident ( ) {
533+ # [ expect ( clippy :: cast_possible_truncation ) ]
534+ let start = searcher. pos - ident . len ( ) as u32 ;
471535 if searcher. match_token ( Bang ) {
472- if !searcher. match_tokens ( DECL_TOKENS , & mut captures) {
473- self . errors . push ( searcher. get_unexpected_err ( file) ) ;
474- return ;
475- }
476- let name_span = captures[ 0 ] . to_span ( file) ;
477- let name = searcher. get_capture ( captures[ 0 ] ) . to_ascii_lowercase ( ) ;
478- if let Some ( e) = get_vacant_lint ( name, name_span, & mut self . lints , & mut self . errors ) {
479- e. insert ( Lint {
480- kind : LintKind :: Active ( ActiveLint {
481- group : searcher. get_capture ( captures[ 1 ] ) . into ( ) ,
482- decl_span : Span {
536+ match ident {
537+ "declare_clippy_lint" => {
538+ if !searcher. match_tokens ( LINT_DECL_TOKENS , & mut captures) {
539+ self . errors . push ( searcher. get_unexpected_err ( file) ) ;
540+ return ;
541+ }
542+ while searcher. match_tokens ( LINT_DECL_EXTRA_TOKENS , & mut [ ] ) {
543+ // nothing
544+ }
545+ if !searcher. match_token ( CloseBrace ) {
546+ self . errors . push ( searcher. get_unexpected_err ( file) ) ;
547+ return ;
548+ }
549+ let name_span = captures[ 0 ] . to_span ( file) ;
550+ let name = searcher. get_capture ( captures[ 0 ] ) . to_ascii_lowercase ( ) ;
551+ if let Some ( e) = get_vacant_lint ( name, name_span, & mut self . lints , & mut self . errors ) {
552+ e. insert ( Lint {
553+ kind : LintKind :: Active ( ActiveLint {
554+ group : searcher. get_capture ( captures[ 1 ] ) . into ( ) ,
555+ decl_span : Span {
556+ file,
557+ start,
558+ end : searcher. pos ( ) ,
559+ } ,
560+ } ) ,
561+ name_span,
562+ } ) ;
563+ }
564+ } ,
565+ "impl_lint_pass" | "declare_lint_pass" => {
566+ if !searcher. match_tokens ( LINT_PASS_TOKENS , & mut captures) {
567+ self . errors . push ( searcher. get_unexpected_err ( file) ) ;
568+ return ;
569+ }
570+ let pass = self . lint_passes . next_index ( ) ;
571+ let pass_name = captures[ 0 ] ;
572+ while searcher. match_tokens ( & [ AnyComment , CaptureIdent ] , & mut captures) {
573+ // Read a path expression.
574+ while searcher. match_token ( DoubleColon ) {
575+ // Overwrite the previous capture. The last segment is the lint name we want.
576+ if !searcher. match_tokens ( & [ CaptureIdent ] , & mut captures) {
577+ self . errors . push ( searcher. get_unexpected_err ( file) ) ;
578+ return ;
579+ }
580+ }
581+ self . lint_registrations . push ( LintRegistration {
582+ name : searcher. get_capture ( captures[ 0 ] ) . to_ascii_lowercase ( ) ,
583+ pass,
584+ } ) ;
585+ if !searcher. match_token ( Comma ) {
586+ break ;
587+ }
588+ }
589+ if !searcher. match_tokens ( & [ CloseBracket , CloseParen ] , & mut [ ] ) {
590+ self . errors . push ( searcher. get_unexpected_err ( file) ) ;
591+ return ;
592+ }
593+ self . lint_passes . push ( LintPassData {
594+ name : searcher. get_capture ( pass_name) . to_owned ( ) ,
595+ mac_span : Span {
483596 file,
484597 start,
485598 end : searcher. pos ( ) ,
486599 } ,
487- } ) ,
488- name_span,
489- } ) ;
490- }
491- while searcher. match_tokens ( EXTRA_TOKENS , & mut [ ] ) {
492- // nothing
493- }
494- if !searcher. match_token ( CloseBrace ) {
495- self . errors . push ( searcher. get_unexpected_err ( file) ) ;
496- return ;
600+ } ) ;
601+ } ,
602+ _ => { } ,
497603 }
498604 }
499605 }
@@ -537,11 +643,11 @@ impl Parser {
537643 let mut searcher = RustSearcher :: new ( & file_data. contents ) ;
538644 // First instance is the macro definition.
539645 assert ! (
540- searcher. find_token ( Ident ( "declare_with_version" ) ) ,
541- "error parsing `clippy_lints/src/deprecated_lints.rs`"
646+ searcher. find_ident ( "declare_with_version" ) ,
647+ "error parsing `clippy_lints/src/deprecated_lints.rs`" ,
542648 ) ;
543649
544- if !searcher. find_token ( Ident ( "declare_with_version" ) ) || !searcher. match_tokens ( DEPRECATED_TOKENS , & mut [ ] ) {
650+ if !searcher. find_ident ( "declare_with_version" ) || !searcher. match_tokens ( DEPRECATED_TOKENS , & mut [ ] ) {
545651 self . errors . push ( searcher. get_unexpected_err ( file) ) ;
546652 return ;
547653 }
@@ -570,7 +676,7 @@ impl Parser {
570676 return ;
571677 }
572678
573- if !searcher. find_token ( Ident ( "declare_with_version" ) ) || !searcher. match_tokens ( RENAMED_TOKENS , & mut [ ] ) {
679+ if !searcher. find_ident ( "declare_with_version" ) || !searcher. match_tokens ( RENAMED_TOKENS , & mut [ ] ) {
574680 self . errors . push ( searcher. get_unexpected_err ( file) ) ;
575681 return ;
576682 }
0 commit comments