Skip to content
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

make noop_method_call warn by default #111916

Merged
merged 3 commits into from Jul 29, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 2 additions & 2 deletions compiler/rustc_lint/messages.ftl
Expand Up @@ -412,8 +412,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 @@ -3580,7 +3579,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
}