1414//! - [ ] TODO The Applicability for each lint for [#4310](https://github.com/rust-lang/rust-clippy/issues/4310)
1515
1616// # Applicability
17- // - TODO xFrednet 2021-01-17: Find all methods that take and modify applicability or predefine
18- // them?
1917// - 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)
2022// # NITs
2123// - TODO xFrednet 2021-02-13: Collect depreciations and maybe renames
2224
2325use if_chain:: if_chain;
2426use 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 } ;
2628use rustc_lint:: { CheckLintNameResult , LateContext , LateLintPass , LintContext , LintId } ;
29+ use rustc_middle:: hir:: map:: Map ;
2730use rustc_session:: { declare_tool_lint, impl_lint_pass} ;
2831use rustc_span:: { sym, Loc , Span , Symbol } ;
2932use serde:: Serialize ;
@@ -33,13 +36,15 @@ use std::path::Path;
3336
3437use crate :: utils:: internal_lints:: is_lint_ref_type;
3538use 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,
3740} ;
3841
3942/// This is the output file of the lint collector.
4043const OUTPUT_FILE : & str = "metadata_collection.json" ;
4144/// These lints are excluded from the export.
4245const 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" ] ;
4348
4449// TODO xFrednet 2021-02-15: `span_lint_and_then` & `span_lint_hir_and_then` requires special
4550// handling
@@ -52,6 +57,9 @@ const LINT_EMISSION_FUNCTIONS: [&[&str]; 5] = [
5257 & [ "clippy_utils" , "diagnostics" , "span_lint_and_sugg" ] ,
5358] ;
5459
60+ /// The index of the applicability name of `paths::APPLICABILITY_VALUES`
61+ const APPLICABILITY_NAME_INDEX : usize = 2 ;
62+
5563declare_clippy_lint ! {
5664 /// **What it does:** Collects metadata about clippy lints for the website.
5765 ///
@@ -297,6 +305,10 @@ fn get_lint_group_or_lint(cx: &LateContext<'_>, lint_name: &str, item: &'hir Ite
297305
298306fn get_lint_group ( cx : & LateContext < ' _ > , lint_id : LintId ) -> Option < String > {
299307 for ( group_name, lints, _) in & cx. lint_store . get_lint_groups ( ) {
308+ if BLACK_LISTED_LINT_GROUP . contains ( group_name) {
309+ continue ;
310+ }
311+
300312 if lints. iter ( ) . any ( |x| * x == lint_id) {
301313 return Some ( ( * group_name) . to_string ( ) ) ;
302314 }
@@ -341,7 +353,10 @@ fn match_simple_lint_emission<'hir>(
341353}
342354
343355/// 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 > ) > {
345360 let mut lint_name = None ;
346361 let mut applicability = None ;
347362
@@ -358,41 +373,38 @@ fn extract_emission_info<'hir>(cx: &LateContext<'hir>, args: &[hir::Expr<'_>]) -
358373 }
359374 }
360375
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) )
367377}
368378
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 > {
370381 match expr. kind {
371382 // 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 ( )
376388 } ,
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 ( )
382394 } ,
383395 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 ( )
387399 } ,
388400 ExprKind :: Path ( hir:: QPath :: Resolved ( _, path) ) => {
389401 // direct applicabilities are simple:
390402 for enum_value in & paths:: APPLICABILITY_VALUES {
391403 if match_path ( path, enum_value) {
392- return Some ( enum_value[ 2 ] . to_string ( ) ) ;
404+ return Some ( enum_value[ APPLICABILITY_NAME_INDEX ] . to_string ( ) ) ;
393405 }
394406 }
395-
407+
396408 // Values yay
397409 if let hir:: def:: Res :: Local ( local_hir) = path. res {
398410 if let Some ( local) = get_parent_local ( cx, local_hir) {
@@ -401,19 +413,67 @@ fn resolve_applicability(cx: &LateContext<'hir>, expr: &hir::Expr<'_>) -> Option
401413 }
402414 }
403415 }
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 ,
404448 }
405- _ => { }
406449 }
407450
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+ }
408457
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+ }
410462}
411463
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 ( ) )
416469 }
417470
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+ }
419479}
0 commit comments