Clean up code rightward drift
This commit is contained in:
parent
e48670c34a
commit
055db16479
1 changed files with 79 additions and 65 deletions
|
@ -38,30 +38,41 @@ declare_lint_pass!(NoopMethodCall => [NOOP_METHOD_CALL]);
|
||||||
|
|
||||||
impl<'tcx> LateLintPass<'tcx> for NoopMethodCall {
|
impl<'tcx> LateLintPass<'tcx> for NoopMethodCall {
|
||||||
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
|
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
|
||||||
// We only care about method calls
|
// We only care about method calls.
|
||||||
if let ExprKind::MethodCall(call, _, elements, _) = expr.kind {
|
let (call, elements) = match expr.kind {
|
||||||
// Get the `DefId` only when dealing with an `AssocFn`
|
ExprKind::MethodCall(call, _, elements, _) => (call, elements),
|
||||||
if let Some((DefKind::AssocFn, did)) =
|
_ => return,
|
||||||
cx.typeck_results().type_dependent_def(expr.hir_id)
|
};
|
||||||
{
|
// We only care about method calls corresponding to the `Clone`, `Deref` and `Borrow`
|
||||||
// Check that we're dealing with a trait method
|
// traits and ignore any other method call.
|
||||||
if let Some(trait_id) = cx.tcx.trait_of_item(did) {
|
let (trait_id, did) = match cx.typeck_results().type_dependent_def(expr.hir_id) {
|
||||||
// Check we're dealing with one of the traits we care about
|
// Verify we are dealing with a method/associated function.
|
||||||
if ![sym::Clone, sym::Deref, sym::Borrow]
|
Some((DefKind::AssocFn, did)) => match cx.tcx.trait_of_item(did) {
|
||||||
|
// Check that we're dealing with a trait method for one of the traits we care about.
|
||||||
|
Some(trait_id)
|
||||||
|
if [sym::Clone, sym::Deref, sym::Borrow]
|
||||||
.iter()
|
.iter()
|
||||||
.any(|s| cx.tcx.is_diagnostic_item(*s, trait_id))
|
.any(|s| cx.tcx.is_diagnostic_item(*s, trait_id)) =>
|
||||||
{
|
{
|
||||||
|
(trait_id, did)
|
||||||
|
}
|
||||||
|
_ => return,
|
||||||
|
},
|
||||||
|
_ => return,
|
||||||
|
};
|
||||||
|
let substs = cx.typeck_results().node_substs(expr.hir_id);
|
||||||
|
if substs.needs_subst() {
|
||||||
|
// We can't resolve on types that require monomorphization, so we don't handle them if
|
||||||
|
// we need to perfom substitution.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let substs = cx.typeck_results().node_substs(expr.hir_id);
|
|
||||||
// We can't resolve on types that require monomorphization,
|
|
||||||
// so check that we don't need to perfom substitution
|
|
||||||
if !substs.needs_subst() {
|
|
||||||
let param_env = cx.tcx.param_env(trait_id);
|
let param_env = cx.tcx.param_env(trait_id);
|
||||||
// Resolve the trait method instance
|
// Resolve the trait method instance.
|
||||||
if let Ok(Some(i)) = ty::Instance::resolve(cx.tcx, param_env, did, substs) {
|
let i = match ty::Instance::resolve(cx.tcx, param_env, did, substs) {
|
||||||
// Check that it implements the noop diagnostic
|
Ok(Some(i)) => i,
|
||||||
|
_ => return,
|
||||||
|
};
|
||||||
|
// (Re)check that it implements the noop diagnostic.
|
||||||
for (s, peel_ref) in [
|
for (s, peel_ref) in [
|
||||||
(sym::noop_method_borrow, true),
|
(sym::noop_method_borrow, true),
|
||||||
(sym::noop_method_clone, false),
|
(sym::noop_method_clone, false),
|
||||||
|
@ -74,13 +85,18 @@ impl<'tcx> LateLintPass<'tcx> for NoopMethodCall {
|
||||||
let receiver = &elements[0];
|
let receiver = &elements[0];
|
||||||
let receiver_ty = cx.typeck_results().expr_ty(receiver);
|
let receiver_ty = cx.typeck_results().expr_ty(receiver);
|
||||||
let receiver_ty = match receiver_ty.kind() {
|
let receiver_ty = match receiver_ty.kind() {
|
||||||
// Remove one borrow from the receiver as all the trait methods
|
// Remove one borrow from the receiver if appropriate to positively verify that
|
||||||
// we care about here have a `&self` receiver.
|
// the receiver `&self` type and the return type are the same, depending on the
|
||||||
|
// involved trait being checked.
|
||||||
ty::Ref(_, ty, _) if *peel_ref => ty,
|
ty::Ref(_, ty, _) if *peel_ref => ty,
|
||||||
|
// When it comes to `Clone` we need to check the `receiver_ty` directly.
|
||||||
|
// FIXME: we must come up with a better strategy for this.
|
||||||
_ => receiver_ty,
|
_ => receiver_ty,
|
||||||
};
|
};
|
||||||
let expr_ty = cx.typeck_results().expr_ty_adjusted(expr);
|
let expr_ty = cx.typeck_results().expr_ty_adjusted(expr);
|
||||||
if receiver_ty != expr_ty {
|
if receiver_ty != expr_ty {
|
||||||
|
// This lint will only trigger if the receiver type and resulting expression \
|
||||||
|
// type are the same, implying that the method call is unnecessary.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let expr_span = expr.span;
|
let expr_span = expr.span;
|
||||||
|
@ -94,7 +110,10 @@ impl<'tcx> LateLintPass<'tcx> for NoopMethodCall {
|
||||||
let span = expr_span.with_lo(receiver.span.hi());
|
let span = expr_span.with_lo(receiver.span.hi());
|
||||||
cx.struct_span_lint(NOOP_METHOD_CALL, span, |lint| {
|
cx.struct_span_lint(NOOP_METHOD_CALL, span, |lint| {
|
||||||
let method = &call.ident.name;
|
let method = &call.ident.name;
|
||||||
let message = format!("call to `.{}()` on a reference in this situation does nothing", &method);
|
let message = format!(
|
||||||
|
"call to `.{}()` on a reference in this situation does nothing",
|
||||||
|
&method,
|
||||||
|
);
|
||||||
lint.build(&message)
|
lint.build(&message)
|
||||||
.span_label(span, "unnecessary method call")
|
.span_label(span, "unnecessary method call")
|
||||||
.note(¬e)
|
.note(¬e)
|
||||||
|
@ -103,9 +122,4 @@ impl<'tcx> LateLintPass<'tcx> for NoopMethodCall {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue