14
14
//! - [ ] TODO The Applicability for each lint for [#4310](https://github.com/rust-lang/rust-clippy/issues/4310)
15
15
16
16
// # Applicability
17
- // - TODO xFrednet 2021-01-17: Find all methods that take and modify applicability or predefine
18
- // them?
19
17
// - TODO xFrednet 2021-01-17: Find lint emit and collect applicability
18
+ // - TODO xFrednet 2021-02-27: Link applicability from function parameters
19
+ // - (Examples: suspicious_operation_groupings:267, needless_bool.rs:311)
20
+ // - TODO xFrednet 2021-02-27: Tuple if let thingy
21
+ // - (Examples: unused_unit.rs:140, misc.rs:694)
20
22
// # NITs
21
23
// - TODO xFrednet 2021-02-13: Collect depreciations and maybe renames
22
24
23
25
use if_chain:: if_chain;
24
26
use rustc_data_structures:: fx:: FxHashMap ;
25
- use rustc_hir:: { self as hir, ExprKind , Item , ItemKind , Mutability } ;
27
+ use rustc_hir:: { self as hir, intravisit , ExprKind , Item , ItemKind , Mutability } ;
26
28
use rustc_lint:: { CheckLintNameResult , LateContext , LateLintPass , LintContext , LintId } ;
29
+ use rustc_middle:: hir:: map:: Map ;
27
30
use rustc_session:: { declare_tool_lint, impl_lint_pass} ;
28
31
use rustc_span:: { sym, Loc , Span , Symbol } ;
29
32
use serde:: Serialize ;
@@ -33,13 +36,15 @@ use std::path::Path;
33
36
34
37
use crate :: utils:: internal_lints:: is_lint_ref_type;
35
38
use crate :: utils:: {
36
- last_path_segment, match_function_call, match_type, paths, span_lint, walk_ptrs_ty_depth, match_path ,
39
+ last_path_segment, match_function_call, match_path , match_type, paths, span_lint, walk_ptrs_ty_depth,
37
40
} ;
38
41
39
42
/// This is the output file of the lint collector.
40
43
const OUTPUT_FILE : & str = "metadata_collection.json" ;
41
44
/// These lints are excluded from the export.
42
45
const BLACK_LISTED_LINTS : [ & str ; 2 ] = [ "lint_author" , "deep_code_inspection" ] ;
46
+ /// These groups will be ignored by the lint group matcher
47
+ const BLACK_LISTED_LINT_GROUP : [ & str ; 1 ] = [ "clippy::all" ] ;
43
48
44
49
// TODO xFrednet 2021-02-15: `span_lint_and_then` & `span_lint_hir_and_then` requires special
45
50
// handling
@@ -52,6 +57,9 @@ const LINT_EMISSION_FUNCTIONS: [&[&str]; 5] = [
52
57
& [ "clippy_utils" , "diagnostics" , "span_lint_and_sugg" ] ,
53
58
] ;
54
59
60
+ /// The index of the applicability name of `paths::APPLICABILITY_VALUES`
61
+ const APPLICABILITY_NAME_INDEX : usize = 2 ;
62
+
55
63
declare_clippy_lint ! {
56
64
/// **What it does:** Collects metadata about clippy lints for the website.
57
65
///
@@ -297,6 +305,10 @@ fn get_lint_group_or_lint(cx: &LateContext<'_>, lint_name: &str, item: &'hir Ite
297
305
298
306
fn get_lint_group ( cx : & LateContext < ' _ > , lint_id : LintId ) -> Option < String > {
299
307
for ( group_name, lints, _) in & cx. lint_store . get_lint_groups ( ) {
308
+ if BLACK_LISTED_LINT_GROUP . contains ( group_name) {
309
+ continue ;
310
+ }
311
+
300
312
if lints. iter ( ) . any ( |x| * x == lint_id) {
301
313
return Some ( ( * group_name) . to_string ( ) ) ;
302
314
}
@@ -341,7 +353,10 @@ fn match_simple_lint_emission<'hir>(
341
353
}
342
354
343
355
/// This returns the lint name and the possible applicability of this emission
344
- fn extract_emission_info < ' hir > ( cx : & LateContext < ' hir > , args : & [ hir:: Expr < ' _ > ] ) -> Option < ( String , Option < String > ) > {
356
+ fn extract_emission_info < ' hir > (
357
+ cx : & LateContext < ' hir > ,
358
+ args : & ' hir [ hir:: Expr < ' hir > ] ,
359
+ ) -> Option < ( String , Option < String > ) > {
345
360
let mut lint_name = None ;
346
361
let mut applicability = None ;
347
362
@@ -358,41 +373,38 @@ fn extract_emission_info<'hir>(cx: &LateContext<'hir>, args: &[hir::Expr<'_>]) -
358
373
}
359
374
}
360
375
361
- lint_name. map ( |lint_name| {
362
- (
363
- sym_to_string ( lint_name) . to_ascii_lowercase ( ) ,
364
- applicability,
365
- )
366
- } )
376
+ lint_name. map ( |lint_name| ( sym_to_string ( lint_name) . to_ascii_lowercase ( ) , applicability) )
367
377
}
368
378
369
- fn resolve_applicability ( cx : & LateContext < ' hir > , expr : & hir:: Expr < ' _ > ) -> Option < String > {
379
+ /// This function tries to resolve the linked applicability to the given expression.
380
+ fn resolve_applicability ( cx : & LateContext < ' hir > , expr : & ' hir hir:: Expr < ' hir > ) -> Option < String > {
370
381
match expr. kind {
371
382
// We can ignore ifs without an else block because those can't be used as an assignment
372
- hir:: ExprKind :: If ( _con, _if_block, Some ( _else_block) ) => {
373
- // self.process_assign_expr(if_block);
374
- // self.process_assign_expr(else_block);
375
- return Some ( "TODO IF EXPR" . to_string ( ) ) ;
383
+ hir:: ExprKind :: If ( _con, if_block, Some ( else_block) ) => {
384
+ let mut visitor = ApplicabilityVisitor :: new ( cx) ;
385
+ intravisit:: walk_expr ( & mut visitor, if_block) ;
386
+ intravisit:: walk_expr ( & mut visitor, else_block) ;
387
+ visitor. complete ( )
376
388
} ,
377
- hir:: ExprKind :: Match ( _expr, _arms , _) => {
378
- // for arm in *arms {
379
- // self.process_assign_expr(arm.body);
380
- // }
381
- return Some ( "TODO MATCH EXPR" . to_string ( ) ) ;
389
+ hir:: ExprKind :: Match ( _expr, arms , _) => {
390
+ let mut visitor = ApplicabilityVisitor :: new ( cx ) ;
391
+ arms . iter ( )
392
+ . for_each ( |arm| intravisit :: walk_expr ( & mut visitor , arm . body ) ) ;
393
+ visitor . complete ( )
382
394
} ,
383
395
hir:: ExprKind :: Loop ( block, ..) | hir:: ExprKind :: Block ( block, ..) => {
384
- if let Some ( block_expr ) = block . expr {
385
- return resolve_applicability ( cx , block_expr ) ;
386
- }
396
+ let mut visitor = ApplicabilityVisitor :: new ( cx ) ;
397
+ intravisit :: walk_block ( & mut visitor , block ) ;
398
+ visitor . complete ( )
387
399
} ,
388
400
ExprKind :: Path ( hir:: QPath :: Resolved ( _, path) ) => {
389
401
// direct applicabilities are simple:
390
402
for enum_value in & paths:: APPLICABILITY_VALUES {
391
403
if match_path ( path, enum_value) {
392
- return Some ( enum_value[ 2 ] . to_string ( ) ) ;
404
+ return Some ( enum_value[ APPLICABILITY_NAME_INDEX ] . to_string ( ) ) ;
393
405
}
394
406
}
395
-
407
+
396
408
// Values yay
397
409
if let hir:: def:: Res :: Local ( local_hir) = path. res {
398
410
if let Some ( local) = get_parent_local ( cx, local_hir) {
@@ -401,19 +413,67 @@ fn resolve_applicability(cx: &LateContext<'hir>, expr: &hir::Expr<'_>) -> Option
401
413
}
402
414
}
403
415
}
416
+
417
+ // This is true for paths that are linked to function parameters. They might be a bit more work so
418
+ // not today :)
419
+ None
420
+ } ,
421
+ _ => None ,
422
+ }
423
+ }
424
+
425
+ fn get_parent_local ( cx : & LateContext < ' hir > , hir_id : hir:: HirId ) -> Option < & ' hir hir:: Local < ' hir > > {
426
+ let map = cx. tcx . hir ( ) ;
427
+
428
+ match map. find ( map. get_parent_node ( hir_id) ) {
429
+ Some ( hir:: Node :: Local ( local) ) => Some ( local) ,
430
+ Some ( hir:: Node :: Pat ( pattern) ) => get_parent_local ( cx, pattern. hir_id ) ,
431
+ _ => None ,
432
+ }
433
+ }
434
+
435
+ /// This visitor finds the highest applicability value in the visited expressions
436
+ struct ApplicabilityVisitor < ' a , ' hir > {
437
+ cx : & ' a LateContext < ' hir > ,
438
+ /// This is the index of hightest `Applicability` for
439
+ /// `clippy_utils::paths::APPLICABILITY_VALUES`
440
+ applicability_index : Option < usize > ,
441
+ }
442
+
443
+ impl < ' a , ' hir > ApplicabilityVisitor < ' a , ' hir > {
444
+ fn new ( cx : & ' a LateContext < ' hir > ) -> Self {
445
+ Self {
446
+ cx,
447
+ applicability_index : None ,
404
448
}
405
- _ => { }
406
449
}
407
450
451
+ fn add_new_index ( & mut self , new_index : usize ) {
452
+ self . applicability_index = self
453
+ . applicability_index
454
+ . map_or ( new_index, |old_index| old_index. min ( new_index) )
455
+ . into ( ) ;
456
+ }
408
457
409
- Some ( "TODO" . to_string ( ) )
458
+ fn complete ( self ) -> Option < String > {
459
+ self . applicability_index
460
+ . map ( |index| paths:: APPLICABILITY_VALUES [ index] [ APPLICABILITY_NAME_INDEX ] . to_string ( ) )
461
+ }
410
462
}
411
463
412
- fn get_parent_local ( cx : & LateContext < ' hir > , hir_id : hir:: HirId ) -> Option < & ' hir hir:: Local < ' hir > > {
413
- let map = cx. tcx . hir ( ) ;
414
- if let Some ( hir:: Node :: Local ( local) ) = map. find ( map. get_parent_node ( hir_id) ) {
415
- return Some ( local) ;
464
+ impl < ' a , ' hir > intravisit:: Visitor < ' hir > for ApplicabilityVisitor < ' a , ' hir > {
465
+ type Map = Map < ' hir > ;
466
+
467
+ fn nested_visit_map ( & mut self ) -> intravisit:: NestedVisitorMap < Self :: Map > {
468
+ intravisit:: NestedVisitorMap :: All ( self . cx . tcx . hir ( ) )
416
469
}
417
470
418
- None
471
+ fn visit_path ( & mut self , path : & hir:: Path < ' _ > , _id : hir:: HirId ) {
472
+ for ( index, enum_value) in paths:: APPLICABILITY_VALUES . iter ( ) . enumerate ( ) {
473
+ if match_path ( path, enum_value) {
474
+ self . add_new_index ( index) ;
475
+ break ;
476
+ }
477
+ }
478
+ }
419
479
}
0 commit comments