1515
1616// # Applicability
1717// - 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
2018// - TODO xFrednet 2021-02-28: 4x weird emission forwarding
2119// - See clippy_lints/src/enum_variants.rs@EnumVariantNames::check_name
2220// - TODO xFrednet 2021-02-28: 6x emission forwarding with local that is initializes from
2624// - See clippy_lints/src/misc.rs@check_binary
2725// - TODO xFrednet 2021-02-28: 2x lint from local from method call
2826// - 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
3127// # NITs
3228// - TODO xFrednet 2021-02-13: Collect depreciations and maybe renames
3329
3430use if_chain:: if_chain;
3531use 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 } ;
3733use rustc_lint:: { CheckLintNameResult , LateContext , LateLintPass , LintContext , LintId } ;
3834use rustc_middle:: hir:: map:: Map ;
3935use rustc_session:: { declare_tool_lint, impl_lint_pass} ;
@@ -49,7 +45,7 @@ use crate::utils::{
4945} ;
5046
5147/// 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" ;
5349/// These lints are excluded from the export.
5450const BLACK_LISTED_LINTS : [ & str ; 2 ] = [ "lint_author" , "deep_code_inspection" ] ;
5551/// 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 {
270266 /// ```
271267 fn check_expr ( & mut self , cx : & LateContext < ' hir > , expr : & ' hir hir:: Expr < ' _ > ) {
272268 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 ( ..) {
274276 let app_info = self . applicability_into . entry ( lint_name) . or_default ( ) ;
275277 app_info. applicability = applicability;
276278 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" ) ;
279279 }
280280 }
281281 }
@@ -380,8 +380,8 @@ fn match_lint_emission<'hir>(cx: &LateContext<'hir>, expr: &'hir hir::Expr<'_>)
380380fn extract_complex_emission_info < ' hir > (
381381 cx : & LateContext < ' hir > ,
382382 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 ( ) ;
385385 let mut applicability = None ;
386386 let mut multi_part = false ;
387387
@@ -390,9 +390,8 @@ fn extract_complex_emission_info<'hir>(
390390
391391 if match_type ( cx, arg_ty, & paths:: LINT ) {
392392 // 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) ;
396395 } else if match_type ( cx, arg_ty, & paths:: APPLICABILITY ) {
397396 applicability = resolve_applicability ( cx, arg) ;
398397 } else if arg_ty. is_closure ( ) {
@@ -402,7 +401,14 @@ fn extract_complex_emission_info<'hir>(
402401 }
403402 }
404403
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
406412}
407413
408414/// 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
426432 false
427433}
428434
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+
429479/// This visitor finds the highest applicability value in the visited expressions
430480struct ApplicabilityResolver < ' a , ' hir > {
431481 cx : & ' a LateContext < ' hir > ,
@@ -488,7 +538,7 @@ impl<'a, 'hir> intravisit::Visitor<'hir> for ApplicabilityResolver<'a, 'hir> {
488538 }
489539}
490540
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
492542fn get_parent_local ( cx : & LateContext < ' hir > , expr : & ' hir hir:: Expr < ' hir > ) -> Option < & ' hir hir:: Local < ' hir > > {
493543 if let ExprKind :: Path ( QPath :: Resolved ( _, path) ) = expr. kind {
494544 if let hir:: def:: Res :: Local ( local_hir) = path. res {
0 commit comments