1+ use std:: iter:: once;
2+
13use clippy_utils:: diagnostics:: span_lint_and_sugg;
24use clippy_utils:: source:: snippet;
35use clippy_utils:: { get_expr_use_or_unification_node, is_res_lang_ctor, path_res, std_or_core} ;
46
57use rustc_errors:: Applicability ;
8+ use rustc_hir:: def_id:: DefId ;
9+ use rustc_hir:: hir_id:: HirId ;
610use rustc_hir:: LangItem :: { OptionNone , OptionSome } ;
711use rustc_hir:: { Expr , ExprKind , Node } ;
812use rustc_lint:: LateContext ;
@@ -25,7 +29,29 @@ impl IterType {
2529 }
2630}
2731
28- pub ( super ) fn check ( cx : & LateContext < ' _ > , expr : & Expr < ' _ > , method_name : & str , recv : & Expr < ' _ > ) {
32+ fn is_arg_ty_unified_in_fn < ' tcx > (
33+ cx : & LateContext < ' tcx > ,
34+ fn_id : DefId ,
35+ arg_id : HirId ,
36+ args : impl IntoIterator < Item = & ' tcx Expr < ' tcx > > ,
37+ ) -> bool {
38+ let fn_sig = cx. tcx . fn_sig ( fn_id) . instantiate_identity ( ) ;
39+ let arg_id_in_args = args. into_iter ( ) . position ( |e| e. hir_id == arg_id) . unwrap ( ) ;
40+ let arg_ty_in_args = fn_sig. input ( arg_id_in_args) . skip_binder ( ) ;
41+
42+ cx. tcx . predicates_of ( fn_id) . predicates . iter ( ) . any ( |( clause, _) | {
43+ clause
44+ . as_projection_clause ( )
45+ . and_then ( |p| p. map_bound ( |p| p. term . ty ( ) ) . transpose ( ) )
46+ . is_some_and ( |ty| ty. skip_binder ( ) == arg_ty_in_args)
47+ } ) || fn_sig
48+ . inputs ( )
49+ . iter ( )
50+ . enumerate ( )
51+ . any ( |( i, ty) | i != arg_id_in_args && ty. skip_binder ( ) . walk ( ) . any ( |arg| arg. as_type ( ) == Some ( arg_ty_in_args) ) )
52+ }
53+
54+ pub ( super ) fn check < ' tcx > ( cx : & LateContext < ' tcx > , expr : & ' tcx Expr < ' tcx > , method_name : & str , recv : & ' tcx Expr < ' tcx > ) {
2955 let item = match recv. kind {
3056 ExprKind :: Array ( [ ] ) => None ,
3157 ExprKind :: Array ( [ e] ) => Some ( e) ,
@@ -43,6 +69,25 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, method_name: &str, re
4369 let is_unified = match get_expr_use_or_unification_node ( cx. tcx , expr) {
4470 Some ( ( Node :: Expr ( parent) , child_id) ) => match parent. kind {
4571 ExprKind :: If ( e, _, _) | ExprKind :: Match ( e, _, _) if e. hir_id == child_id => false ,
72+ ExprKind :: Call (
73+ Expr {
74+ kind : ExprKind :: Path ( path) ,
75+ hir_id,
76+ ..
77+ } ,
78+ args,
79+ ) => cx
80+ . typeck_results ( )
81+ . qpath_res ( path, * hir_id)
82+ . opt_def_id ( )
83+ . filter ( |fn_id| cx. tcx . def_kind ( fn_id) . is_fn_like ( ) )
84+ . is_some_and ( |fn_id| is_arg_ty_unified_in_fn ( cx, fn_id, child_id, args) ) ,
85+ ExprKind :: MethodCall ( _name, recv, args, _span) => is_arg_ty_unified_in_fn (
86+ cx,
87+ cx. typeck_results ( ) . type_dependent_def_id ( parent. hir_id ) . unwrap ( ) ,
88+ child_id,
89+ once ( recv) . chain ( args. iter ( ) ) ,
90+ ) ,
4691 ExprKind :: If ( _, _, _)
4792 | ExprKind :: Match ( _, _, _)
4893 | ExprKind :: Closure ( _)
0 commit comments