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