Skip to content

Commit

Permalink
Auto merge of #111916 - fee1-dead-contrib:noop-method-call-warn, r=co…
Browse files Browse the repository at this point in the history
…mpiler-errors

make `noop_method_call` warn by default

r? `@compiler-errors`
  • Loading branch information
bors committed Jul 29, 2023
2 parents ca1f813 + 2a76c57 commit 4734ac0
Show file tree
Hide file tree
Showing 17 changed files with 161 additions and 104 deletions.
4 changes: 2 additions & 2 deletions compiler/rustc_lint/messages.ftl
Expand Up @@ -410,8 +410,8 @@ lint_non_upper_case_global = {$sort} `{$name}` should have an upper case name
.label = 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
.suggestion = remove this redundant call
.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
5 changes: 3 additions & 2 deletions compiler/rustc_lint/src/lints.rs
Expand Up @@ -1231,8 +1231,9 @@ pub enum NonUpperCaseGlobalSub {
#[note]
pub struct NoopMethodCallDiag<'a> {
pub method: Symbol,
pub receiver_ty: Ty<'a>,
#[label]
pub orig_ty: Ty<'a>,
pub trait_: Symbol,
#[suggestion(code = "", applicability = "machine-applicable")]
pub label: Span,
}

Expand Down
14 changes: 7 additions & 7 deletions compiler/rustc_lint/src/noop_method_call.rs
Expand Up @@ -18,7 +18,6 @@ declare_lint! {
///
/// ```rust
/// # #![allow(unused)]
/// #![warn(noop_method_call)]
/// struct Foo;
/// let foo = &Foo;
/// let clone: &Foo = foo.clone();
Expand All @@ -34,7 +33,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,
Warn,
"detects the use of well-known noop methods"
}

