1
- use crate :: utils:: { FileUpdater , UpdateMode , UpdateStatus , update_text_region_fn} ;
1
+ use crate :: utils:: { File , FileAction , FileUpdater , UpdateMode , UpdateStatus , panic_file, update_text_region_fn} ;
2
+ use core:: str;
2
3
use itertools:: Itertools ;
3
4
use rustc_lexer:: { LiteralKind , TokenKind , tokenize, unescape} ;
4
5
use std:: collections:: { HashMap , HashSet } ;
5
- use std:: ffi:: OsStr ;
6
6
use std:: fmt:: Write ;
7
- use std:: fs;
7
+ use std:: fs:: OpenOptions ;
8
8
use std:: ops:: Range ;
9
9
use std:: path:: Path ;
10
10
use walkdir:: { DirEntry , WalkDir } ;
@@ -25,8 +25,11 @@ const DOCS_LINK: &str = "https://rust-lang.github.io/rust-clippy/master/index.ht
25
25
///
26
26
/// Panics if a file path could not read from or then written to
27
27
pub fn update ( update_mode : UpdateMode ) {
28
- let ( lints, deprecated_lints, renamed_lints) = gather_all ( ) ;
29
- generate_lint_files ( update_mode, & lints, & deprecated_lints, & renamed_lints) ;
28
+ let lints = find_lint_decls ( ) ;
29
+ let DeprecatedLints {
30
+ renamed, deprecated, ..
31
+ } = read_deprecated_lints ( ) ;
32
+ generate_lint_files ( update_mode, & lints, & deprecated, & renamed) ;
30
33
}
31
34
32
35
pub fn generate_lint_files (
@@ -35,8 +38,6 @@ pub fn generate_lint_files(
35
38
deprecated : & [ DeprecatedLint ] ,
36
39
renamed : & [ RenamedLint ] ,
37
40
) {
38
- let mut lints = lints. to_owned ( ) ;
39
- lints. sort_by ( |lhs, rhs| lhs. name . cmp ( & rhs. name ) ) ;
40
41
FileUpdater :: default ( ) . update_files_checked (
41
42
"cargo dev lint" ,
42
43
update_mode,
@@ -106,7 +107,7 @@ pub fn generate_lint_files(
106
107
}
107
108
108
109
pub fn print_lints ( ) {
109
- let ( lints, _ , _ ) = gather_all ( ) ;
110
+ let lints = find_lint_decls ( ) ;
110
111
let lint_count = lints. len ( ) ;
111
112
let grouped_by_lint_group = Lint :: by_lint_group ( lints. into_iter ( ) ) ;
112
113
@@ -204,40 +205,54 @@ pub fn gen_renamed_lints_test_fn(lints: &[RenamedLint]) -> impl Fn(&Path, &str,
204
205
}
205
206
}
206
207
207
- /// Gathers all lints defined in `clippy_lints/src`
208
+ /// Finds all lint declarations (`declare_clippy_lint!`)
208
209
#[ must_use]
209
- pub fn gather_all ( ) -> ( Vec < Lint > , Vec < DeprecatedLint > , Vec < RenamedLint > ) {
210
+ pub fn find_lint_decls ( ) -> Vec < Lint > {
210
211
let mut lints = Vec :: with_capacity ( 1000 ) ;
211
- let mut deprecated_lints = Vec :: with_capacity ( 50 ) ;
212
- let mut renamed_lints = Vec :: with_capacity ( 50 ) ;
213
-
214
- for file in clippy_lints_src_files ( ) {
215
- let path = file. path ( ) ;
216
- let contents =
217
- fs:: read_to_string ( path) . unwrap_or_else ( |e| panic ! ( "Cannot read from `{}`: {e}" , path. display( ) ) ) ;
218
- let module = path. as_os_str ( ) . to_str ( ) . unwrap ( ) [ "clippy_lints/src/" . len ( ) ..] . replace ( [ '/' , '\\' ] , "::" ) ;
219
-
220
- // If the lints are stored in mod.rs, we get the module name from
221
- // the containing directory:
222
- let module = if let Some ( module) = module. strip_suffix ( "::mod.rs" ) {
223
- module
224
- } else {
225
- module. strip_suffix ( ".rs" ) . unwrap_or ( & module)
226
- } ;
227
-
228
- if module == "deprecated_lints" {
229
- parse_deprecated_contents ( & contents, & mut deprecated_lints, & mut renamed_lints) ;
230
- } else {
231
- parse_contents ( & contents, module, & mut lints) ;
232
- }
212
+ let mut contents = String :: new ( ) ;
213
+ for ( file, module) in read_src_with_module ( "clippy_lints/src" . as_ref ( ) ) {
214
+ parse_clippy_lint_decls (
215
+ File :: open_read_to_cleared_string ( file. path ( ) , & mut contents) ,
216
+ & module,
217
+ & mut lints,
218
+ ) ;
233
219
}
234
- ( lints, deprecated_lints, renamed_lints)
220
+ lints. sort_by ( |lhs, rhs| lhs. name . cmp ( & rhs. name ) ) ;
221
+ lints
235
222
}
236
223
237
- pub fn clippy_lints_src_files ( ) -> impl Iterator < Item = DirEntry > {
238
- let iter = WalkDir :: new ( "clippy_lints/src" ) . into_iter ( ) ;
239
- iter. map ( Result :: unwrap)
240
- . filter ( |f| f. path ( ) . extension ( ) == Some ( OsStr :: new ( "rs" ) ) )
224
+ /// Reads the source files from the given root directory
225
+ fn read_src_with_module ( src_root : & Path ) -> impl use < ' _ > + Iterator < Item = ( DirEntry , String ) > {
226
+ WalkDir :: new ( src_root) . into_iter ( ) . filter_map ( move |e| {
227
+ let e = match e {
228
+ Ok ( e) => e,
229
+ Err ( ref e) => panic_file ( e, FileAction :: Read , src_root) ,
230
+ } ;
231
+ let path = e. path ( ) . as_os_str ( ) . as_encoded_bytes ( ) ;
232
+ if let Some ( path) = path. strip_suffix ( b".rs" )
233
+ && let Some ( path) = path. get ( "clippy_lints/src/" . len ( ) ..)
234
+ {
235
+ if path == b"lib" {
236
+ Some ( ( e, String :: new ( ) ) )
237
+ } else {
238
+ let path = if let Some ( path) = path. strip_suffix ( b"mod" )
239
+ && let Some ( path) = path. strip_suffix ( b"/" ) . or_else ( || path. strip_suffix ( b"\\ " ) )
240
+ {
241
+ path
242
+ } else {
243
+ path
244
+ } ;
245
+ if let Ok ( path) = str:: from_utf8 ( path) {
246
+ let path = path. replace ( [ '/' , '\\' ] , "::" ) ;
247
+ Some ( ( e, path) )
248
+ } else {
249
+ None
250
+ }
251
+ }
252
+ } else {
253
+ None
254
+ }
255
+ } )
241
256
}
242
257
243
258
macro_rules! match_tokens {
@@ -265,7 +280,7 @@ pub(crate) struct LintDeclSearchResult<'a> {
265
280
}
266
281
267
282
/// Parse a source file looking for `declare_clippy_lint` macro invocations.
268
- fn parse_contents ( contents : & str , module : & str , lints : & mut Vec < Lint > ) {
283
+ fn parse_clippy_lint_decls ( contents : & str , module : & str , lints : & mut Vec < Lint > ) {
269
284
let mut offset = 0usize ;
270
285
let mut iter = tokenize ( contents) . map ( |t| {
271
286
let range = offset..offset + t. len as usize ;
@@ -332,15 +347,40 @@ fn parse_contents(contents: &str, module: &str, lints: &mut Vec<Lint>) {
332
347
}
333
348
}
334
349
335
- /// Parse a source file looking for `declare_deprecated_lint` macro invocations.
336
- fn parse_deprecated_contents ( contents : & str , deprecated : & mut Vec < DeprecatedLint > , renamed : & mut Vec < RenamedLint > ) {
337
- let Some ( ( _, contents) ) = contents. split_once ( "\n declare_with_version! { DEPRECATED" ) else {
338
- return ;
339
- } ;
340
- let Some ( ( deprecated_src, renamed_src) ) = contents. split_once ( "\n declare_with_version! { RENAMED" ) else {
341
- return ;
350
+ pub struct DeprecatedLints {
351
+ pub file : File < ' static > ,
352
+ pub contents : String ,
353
+ pub deprecated : Vec < DeprecatedLint > ,
354
+ pub renamed : Vec < RenamedLint > ,
355
+ pub deprecated_end : u32 ,
356
+ pub renamed_end : u32 ,
357
+ }
358
+
359
+ #[ must_use]
360
+ #[ expect( clippy:: cast_possible_truncation) ]
361
+ pub fn read_deprecated_lints ( ) -> DeprecatedLints {
362
+ let mut res = DeprecatedLints {
363
+ file : File :: open (
364
+ "clippy_lints/src/deprecated_lints.rs" ,
365
+ OpenOptions :: new ( ) . read ( true ) . write ( true ) ,
366
+ ) ,
367
+ contents : String :: new ( ) ,
368
+ deprecated : Vec :: with_capacity ( 30 ) ,
369
+ renamed : Vec :: with_capacity ( 80 ) ,
370
+ deprecated_end : 0 ,
371
+ renamed_end : 0 ,
342
372
} ;
343
373
374
+ res. file . read_append_to_string ( & mut res. contents ) ;
375
+
376
+ let ( _, contents) = res. contents . split_once ( "\n declare_with_version! { DEPRECATED" ) . unwrap ( ) ;
377
+ let ( deprecated_src, contents) = contents. split_once ( "\n ]}" ) . unwrap ( ) ;
378
+ res. deprecated_end = ( res. contents . len ( ) - contents. len ( ) - 2 ) as u32 ;
379
+
380
+ let ( _, contents) = contents. split_once ( "\n declare_with_version! { RENAMED" ) . unwrap ( ) ;
381
+ let ( renamed_src, contents) = contents. split_once ( "\n ]}" ) . unwrap ( ) ;
382
+ res. renamed_end = ( res. contents . len ( ) - contents. len ( ) - 2 ) as u32 ;
383
+
344
384
for line in deprecated_src. lines ( ) {
345
385
let mut offset = 0usize ;
346
386
let mut iter = tokenize ( line) . map ( |t| {
@@ -361,7 +401,7 @@ fn parse_deprecated_contents(contents: &str, deprecated: &mut Vec<DeprecatedLint
361
401
// "new_name"),
362
402
Whitespace Literal { kind: LiteralKind :: Str { ..} , ..} ( reason) CloseParen Comma
363
403
) ;
364
- deprecated. push ( DeprecatedLint :: new ( name, reason) ) ;
404
+ res . deprecated . push ( DeprecatedLint :: new ( name, reason) ) ;
365
405
}
366
406
for line in renamed_src. lines ( ) {
367
407
let mut offset = 0usize ;
@@ -383,8 +423,10 @@ fn parse_deprecated_contents(contents: &str, deprecated: &mut Vec<DeprecatedLint
383
423
// "new_name"),
384
424
Whitespace Literal { kind: LiteralKind :: Str { ..} , ..} ( new_name) CloseParen Comma
385
425
) ;
386
- renamed. push ( RenamedLint :: new ( old_name, new_name) ) ;
426
+ res . renamed . push ( RenamedLint :: new ( old_name, new_name) ) ;
387
427
}
428
+
429
+ res
388
430
}
389
431
390
432
/// Removes the line splices and surrounding quotes from a string literal
@@ -410,7 +452,7 @@ mod tests {
410
452
use super :: * ;
411
453
412
454
#[ test]
413
- fn test_parse_contents ( ) {
455
+ fn test_parse_clippy_lint_decls ( ) {
414
456
static CONTENTS : & str = r#"
415
457
declare_clippy_lint! {
416
458
#[clippy::version = "Hello Clippy!"]
@@ -428,7 +470,7 @@ mod tests {
428
470
}
429
471
"# ;
430
472
let mut result = Vec :: new ( ) ;
431
- parse_contents ( CONTENTS , "module_name" , & mut result) ;
473
+ parse_clippy_lint_decls ( CONTENTS , "module_name" , & mut result) ;
432
474
for r in & mut result {
433
475
r. declaration_range = Range :: default ( ) ;
434
476
}
0 commit comments