@@ -33,6 +33,7 @@ mod ok_expect;
3333mod option_as_ref_deref;
3434mod option_map_or_none;
3535mod option_map_unwrap_or;
36+ mod or_fun_call;
3637mod search_is_some;
3738mod single_char_insert_string;
3839mod single_char_pattern;
@@ -66,12 +67,11 @@ use rustc_span::source_map::Span;
6667use rustc_span:: symbol:: { sym, Symbol , SymbolStr } ;
6768use rustc_typeck:: hir_ty_to_ty;
6869
69- use crate :: utils:: eager_or_lazy:: is_lazyness_candidate;
7070use crate :: utils:: {
7171 contains_return, contains_ty, get_trait_def_id, implements_trait, in_macro, is_copy, is_expn_of,
72- is_type_diagnostic_item, iter_input_pats, last_path_segment , match_def_path, match_qpath, match_type , method_calls ,
73- method_chain_args , paths , return_ty, single_segment_path, snippet, snippet_with_applicability,
74- snippet_with_macro_callsite , span_lint , span_lint_and_help , span_lint_and_sugg, SpanlessEq ,
72+ is_type_diagnostic_item, iter_input_pats, match_def_path, match_qpath, method_calls , method_chain_args , paths ,
73+ return_ty, single_segment_path, snippet, snippet_with_applicability, span_lint , span_lint_and_help ,
74+ span_lint_and_sugg, SpanlessEq ,
7575} ;
7676
7777declare_clippy_lint ! {
@@ -1778,7 +1778,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
17781778 }
17791779 } ,
17801780 hir:: ExprKind :: MethodCall ( ref method_call, ref method_span, ref args, _) => {
1781- lint_or_fun_call ( cx, expr, * method_span, & method_call. ident . as_str ( ) , args) ;
1781+ or_fun_call :: check ( cx, expr, * method_span, & method_call. ident . as_str ( ) , args) ;
17821782 lint_expect_fun_call ( cx, expr, * method_span, & method_call. ident . as_str ( ) , args) ;
17831783
17841784 let self_ty = cx. typeck_results ( ) . expr_ty_adjusted ( & args[ 0 ] ) ;
@@ -1973,164 +1973,6 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
19731973 extract_msrv_attr ! ( LateContext ) ;
19741974}
19751975
1976- /// Checks for the `OR_FUN_CALL` lint.
1977- #[ allow( clippy:: too_many_lines) ]
1978- fn lint_or_fun_call < ' tcx > (
1979- cx : & LateContext < ' tcx > ,
1980- expr : & hir:: Expr < ' _ > ,
1981- method_span : Span ,
1982- name : & str ,
1983- args : & ' tcx [ hir:: Expr < ' _ > ] ,
1984- ) {
1985- /// Checks for `unwrap_or(T::new())` or `unwrap_or(T::default())`.
1986- fn check_unwrap_or_default (
1987- cx : & LateContext < ' _ > ,
1988- name : & str ,
1989- fun : & hir:: Expr < ' _ > ,
1990- self_expr : & hir:: Expr < ' _ > ,
1991- arg : & hir:: Expr < ' _ > ,
1992- or_has_args : bool ,
1993- span : Span ,
1994- ) -> bool {
1995- if_chain ! {
1996- if !or_has_args;
1997- if name == "unwrap_or" ;
1998- if let hir:: ExprKind :: Path ( ref qpath) = fun. kind;
1999- let path = & * last_path_segment( qpath) . ident. as_str( ) ;
2000- if [ "default" , "new" ] . contains( & path) ;
2001- let arg_ty = cx. typeck_results( ) . expr_ty( arg) ;
2002- if let Some ( default_trait_id) = get_trait_def_id( cx, & paths:: DEFAULT_TRAIT ) ;
2003- if implements_trait( cx, arg_ty, default_trait_id, & [ ] ) ;
2004-
2005- then {
2006- let mut applicability = Applicability :: MachineApplicable ;
2007- span_lint_and_sugg(
2008- cx,
2009- OR_FUN_CALL ,
2010- span,
2011- & format!( "use of `{}` followed by a call to `{}`" , name, path) ,
2012- "try this" ,
2013- format!(
2014- "{}.unwrap_or_default()" ,
2015- snippet_with_applicability( cx, self_expr. span, ".." , & mut applicability)
2016- ) ,
2017- applicability,
2018- ) ;
2019-
2020- true
2021- } else {
2022- false
2023- }
2024- }
2025- }
2026-
2027- /// Checks for `*or(foo())`.
2028- #[ allow( clippy:: too_many_arguments) ]
2029- fn check_general_case < ' tcx > (
2030- cx : & LateContext < ' tcx > ,
2031- name : & str ,
2032- method_span : Span ,
2033- self_expr : & hir:: Expr < ' _ > ,
2034- arg : & ' tcx hir:: Expr < ' _ > ,
2035- span : Span ,
2036- // None if lambda is required
2037- fun_span : Option < Span > ,
2038- ) {
2039- // (path, fn_has_argument, methods, suffix)
2040- static KNOW_TYPES : [ ( & [ & str ] , bool , & [ & str ] , & str ) ; 4 ] = [
2041- ( & paths:: BTREEMAP_ENTRY , false , & [ "or_insert" ] , "with" ) ,
2042- ( & paths:: HASHMAP_ENTRY , false , & [ "or_insert" ] , "with" ) ,
2043- ( & paths:: OPTION , false , & [ "map_or" , "ok_or" , "or" , "unwrap_or" ] , "else" ) ,
2044- ( & paths:: RESULT , true , & [ "or" , "unwrap_or" ] , "else" ) ,
2045- ] ;
2046-
2047- if let hir:: ExprKind :: MethodCall ( ref path, _, ref args, _) = & arg. kind {
2048- if path. ident . as_str ( ) == "len" {
2049- let ty = cx. typeck_results ( ) . expr_ty ( & args[ 0 ] ) . peel_refs ( ) ;
2050-
2051- match ty. kind ( ) {
2052- ty:: Slice ( _) | ty:: Array ( _, _) => return ,
2053- _ => ( ) ,
2054- }
2055-
2056- if is_type_diagnostic_item ( cx, ty, sym:: vec_type) {
2057- return ;
2058- }
2059- }
2060- }
2061-
2062- if_chain ! {
2063- if KNOW_TYPES . iter( ) . any( |k| k. 2 . contains( & name) ) ;
2064-
2065- if is_lazyness_candidate( cx, arg) ;
2066- if !contains_return( & arg) ;
2067-
2068- let self_ty = cx. typeck_results( ) . expr_ty( self_expr) ;
2069-
2070- if let Some ( & ( _, fn_has_arguments, poss, suffix) ) =
2071- KNOW_TYPES . iter( ) . find( |&&i| match_type( cx, self_ty, i. 0 ) ) ;
2072-
2073- if poss. contains( & name) ;
2074-
2075- then {
2076- let macro_expanded_snipped;
2077- let sugg: Cow <' _, str > = {
2078- let ( snippet_span, use_lambda) = match ( fn_has_arguments, fun_span) {
2079- ( false , Some ( fun_span) ) => ( fun_span, false ) ,
2080- _ => ( arg. span, true ) ,
2081- } ;
2082- let snippet = {
2083- let not_macro_argument_snippet = snippet_with_macro_callsite( cx, snippet_span, ".." ) ;
2084- if not_macro_argument_snippet == "vec![]" {
2085- macro_expanded_snipped = snippet( cx, snippet_span, ".." ) ;
2086- match macro_expanded_snipped. strip_prefix( "$crate::vec::" ) {
2087- Some ( stripped) => Cow :: from( stripped) ,
2088- None => macro_expanded_snipped
2089- }
2090- }
2091- else {
2092- not_macro_argument_snippet
2093- }
2094- } ;
2095-
2096- if use_lambda {
2097- let l_arg = if fn_has_arguments { "_" } else { "" } ;
2098- format!( "|{}| {}" , l_arg, snippet) . into( )
2099- } else {
2100- snippet
2101- }
2102- } ;
2103- let span_replace_word = method_span. with_hi( span. hi( ) ) ;
2104- span_lint_and_sugg(
2105- cx,
2106- OR_FUN_CALL ,
2107- span_replace_word,
2108- & format!( "use of `{}` followed by a function call" , name) ,
2109- "try this" ,
2110- format!( "{}_{}({})" , name, suffix, sugg) ,
2111- Applicability :: HasPlaceholders ,
2112- ) ;
2113- }
2114- }
2115- }
2116-
2117- if args. len ( ) == 2 {
2118- match args[ 1 ] . kind {
2119- hir:: ExprKind :: Call ( ref fun, ref or_args) => {
2120- let or_has_args = !or_args. is_empty ( ) ;
2121- if !check_unwrap_or_default ( cx, name, fun, & args[ 0 ] , & args[ 1 ] , or_has_args, expr. span ) {
2122- let fun_span = if or_has_args { None } else { Some ( fun. span ) } ;
2123- check_general_case ( cx, name, method_span, & args[ 0 ] , & args[ 1 ] , expr. span , fun_span) ;
2124- }
2125- } ,
2126- hir:: ExprKind :: Index ( ..) | hir:: ExprKind :: MethodCall ( ..) => {
2127- check_general_case ( cx, name, method_span, & args[ 0 ] , & args[ 1 ] , expr. span , None ) ;
2128- } ,
2129- _ => { } ,
2130- }
2131- }
2132- }
2133-
21341976/// Checks for the `EXPECT_FUN_CALL` lint.
21351977#[ allow( clippy:: too_many_lines) ]
21361978fn lint_expect_fun_call (
0 commit comments