Expand Down Expand Up @@ -86,10 +85,9 @@ impl<'tcx> LateLintPass<'tcx> for NoopMethodCall {

let Some(trait_id) = cx.tcx.trait_of_item(did) else { return };

if !matches!(
cx.tcx.get_diagnostic_name(trait_id),
Some(sym::Borrow | sym::Clone | sym::Deref)
) {
let Some(trait_) = cx.tcx.get_diagnostic_name(trait_id) else { return };

if !matches!(trait_, sym::Borrow | sym::Clone | sym::Deref) {
return;
};

Expand All @@ -114,11 +112,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 {
match name {
Expand Down
Expand Up @@ -41,7 +41,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 @@ -3577,7 +3576,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_args) = typeck_results.node_args_opt(call_hir_id)
&& let where_clauses = self.tcx.predicates_of(def_id).instantiate(self.tcx, node_args)
&& let Some(where_pred) = where_clauses.predicates.get(*idx)
Expand Down
1 change: 1 addition & 0 deletions library/core/benches/iter.rs
Expand Up @@ -473,6 +473,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
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::no_effect,
Expand Down
1 change: 1 addition & 0 deletions src/tools/clippy/tests/ui/explicit_deref_methods.rs
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::no_effect,
Expand Down
24 changes: 12 additions & 12 deletions src/tools/clippy/tests/ui/explicit_deref_methods.stderr
@@ -1,73 +1,73 @@
error: explicit `deref` method call
--> $DIR/explicit_deref_methods.rs:54:19
--> $DIR/explicit_deref_methods.rs:55:19
|
LL | let b: &str = a.deref();
| ^^^^^^^^^ help: try: `&*a`
|
= note: `-D clippy::explicit-deref-methods` implied by `-D warnings`

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

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

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

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

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

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

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

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

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

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

error: explicit `deref` method call
--> $DIR/explicit_deref_methods.rs:114:31
--> $DIR/explicit_deref_methods.rs:115:31
|
LL | let b: &str = expr_deref!(a.deref());
| ^^^^^^^^^ help: try: `&*a`
Expand Down
2 changes: 1 addition & 1 deletion src/tools/compiletest/src/lib.rs
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
@@ -1,6 +1,8 @@
// run-pass
// pretty-expanded FIXME #23616

#![allow(noop_method_call)]

struct NoClone;

fn main() {
Expand Down
51 changes: 51 additions & 0 deletions tests/ui/lint/noop-method-call.fixed
@@ -0,0 +1,51 @@
// check-pass
// run-rustfix

#![allow(unused)]

use std::borrow::Borrow;
use std::ops::Deref;

struct PlainType<T>(T);

#[derive(Clone)]
struct CloneType<T>(T);

fn check(mut encoded: &[u8]) {
let _ = &mut encoded;
//~^ WARN call to `.clone()` on a reference in this situation does nothing
let _ = &encoded;
//~^ WARN call to `.clone()` on a reference in this situation does nothing
}

fn main() {
let non_clone_type_ref = &PlainType(1u32);
let non_clone_type_ref_clone: &PlainType<u32> = non_clone_type_ref;
//~^ WARN call to `.clone()` on a reference in this situation does nothing

let clone_type_ref = &CloneType(1u32);
let clone_type_ref_clone: CloneType<u32> = clone_type_ref.clone();


let non_deref_type = &PlainType(1u32);
let non_deref_type_deref: &PlainType<u32> = non_deref_type;
//~^ WARN call to `.deref()` on a reference in this situation does nothing

let non_borrow_type = &PlainType(1u32);
let non_borrow_type_borrow: &PlainType<u32> = non_borrow_type;
//~^ WARN call to `.borrow()` on a reference in this situation does nothing

// Borrowing a &&T does not warn since it has collapsed the double reference
let non_borrow_type = &&PlainType(1u32);
let non_borrow_type_borrow: &PlainType<u32> = non_borrow_type.borrow();
}

fn generic<T>(non_clone_type: &PlainType<T>) {
non_clone_type;
//~^ WARN call to `.clone()` on a reference in this situation does nothing
}

fn non_generic(non_clone_type: &PlainType<u32>) {
non_clone_type;
//~^ WARN call to `.clone()` on a reference in this situation does nothing
}
30 changes: 13 additions & 17 deletions tests/ui/lint/noop-method-call.rs
@@ -1,7 +1,7 @@
// check-pass
// run-rustfix

#![allow(unused)]
#![warn(noop_method_call)]

use std::borrow::Borrow;
use std::ops::Deref;
Expand All @@ -11,45 +11,41 @@ struct PlainType<T>(T);
#[derive(Clone)]
struct CloneType<T>(T);

fn check(mut encoded: &[u8]) {
let _ = &mut encoded.clone();
//~^ WARN call to `.clone()` on a reference in this situation does nothing
let _ = &encoded.clone();
//~^ WARN call to `.clone()` on a reference in this situation does nothing
}

fn main() {
let non_clone_type_ref = &PlainType(1u32);
let non_clone_type_ref_clone: &PlainType<u32> = non_clone_type_ref.clone();
//~^ WARNING call to `.clone()` on a reference in this situation does nothing
//~^ WARN call to `.clone()` on a reference in this situation does nothing

let clone_type_ref = &CloneType(1u32);
let clone_type_ref_clone: CloneType<u32> = clone_type_ref.clone();

let clone_type_ref = &&CloneType(1u32);
let clone_type_ref_clone: &CloneType<u32> = clone_type_ref.clone();
//~^ WARNING using `.clone()` on a double reference, which returns `&CloneType<u32>`

let non_deref_type = &PlainType(1u32);
let non_deref_type_deref: &PlainType<u32> = non_deref_type.deref();
//~^ WARNING call to `.deref()` on a reference in this situation does nothing

let non_deref_type = &&PlainType(1u32);
let non_deref_type_deref: &PlainType<u32> = non_deref_type.deref();
//~^ WARNING using `.deref()` on a double reference, which returns `&PlainType<u32>`
//~^ WARN call to `.deref()` on a reference in this situation does nothing

let non_borrow_type = &PlainType(1u32);
let non_borrow_type_borrow: &PlainType<u32> = non_borrow_type.borrow();
//~^ WARNING call to `.borrow()` on a reference in this situation does nothing
//~^ WARN call to `.borrow()` on a reference in this situation does nothing

// Borrowing a &&T does not warn since it has collapsed the double reference
let non_borrow_type = &&PlainType(1u32);
let non_borrow_type_borrow: &PlainType<u32> = non_borrow_type.borrow();

let xs = ["a", "b", "c"];
let _v: Vec<&str> = xs.iter().map(|x| x.clone()).collect(); // could use `*x` instead
//~^ WARNING using `.clone()` on a double reference, which returns `&str`
}

fn generic<T>(non_clone_type: &PlainType<T>) {
non_clone_type.clone();
//~^ WARNING call to `.clone()` on a reference in this situation does nothing
//~^ WARN call to `.clone()` on a reference in this situation does nothing
}

fn non_generic(non_clone_type: &PlainType<u32>) {
non_clone_type.clone();
//~^ WARNING call to `.clone()` on a reference in this situation does nothing
//~^ WARN call to `.clone()` on a reference in this situation does nothing
}

0 comments on commit 4734ac0

Please sign in to comment.