15
15
16
16
// # Applicability
17
17
// - TODO xFrednet 2021-01-17: Find lint emit and collect applicability
18
- // - TODO xFrednet 2021-02-28: 1x reference to closure
19
- // - See clippy_lints/src/needless_pass_by_value.rs@NeedlessPassByValue::check_fn
20
18
// - TODO xFrednet 2021-02-28: 4x weird emission forwarding
21
19
// - See clippy_lints/src/enum_variants.rs@EnumVariantNames::check_name
22
20
// - TODO xFrednet 2021-02-28: 6x emission forwarding with local that is initializes from
26
24
// - See clippy_lints/src/misc.rs@check_binary
27
25
// - TODO xFrednet 2021-02-28: 2x lint from local from method call
28
26
// - See clippy_lints/src/non_copy_const.rs@lint
29
- // - TODO xFrednet 2021-02-28: 20x lint from local
30
- // - See clippy_lints/src/map_unit_fn.rs@lint_map_unit_fn
31
27
// # NITs
32
28
// - TODO xFrednet 2021-02-13: Collect depreciations and maybe renames
33
29
34
30
use if_chain:: if_chain;
35
31
use rustc_data_structures:: fx:: FxHashMap ;
36
- use rustc_hir:: { self as hir, intravisit, intravisit:: Visitor , ExprKind , Item , ItemKind , Mutability , QPath } ;
32
+ use rustc_hir:: { self as hir, intravisit, intravisit:: Visitor , ExprKind , Item , ItemKind , Mutability , QPath , def :: DefKind } ;
37
33
use rustc_lint:: { CheckLintNameResult , LateContext , LateLintPass , LintContext , LintId } ;
38
34
use rustc_middle:: hir:: map:: Map ;
39
35
use rustc_session:: { declare_tool_lint, impl_lint_pass} ;
@@ -49,7 +45,7 @@ use crate::utils::{
49
45
} ;
50
46
51
47
/// This is the output file of the lint collector.
52
- const OUTPUT_FILE : & str = "metadata_collection.json" ;
48
+ const OUTPUT_FILE : & str = "../ metadata_collection.json" ;
53
49
/// These lints are excluded from the export.
54
50
const BLACK_LISTED_LINTS : [ & str ; 2 ] = [ "lint_author" , "deep_code_inspection" ] ;
55
51
/// These groups will be ignored by the lint group matcher. This is useful for collections like
@@ -270,12 +266,16 @@ impl<'hir> LateLintPass<'hir> for MetadataCollector {
270
266
/// ```
271
267
fn check_expr ( & mut self , cx : & LateContext < ' hir > , expr : & ' hir hir:: Expr < ' _ > ) {
272
268
if let Some ( args) = match_lint_emission ( cx, expr) {
273
- if let Some ( ( lint_name, applicability, is_multi_part) ) = extract_complex_emission_info ( cx, args) {
269
+ let mut emission_info = extract_complex_emission_info ( cx, args) ;
270
+ if emission_info. is_empty ( ) {
271
+ lint_collection_error_span ( cx, expr. span , "Look, here ... I have no clue what todo with it" ) ;
272
+ return ;
273
+ }
274
+
275
+ for ( lint_name, applicability, is_multi_part) in emission_info. drain ( ..) {
274
276
let app_info = self . applicability_into . entry ( lint_name) . or_default ( ) ;
275
277
app_info. applicability = applicability;
276
278
app_info. is_multi_suggestion = is_multi_part;
277
- } else {
278
- lint_collection_error_span ( cx, expr. span , "Look, here ... I have no clue what todo with it" ) ;
279
279
}
280
280
}
281
281
}
@@ -380,8 +380,8 @@ fn match_lint_emission<'hir>(cx: &LateContext<'hir>, expr: &'hir hir::Expr<'_>)
380
380
fn extract_complex_emission_info < ' hir > (
381
381
cx : & LateContext < ' hir > ,
382
382
args : & ' hir [ hir:: Expr < ' hir > ] ,
383
- ) -> Option < ( String , Option < String > , bool ) > {
384
- let mut lint_name = None ;
383
+ ) -> Vec < ( String , Option < String > , bool ) > {
384
+ let mut lints= Vec :: new ( ) ;
385
385
let mut applicability = None ;
386
386
let mut multi_part = false ;
387
387
@@ -390,9 +390,8 @@ fn extract_complex_emission_info<'hir>(
390
390
391
391
if match_type ( cx, arg_ty, & paths:: LINT ) {
392
392
// If we found the lint arg, extract the lint name
393
- if let ExprKind :: Path ( ref lint_path) = arg. kind {
394
- lint_name = Some ( last_path_segment ( lint_path) . ident . name ) ;
395
- }
393
+ let mut resolved_lints = resolve_lints ( cx, arg) ;
394
+ lints. append ( & mut resolved_lints) ;
396
395
} else if match_type ( cx, arg_ty, & paths:: APPLICABILITY ) {
397
396
applicability = resolve_applicability ( cx, arg) ;
398
397
} else if arg_ty. is_closure ( ) {
@@ -402,7 +401,14 @@ fn extract_complex_emission_info<'hir>(
402
401
}
403
402
}
404
403
405
- lint_name. map ( |lint_name| ( sym_to_string ( lint_name) . to_ascii_lowercase ( ) , applicability, multi_part) )
404
+ lints. drain ( ..) . map ( |lint_name| ( lint_name, applicability. clone ( ) , multi_part) ) . collect ( )
405
+ }
406
+
407
+ /// Resolves the possible lints that this expression could reference
408
+ fn resolve_lints ( cx : & LateContext < ' hir > , expr : & ' hir hir:: Expr < ' hir > ) -> Vec < String > {
409
+ let mut resolver = LintResolver :: new ( cx) ;
410
+ resolver. visit_expr ( expr) ;
411
+ resolver. lints
406
412
}
407
413
408
414
/// This function tries to resolve the linked applicability to the given expression.
@@ -426,6 +432,50 @@ fn check_is_multi_part(cx: &LateContext<'hir>, closure_expr: &'hir hir::Expr<'hi
426
432
false
427
433
}
428
434
435
+ struct LintResolver < ' a , ' hir > {
436
+ cx : & ' a LateContext < ' hir > ,
437
+ lints : Vec < String > ,
438
+ }
439
+
440
+ impl < ' a , ' hir > LintResolver < ' a , ' hir > {
441
+ fn new ( cx : & ' a LateContext < ' hir > ) -> Self {
442
+ Self {
443
+ cx,
444
+ lints : Vec :: < String > :: default ( ) ,
445
+ }
446
+ }
447
+ }
448
+
449
+ impl < ' a , ' hir > intravisit:: Visitor < ' hir > for LintResolver < ' a , ' hir > {
450
+ type Map = Map < ' hir > ;
451
+
452
+ fn nested_visit_map ( & mut self ) -> intravisit:: NestedVisitorMap < Self :: Map > {
453
+ intravisit:: NestedVisitorMap :: All ( self . cx . tcx . hir ( ) )
454
+ }
455
+
456
+ fn visit_expr ( & mut self , expr : & ' hir hir:: Expr < ' hir > ) {
457
+ if_chain ! {
458
+ if let ExprKind :: Path ( qpath) = & expr. kind;
459
+ if let QPath :: Resolved ( _, path) = qpath;
460
+
461
+ let ( expr_ty, _) = walk_ptrs_ty_depth( self . cx. typeck_results( ) . expr_ty( & expr) ) ;
462
+ if match_type( self . cx, expr_ty, & paths:: LINT ) ;
463
+ then {
464
+ if let hir:: def:: Res :: Def ( DefKind :: Static , _) = path. res {
465
+ let lint_name = last_path_segment( qpath) . ident. name;
466
+ self . lints. push( sym_to_string( lint_name) . to_ascii_lowercase( ) ) ;
467
+ } else if let Some ( local) = get_parent_local( self . cx, expr) {
468
+ if let Some ( local_init) = local. init {
469
+ intravisit:: walk_expr( self , local_init) ;
470
+ }
471
+ }
472
+ }
473
+ }
474
+
475
+ intravisit:: walk_expr ( self , expr) ;
476
+ }
477
+ }
478
+
429
479
/// This visitor finds the highest applicability value in the visited expressions
430
480
struct ApplicabilityResolver < ' a , ' hir > {
431
481
cx : & ' a LateContext < ' hir > ,
@@ -488,7 +538,7 @@ impl<'a, 'hir> intravisit::Visitor<'hir> for ApplicabilityResolver<'a, 'hir> {
488
538
}
489
539
}
490
540
491
- /// This returns the parent local node if the expression is a reference to
541
+ /// This returns the parent local node if the expression is a reference one
492
542
fn get_parent_local ( cx : & LateContext < ' hir > , expr : & ' hir hir:: Expr < ' hir > ) -> Option < & ' hir hir:: Local < ' hir > > {
493
543
if let ExprKind :: Path ( QPath :: Resolved ( _, path) ) = expr. kind {
494
544
if let hir:: def:: Res :: Local ( local_hir) = path. res {
0 commit comments