@@ -4,10 +4,14 @@ use clippy_utils::{expr_or_init, is_path_diagnostic_item, path_res};
44use rustc_errors:: Applicability ;
55use rustc_hir:: def:: { CtorKind , DefKind , Res } ;
66use rustc_hir:: { Expr , ExprKind , QPath } ;
7+ use rustc_infer:: infer:: InferCtxt ;
8+ use rustc_infer:: traits:: { Obligation , ObligationCause } ;
79use rustc_lint:: { LateContext , LateLintPass } ;
8- use rustc_middle:: ty:: { self , GenericPredicates , ParamTy , Ty } ;
10+ use rustc_middle:: ty:: { self , GenericPredicates , ParamTy , PredicatePolarity , Ty } ;
911use rustc_session:: declare_lint_pass;
1012use rustc_span:: sym;
13+ use rustc_trait_selection:: infer:: TyCtxtInferExt ;
14+ use rustc_trait_selection:: traits:: query:: evaluate_obligation:: InferCtxtExt ;
1115use std:: iter;
1216
1317declare_clippy_lint ! {
@@ -59,10 +63,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPathNew {
5963
6064 let sig = tcx. fn_sig ( fn_did) . skip_binder ( ) . skip_binder ( ) ;
6165
62- let has_required_preds = |_param_ty : & ParamTy , _preds : GenericPredicates < ' _ > | -> bool {
63- // TODO
64- true
65- } ;
66+ let infcx = cx. tcx . infer_ctxt ( ) . build ( cx. typing_mode ( ) ) ;
6667
6768 // `ExprKind::MethodCall` doesn't include the receiver in `args`, but does in `sig.inputs()`
6869 // -- so we iterate over both in `rev`erse in order to line them up starting from the _end_
@@ -87,7 +88,8 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPathNew {
8788 . enumerate ( )
8889 . filter_map ( |( i, input) | ( i != arg_idx) . then_some ( * input) ) ,
8990 )
90- && has_required_preds ( arg_param_ty, cx. tcx . predicates_of ( fn_did) )
91+ && let x_ty = cx. typeck_results ( ) . expr_ty ( x)
92+ && has_required_preds ( cx, & infcx, * arg_ty, x_ty, cx. tcx . predicates_of ( fn_did) )
9193 {
9294 let mut applicability = Applicability :: MachineApplicable ;
9395 let sugg = Sugg :: hir_with_applicability ( cx, x, "_" , & mut applicability) ;
@@ -119,3 +121,49 @@ fn is_used_anywhere_else<'tcx>(param_ty: ParamTy, mut other_sig_tys: impl Iterat
119121 } )
120122 } )
121123}
124+
125+ fn has_required_preds < ' tcx > (
126+ cx : & LateContext < ' tcx > ,
127+ infcx : & InferCtxt < ' tcx > ,
128+ param_ty : Ty < ' tcx > ,
129+ x_ty : Ty < ' tcx > ,
130+ preds : GenericPredicates < ' tcx > ,
131+ ) -> bool {
132+ let mut has_preds = false ;
133+
134+ let has_required_preds = preds
135+ . predicates
136+ . iter ( )
137+ . filter_map ( |( clause, _) | clause. as_trait_clause ( ) )
138+ . map ( |pred| pred. skip_binder ( ) )
139+ . filter ( |pred| {
140+ // dbg!(pred.self_ty(), param_ty);
141+ pred. self_ty ( ) == param_ty
142+ } )
143+ . all ( |pred| {
144+ has_preds = true ;
145+
146+ if pred. polarity != PredicatePolarity :: Positive {
147+ return false ;
148+ }
149+
150+ let new_pred = pred. with_replaced_self_ty ( cx. tcx , x_ty) ;
151+ let obligation = Obligation :: new ( cx. tcx , ObligationCause :: dummy ( ) , cx. param_env , new_pred) ;
152+ infcx. predicate_must_hold_modulo_regions ( & obligation)
153+ // match cx.tcx.get_diagnostic_name(pred.def_id()) {
154+ // Some(sym::AsRef) => {
155+ // // TODO: check if it's `AsRef<Path>` in paricular
156+ // },
157+ // Some(sym::Sized) => todo!(),
158+ // _ => return false,
159+ // };
160+ } ) ;
161+
162+ if !has_preds {
163+ // There were no trait clauses -- this means that the type just needs to be `Path`, so the
164+ // lint is not applicable
165+ return false ;
166+ }
167+
168+ has_required_preds
169+ }
0 commit comments