Skip to content

Commit 629a638

Browse files
committed
WIP: has_required_preds
1 parent 0886c57 commit 629a638

File tree

1 file changed

+55
-7
lines changed

1 file changed

+55
-7
lines changed

clippy_lints/src/needless_path_new.rs

Lines changed: 55 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,14 @@ use clippy_utils::{expr_or_init, is_path_diagnostic_item, path_res};
44
use rustc_errors::Applicability;
55
use rustc_hir::def::{CtorKind, DefKind, Res};
66
use rustc_hir::{Expr, ExprKind, QPath};
7+
use rustc_infer::infer::InferCtxt;
8+
use rustc_infer::traits::{Obligation, ObligationCause};
79
use rustc_lint::{LateContext, LateLintPass};
8-
use rustc_middle::ty::{self, GenericPredicates, ParamTy, Ty};
10+
use rustc_middle::ty::{self, GenericPredicates, ParamTy, PredicatePolarity, Ty};
911
use rustc_session::declare_lint_pass;
1012
use rustc_span::sym;
13+
use rustc_trait_selection::infer::TyCtxtInferExt;
14+
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
1115
use std::iter;
1216

1317
declare_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);
@@ -105,7 +107,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPathNew {
105107
}
106108
}
107109

108-
fn is_used_anywhere_else<'a>(param_ty: &'_ ParamTy, mut other_sig_tys: impl Iterator<Item = Ty<'a>>) -> bool {
110+
fn is_used_anywhere_else<'tcx>(param_ty: &ParamTy, mut other_sig_tys: impl Iterator<Item = Ty<'tcx>>) -> bool {
109111
other_sig_tys.any(|sig_ty| {
110112
sig_ty.walk().any(|generic_arg| {
111113
if let Some(ty) = generic_arg.as_type()
@@ -119,3 +121,49 @@ fn is_used_anywhere_else<'a>(param_ty: &'_ ParamTy, mut other_sig_tys: impl Iter
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

Comments
 (0)