Increase accuracy of lint trigger

This commit is contained in:
Esteban Küber 2021-01-12 18:37:32 -08:00 committed by Ryan Levick
parent 49f32e0c8e
commit e48670c34a
3 changed files with 43 additions and 28 deletions

View file

@ -62,33 +62,45 @@ impl<'tcx> LateLintPass<'tcx> for NoopMethodCall {
// Resolve the trait method instance // Resolve the trait method instance
if let Ok(Some(i)) = ty::Instance::resolve(cx.tcx, param_env, did, substs) { if let Ok(Some(i)) = ty::Instance::resolve(cx.tcx, param_env, did, substs) {
// Check that it implements the noop diagnostic // Check that it implements the noop diagnostic
if [ for (s, peel_ref) in [
sym::noop_method_borrow, (sym::noop_method_borrow, true),
sym::noop_method_clone, (sym::noop_method_clone, false),
sym::noop_method_deref, (sym::noop_method_deref, true),
] ]
.iter() .iter()
.any(|s| cx.tcx.is_diagnostic_item(*s, i.def_id()))
{ {
let method = &call.ident.name; if cx.tcx.is_diagnostic_item(*s, i.def_id()) {
let receiver = &elements[0];
let receiver_ty = cx.typeck_results().expr_ty(receiver);
let expr_span = expr.span;
let note = format!(
"the type `{:?}` which `{}` is being called on is the same as the type returned from `{}`, \
so the method call does not do anything and can be removed.",
receiver_ty, method, method
);
let span = expr_span.with_lo(receiver.span.hi());
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 receiver = &elements[0];
lint.build(&message) let receiver_ty = cx.typeck_results().expr_ty(receiver);
.span_label(span, "unnecessary method call") let receiver_ty = match receiver_ty.kind() {
.note(&note) // Remove one borrow from the receiver as all the trait methods
.emit() // we care about here have a `&self` receiver.
}); ty::Ref(_, ty, _) if *peel_ref => ty,
_ => receiver_ty,
};
let expr_ty = cx.typeck_results().expr_ty_adjusted(expr);
if receiver_ty != expr_ty {
return;
}
let expr_span = expr.span;
let note = format!(
"the type `{:?}` which `{}` is being called on is the same as \
the type returned from `{}`, so the method call does not do \
anything and can be removed",
receiver_ty, method, method,
);
let span = expr_span.with_lo(receiver.span.hi());
cx.struct_span_lint(NOOP_METHOD_CALL, span, |lint| {
let method = &call.ident.name;
let message = format!("call to `.{}()` on a reference in this situation does nothing", &method);
lint.build(&message)
.span_label(span, "unnecessary method call")
.note(&note)
.emit()
});
}
} }
} }
} }

View file

@ -37,6 +37,9 @@ fn main() {
let a = &&Foo(1u32); let a = &&Foo(1u32);
let borrowed: &Foo<u32> = a.borrow(); let borrowed: &Foo<u32> = a.borrow();
//~^ WARNING call to `.borrow()` on a reference in this situation does nothing //~^ WARNING call to `.borrow()` on a reference in this situation does nothing
let xs = ["a", "b", "c"];
let _v: Vec<&str> = xs.iter().map(|x| x.clone()).collect(); // ok, but could use `*x` instead
} }
fn generic<T>(foo: &Foo<T>) { fn generic<T>(foo: &Foo<T>) {

View file

@ -5,7 +5,7 @@ LL | let foo_clone: &Foo<u32> = foo.clone();
| ^^^^^^^^ unnecessary method call | ^^^^^^^^ unnecessary method call
| |
= note: `#[warn(noop_method_call)]` on by default = note: `#[warn(noop_method_call)]` on by default
= note: the type `&Foo<u32>` which `clone` is being called on is the same as the type returned from `clone`, so the method call does not do anything and can be removed. = note: the type `&Foo<u32>` which `clone` is being called on is the same as the type returned from `clone`, so the method call does not do anything and can be removed
warning: call to `.deref()` on a reference in this situation does nothing warning: call to `.deref()` on a reference in this situation does nothing
--> $DIR/noop-method-call.rs:31:44 --> $DIR/noop-method-call.rs:31:44
@ -13,7 +13,7 @@ warning: call to `.deref()` on a reference in this situation does nothing
LL | let derefed: &DerefExample<u32> = deref.deref(); LL | let derefed: &DerefExample<u32> = deref.deref();
| ^^^^^^^^ unnecessary method call | ^^^^^^^^ unnecessary method call
| |
= note: the type `&&DerefExample<u32>` which `deref` is being called on is the same as the type returned from `deref`, so the method call does not do anything and can be removed. = note: the type `&DerefExample<u32>` which `deref` is being called on is the same as the type returned from `deref`, so the method call does not do anything and can be removed
warning: call to `.borrow()` on a reference in this situation does nothing warning: call to `.borrow()` on a reference in this situation does nothing
--> $DIR/noop-method-call.rs:38:32 --> $DIR/noop-method-call.rs:38:32
@ -21,15 +21,15 @@ warning: call to `.borrow()` on a reference in this situation does nothing
LL | let borrowed: &Foo<u32> = a.borrow(); LL | let borrowed: &Foo<u32> = a.borrow();
| ^^^^^^^^^ unnecessary method call | ^^^^^^^^^ unnecessary method call
| |
= note: the type `&&Foo<u32>` which `borrow` is being called on is the same as the type returned from `borrow`, so the method call does not do anything and can be removed. = note: the type `&Foo<u32>` which `borrow` is being called on is the same as the type returned from `borrow`, so the method call does not do anything and can be removed
warning: call to `.clone()` on a reference in this situation does nothing warning: call to `.clone()` on a reference in this situation does nothing
--> $DIR/noop-method-call.rs:47:8 --> $DIR/noop-method-call.rs:50:8
| |
LL | foo.clone(); LL | foo.clone();
| ^^^^^^^^ unnecessary method call | ^^^^^^^^ unnecessary method call
| |
= note: the type `&Foo<u32>` which `clone` is being called on is the same as the type returned from `clone`, so the method call does not do anything and can be removed. = note: the type `&Foo<u32>` which `clone` is being called on is the same as the type returned from `clone`, so the method call does not do anything and can be removed
warning: 4 warnings emitted warning: 4 warnings emitted