Skip to content

[experiment] Deny noop_method_call #112160

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion compiler/rustc_lint/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -405,7 +405,7 @@ lint_non_upper_case_global = {$sort} `{$name}` should have an upper case name

lint_noop_method_call = call to `.{$method}()` on a reference in this situation does nothing
.label = unnecessary method call
.note = the type `{$receiver_ty}` which `{$method}` is being called on is the same as the type returned from `{$method}`, so the method call does not do anything and can be removed
.note = the type `{$orig_ty}` does not implement `{$trait_}`, so calling `{$method}` on `&{$orig_ty}` copies the reference, which does not do anything and can be removed

lint_only_cast_u8_to_char = only `u8` can be cast into `char`
.suggestion = use a `char` literal instead
Expand Down
3 changes: 2 additions & 1 deletion compiler/rustc_lint/src/lints.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1206,7 +1206,8 @@ pub enum NonUpperCaseGlobalSub {
#[note]
pub struct NoopMethodCallDiag<'a> {
pub method: Symbol,
pub receiver_ty: Ty<'a>,
pub orig_ty: Ty<'a>,
pub trait_: Symbol,
#[label]
pub label: Span,
}
Expand Down
32 changes: 14 additions & 18 deletions compiler/rustc_lint/src/noop_method_call.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ declare_lint! {
///
/// ```rust
/// # #![allow(unused)]
/// #![warn(noop_method_call)]
/// struct Foo;
/// let foo = &Foo;
/// let clone: &Foo = foo.clone();
Expand All @@ -32,7 +31,7 @@ declare_lint! {
/// calling `clone` on a `&T` where `T` does not implement clone, actually doesn't do anything
/// as references are copy. This lint detects these calls and warns the user about them.
pub NOOP_METHOD_CALL,
Allow,
Deny,
"detects the use of well-known noop methods"
}

Expand Down Expand Up @@ -76,21 +75,16 @@ impl<'tcx> LateLintPass<'tcx> for NoopMethodCall {

// We only care about method calls corresponding to the `Clone`, `Deref` and `Borrow`
// traits and ignore any other method call.
let did = match cx.typeck_results().type_dependent_def(expr.hir_id) {
// Verify we are dealing with a method/associated function.
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 matches!(
cx.tcx.get_diagnostic_name(trait_id),
Some(sym::Borrow | sym::Clone | sym::Deref)
) =>
{
did
}
_ => return,
},
_ => return,
//
// Verify we are dealing with a method/associated function, and check that we're dealing
// with a trait method for one of the traits we care about.
let (did, trait_) = if let Some((DefKind::AssocFn, did)) = cx.typeck_results().type_dependent_def(expr.hir_id)
&& let Some(trait_id) = cx.tcx.trait_of_item(did)
&& let Some(trait_ @ (sym::Borrow | sym::Clone | sym::Deref)) = cx.tcx.get_diagnostic_name(trait_id)
{
(did, trait_)
} else {
return;
};
let substs = cx
.tcx
Expand Down Expand Up @@ -122,11 +116,13 @@ impl<'tcx> LateLintPass<'tcx> for NoopMethodCall {
let expr_span = expr.span;
let span = expr_span.with_lo(receiver.span.hi());

let orig_ty = expr_ty.peel_refs();

if receiver_ty == expr_ty {
cx.emit_spanned_lint(
NOOP_METHOD_CALL,
span,
NoopMethodCallDiag { method: call.ident.name, receiver_ty, label: span },
NoopMethodCallDiag { method: call.ident.name, orig_ty, trait_, label: span },
);
} else {
cx.emit_spanned_lint(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@ use rustc_span::{BytePos, DesugaringKind, ExpnKind, MacroKind, Span, DUMMY_SP};
use rustc_target::spec::abi;
use std::borrow::Cow;
use std::iter;
use std::ops::Deref;

use super::InferCtxtPrivExt;
use crate::infer::InferCtxtExt as _;
Expand Down Expand Up @@ -3466,7 +3465,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
// to an associated type (as seen from `trait_pred`) in the predicate. Like in
// trait_pred `S: Sum<<Self as Iterator>::Item>` and predicate `i32: Sum<&()>`
let mut type_diffs = vec![];
if let ObligationCauseCode::ExprBindingObligation(def_id, _, _, idx) = parent_code.deref()
if let ObligationCauseCode::ExprBindingObligation(def_id, _, _, idx) = parent_code
&& let Some(node_substs) = typeck_results.node_substs_opt(call_hir_id)
&& let where_clauses = self.tcx.predicates_of(def_id).instantiate(self.tcx, node_substs)
&& let Some(where_pred) = where_clauses.predicates.get(*idx)
Expand Down
1 change: 1 addition & 0 deletions library/core/benches/iter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -421,6 +421,7 @@ fn bench_next_chunk_copied(b: &mut Bencher) {

/// Exercises the TrustedRandomAccess specialization in ArrayChunks
#[bench]
#[allow(noop_method_call)]
fn bench_next_chunk_trusted_random_access(b: &mut Bencher) {
let v = vec![1u8; 1024];

Expand Down
1 change: 1 addition & 0 deletions src/tools/clippy/tests/ui/explicit_deref_methods.fixed
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#![allow(
clippy::borrow_deref_ref,
suspicious_double_ref_op,
noop_method_call,
clippy::explicit_auto_deref,
clippy::needless_borrow,
clippy::uninlined_format_args
Expand Down
1 change: 1 addition & 0 deletions src/tools/clippy/tests/ui/explicit_deref_methods.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#![allow(
clippy::borrow_deref_ref,
suspicious_double_ref_op,
noop_method_call,
clippy::explicit_auto_deref,
clippy::needless_borrow,
clippy::uninlined_format_args
Expand Down
24 changes: 12 additions & 12 deletions src/tools/clippy/tests/ui/explicit_deref_methods.stderr
Original file line number Diff line number Diff line change
@@ -1,73 +1,73 @@
error: explicit `deref` method call
--> $DIR/explicit_deref_methods.rs:36:19
--> $DIR/explicit_deref_methods.rs:37:19
|
LL | let b: &str = a.deref();
| ^^^^^^^^^ help: try this: `&*a`
|
= note: `-D clippy::explicit-deref-methods` implied by `-D warnings`

error: explicit `deref_mut` method call
--> $DIR/explicit_deref_methods.rs:38:23
--> $DIR/explicit_deref_methods.rs:39:23
|
LL | let b: &mut str = a.deref_mut();
| ^^^^^^^^^^^^^ help: try this: `&mut **a`

error: explicit `deref` method call
--> $DIR/explicit_deref_methods.rs:41:39
--> $DIR/explicit_deref_methods.rs:42:39
|
LL | let b: String = format!("{}, {}", a.deref(), a.deref());
| ^^^^^^^^^ help: try this: `&*a`

error: explicit `deref` method call
--> $DIR/explicit_deref_methods.rs:41:50
--> $DIR/explicit_deref_methods.rs:42:50
|
LL | let b: String = format!("{}, {}", a.deref(), a.deref());
| ^^^^^^^^^ help: try this: `&*a`

error: explicit `deref` method call
--> $DIR/explicit_deref_methods.rs:43:20
--> $DIR/explicit_deref_methods.rs:44:20
|
LL | println!("{}", a.deref());
| ^^^^^^^^^ help: try this: `&*a`

error: explicit `deref` method call
--> $DIR/explicit_deref_methods.rs:46:11
--> $DIR/explicit_deref_methods.rs:47:11
|
LL | match a.deref() {
| ^^^^^^^^^ help: try this: `&*a`

error: explicit `deref` method call
--> $DIR/explicit_deref_methods.rs:50:28
--> $DIR/explicit_deref_methods.rs:51:28
|
LL | let b: String = concat(a.deref());
| ^^^^^^^^^ help: try this: `&*a`

error: explicit `deref` method call
--> $DIR/explicit_deref_methods.rs:52:13
--> $DIR/explicit_deref_methods.rs:53:13
|
LL | let b = just_return(a).deref();
| ^^^^^^^^^^^^^^^^^^^^^^ help: try this: `just_return(a)`

error: explicit `deref` method call
--> $DIR/explicit_deref_methods.rs:54:28
--> $DIR/explicit_deref_methods.rs:55:28
|
LL | let b: String = concat(just_return(a).deref());
| ^^^^^^^^^^^^^^^^^^^^^^ help: try this: `just_return(a)`

error: explicit `deref` method call
--> $DIR/explicit_deref_methods.rs:56:19
--> $DIR/explicit_deref_methods.rs:57:19
|
LL | let b: &str = a.deref().deref();
| ^^^^^^^^^^^^^^^^^ help: try this: `&**a`

error: explicit `deref` method call
--> $DIR/explicit_deref_methods.rs:59:13
--> $DIR/explicit_deref_methods.rs:60:13
|
LL | let b = opt_a.unwrap().deref();
| ^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&*opt_a.unwrap()`

error: explicit `deref` method call
--> $DIR/explicit_deref_methods.rs:85:31
--> $DIR/explicit_deref_methods.rs:86:31
|
LL | let b: &str = expr_deref!(a.deref());
| ^^^^^^^^^ help: try this: `&*a`
Expand Down
2 changes: 1 addition & 1 deletion src/tools/compiletest/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1119,7 +1119,7 @@ fn check_overlapping_tests(found_paths: &BTreeSet<PathBuf>) {
for path in found_paths {
for ancestor in path.ancestors().skip(1) {
if found_paths.contains(ancestor) {
collisions.push((path, ancestor.clone()));
collisions.push((path, ancestor));
}
}
}
Expand Down
2 changes: 2 additions & 0 deletions tests/ui/issues/issue-11820.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
// run-pass
// pretty-expanded FIXME #23616

#![allow(noop_method_call)]

struct NoClone;

fn main() {
Expand Down
10 changes: 5 additions & 5 deletions tests/ui/lint/noop-method-call.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ warning: call to `.clone()` on a reference in this situation does nothing
LL | let non_clone_type_ref_clone: &PlainType<u32> = non_clone_type_ref.clone();
| ^^^^^^^^ unnecessary method call
|
= note: the type `&PlainType<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 `PlainType<u32>` does not implement `Clone`, so calling `clone` on `&PlainType<u32>` copies the reference, which does not do anything and can be removed
note: the lint level is defined here
--> $DIR/noop-method-call.rs:4:9
|
Expand All @@ -25,7 +25,7 @@ warning: call to `.deref()` on a reference in this situation does nothing
LL | let non_deref_type_deref: &PlainType<u32> = non_deref_type.deref();
| ^^^^^^^^ unnecessary method call
|
= note: the type `&PlainType<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 `PlainType<u32>` does not implement `Deref`, so calling `deref` on `&PlainType<u32>` copies the reference, which does not do anything and can be removed

warning: using `.deref()` on a double reference, which returns `&PlainType<u32>` instead of dereferencing the inner type
--> $DIR/noop-method-call.rs:31:63
Expand All @@ -39,7 +39,7 @@ warning: call to `.borrow()` on a reference in this situation does nothing
LL | let non_borrow_type_borrow: &PlainType<u32> = non_borrow_type.borrow();
| ^^^^^^^^^ unnecessary method call
|
= note: the type `&PlainType<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 `PlainType<u32>` does not implement `Borrow`, so calling `borrow` on `&PlainType<u32>` copies the reference, which does not do anything and can be removed

warning: using `.clone()` on a double reference, which returns `&str` instead of cloning the inner type
--> $DIR/noop-method-call.rs:43:44
Expand All @@ -53,15 +53,15 @@ warning: call to `.clone()` on a reference in this situation does nothing
LL | non_clone_type.clone();
| ^^^^^^^^ unnecessary method call
|
= note: the type `&PlainType<T>` 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 `PlainType<T>` does not implement `Clone`, so calling `clone` on `&PlainType<T>` copies the reference, which does not do anything and can be removed

warning: call to `.clone()` on a reference in this situation does nothing
--> $DIR/noop-method-call.rs:53:19
|
LL | non_clone_type.clone();
| ^^^^^^^^ unnecessary method call
|
= note: the type `&PlainType<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 `PlainType<u32>` does not implement `Clone`, so calling `clone` on `&PlainType<u32>` copies the reference, which does not do anything and can be removed

warning: 8 warnings emitted

4 changes: 2 additions & 2 deletions tests/ui/lint/suspicious-double-ref-op.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ error: call to `.clone()` on a reference in this situation does nothing
LL | let _ = &mut encoded.clone();
| ^^^^^^^^ unnecessary method call
|
= note: the type `&[u8]` 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 `[u8]` does not implement `Clone`, so calling `clone` on `&[u8]` copies the reference, which does not do anything and can be removed
note: the lint level is defined here
--> $DIR/suspicious-double-ref-op.rs:2:35
|
Expand All @@ -29,7 +29,7 @@ error: call to `.clone()` on a reference in this situation does nothing
LL | let _ = &encoded.clone();
| ^^^^^^^^ unnecessary method call
|
= note: the type `&[u8]` 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 `[u8]` does not implement `Clone`, so calling `clone` on `&[u8]` copies the reference, which does not do anything and can be removed

error: aborting due to 3 previous errors

2 changes: 2 additions & 0 deletions tests/ui/underscore-imports/cycle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

// check-pass

#![allow(noop_method_call)]

mod x {
pub use crate::y::*;
pub use std::ops::Deref as _;
Expand Down
1 change: 1 addition & 0 deletions tests/ui/underscore-imports/hygiene.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
// check-pass

#![feature(decl_macro)]
#![allow(noop_method_call)]

mod x {
pub use std::ops::Deref as _;
Expand Down