@@ -3,6 +3,7 @@ use crate::utils::{ErrAction, expect_action, walk_dir_no_dot_or_target};
3
3
use core:: ops:: Range ;
4
4
use core:: slice;
5
5
use rustc_data_structures:: fx:: FxHashMap ;
6
+ use rustc_index:: { IndexVec , newtype_index} ;
6
7
use rustc_lexer:: { self as lexer, FrontmatterAllowed } ;
7
8
use std:: collections:: hash_map:: { Entry , VacantEntry } ;
8
9
use std:: panic:: Location ;
@@ -27,13 +28,15 @@ pub enum Token<'a> {
27
28
DoubleColon ,
28
29
Comma ,
29
30
Eq ,
31
+ FatArrow ,
30
32
Lifetime ,
31
33
Literal ,
32
34
Lt ,
33
35
Gt ,
34
36
OpenBrace ,
35
37
OpenBracket ,
36
38
OpenParen ,
39
+ OptLifetimeArgs ,
37
40
Pound ,
38
41
Semi ,
39
42
}
@@ -134,6 +137,7 @@ impl<'txt> RustSearcher<'txt> {
134
137
135
138
/// Consumes the next token if it matches the requested value and captures the value if
136
139
/// requested. Returns `true` if a token was matched.
140
+ #[ expect( clippy:: too_many_lines) ]
137
141
fn read_token ( & mut self , token : Token < ' _ > , captures : & mut slice:: IterMut < ' _ , Capture > ) -> bool {
138
142
loop {
139
143
match ( token, self . next_token . kind ) {
@@ -202,6 +206,25 @@ impl<'txt> RustSearcher<'txt> {
202
206
}
203
207
return false ;
204
208
} ,
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 ,
205
228
#[ rustfmt:: skip]
206
229
(
207
230
Token :: CaptureLitStr ,
@@ -235,16 +258,28 @@ impl<'txt> RustSearcher<'txt> {
235
258
}
236
259
237
260
#[ 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 ( ) ,
245
271
}
246
272
}
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
248
283
}
249
284
250
285
#[ must_use]
@@ -286,9 +321,27 @@ pub struct Lint {
286
321
pub name_span : Span ,
287
322
}
288
323
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
+
289
340
pub struct ParsedData {
290
341
pub source_map : SourceMap ,
291
342
pub lints : FxHashMap < String , Lint > ,
343
+ pub lint_passes : IndexVec < LintPass , LintPassData > ,
344
+ pub lint_registrations : Vec < LintRegistration > ,
292
345
pub deprecated_span : Range < u32 > ,
293
346
pub renamed_span : Range < u32 > ,
294
347
}
@@ -299,6 +352,8 @@ impl ParsedData {
299
352
let mut parser = Parser {
300
353
source_map : SourceMap :: with_capacity ( 8 , 1000 ) ,
301
354
lints : FxHashMap :: with_capacity_and_hasher ( 1000 , Default :: default ( ) ) ,
355
+ lint_passes : IndexVec :: with_capacity ( 400 ) ,
356
+ lint_registrations : Vec :: with_capacity ( 1000 ) ,
302
357
deprecated_span : 0 ..0 ,
303
358
renamed_span : 0 ..0 ,
304
359
errors : Vec :: new ( ) ,
@@ -355,6 +410,8 @@ impl ParsedData {
355
410
ParsedData {
356
411
source_map : parser. source_map ,
357
412
lints : parser. lints ,
413
+ lint_passes : parser. lint_passes ,
414
+ lint_registrations : parser. lint_registrations ,
358
415
deprecated_span : parser. deprecated_span ,
359
416
renamed_span : parser. renamed_span ,
360
417
}
@@ -399,6 +456,8 @@ impl From<ErrorKind> for Error {
399
456
struct Parser {
400
457
source_map : SourceMap ,
401
458
lints : FxHashMap < String , Lint > ,
459
+ lint_passes : IndexVec < LintPass , LintPassData > ,
460
+ lint_registrations : Vec < LintRegistration > ,
402
461
deprecated_span : Range < u32 > ,
403
462
renamed_span : Range < u32 > ,
404
463
errors : Vec < Error > ,
@@ -449,7 +508,7 @@ impl Parser {
449
508
#[ allow( clippy:: enum_glob_use) ]
450
509
use Token :: * ;
451
510
#[ rustfmt:: skip]
452
- static DECL_TOKENS : & [ Token < ' _ > ] = & [
511
+ static LINT_DECL_TOKENS : & [ Token < ' _ > ] = & [
453
512
// { /// docs
454
513
OpenBrace , AnyComment ,
455
514
// #[clippy::version = "version"]
@@ -458,42 +517,89 @@ impl Parser {
458
517
Ident ( "pub" ) , CaptureIdent , Comma , AnyComment , CaptureIdent , Comma , AnyComment , LitStr ,
459
518
] ;
460
519
#[ rustfmt:: skip]
461
- static EXTRA_TOKENS : & [ Token < ' _ > ] = & [
520
+ static LINT_DECL_EXTRA_TOKENS : & [ Token < ' _ > ] = & [
462
521
// , @option = value
463
522
Comma , AnyComment , At , AnyIdent , Eq , Literal ,
464
523
] ;
524
+ #[ rustfmt:: skip]
525
+ static LINT_PASS_TOKENS : & [ Token < ' _ > ] = & [
526
+ // ( name <'lt> => [
527
+ OpenParen , AnyComment , CaptureIdent , OptLifetimeArgs , FatArrow , OpenBracket ,
528
+ ] ;
465
529
466
530
let mut searcher = RustSearcher :: new ( & self . source_map . files [ file] . contents ) ;
467
531
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 ;
471
535
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 {
483
596
file,
484
597
start,
485
598
end : searcher. pos ( ) ,
486
599
} ,
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
+ _ => { } ,
497
603
}
498
604
}
499
605
}
@@ -537,11 +643,11 @@ impl Parser {
537
643
let mut searcher = RustSearcher :: new ( & file_data. contents ) ;
538
644
// First instance is the macro definition.
539
645
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`" ,
542
648
) ;
543
649
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 [ ] ) {
545
651
self . errors . push ( searcher. get_unexpected_err ( file) ) ;
546
652
return ;
547
653
}
@@ -570,7 +676,7 @@ impl Parser {
570
676
return ;
571
677
}
572
678
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 [ ] ) {
574
680
self . errors . push ( searcher. get_unexpected_err ( file) ) ;
575
681
return ;
576
682
}
0 commit comments