Skip to content

Commit 988e2f9

Browse files
committed
First version of noop-lint
1 parent 9530fdc commit 988e2f9

File tree

4 files changed

+77
-0
lines changed

4 files changed

+77
-0
lines changed

compiler/rustc_lint/src/lib.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ mod levels;
5555
mod methods;
5656
mod non_ascii_idents;
5757
mod nonstandard_style;
58+
mod noop_method_call;
5859
mod panic_fmt;
5960
mod passes;
6061
mod redundant_semicolon;
@@ -81,6 +82,7 @@ use internal::*;
8182
use methods::*;
8283
use non_ascii_idents::*;
8384
use nonstandard_style::*;
85+
use noop_method_call::*;
8486
use panic_fmt::PanicFmt;
8587
use redundant_semicolon::*;
8688
use traits::*;
@@ -168,6 +170,7 @@ macro_rules! late_lint_passes {
168170
ClashingExternDeclarations: ClashingExternDeclarations::new(),
169171
DropTraitConstraints: DropTraitConstraints,
170172
TemporaryCStringAsPtr: TemporaryCStringAsPtr,
173+
NoopMethodCall: NoopMethodCall,
171174
PanicFmt: PanicFmt,
172175
]
173176
);
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
use crate::context::LintContext;
2+
use crate::rustc_middle::ty::TypeFoldable;
3+
use crate::LateContext;
4+
use crate::LateLintPass;
5+
use rustc_hir::def::DefKind;
6+
use rustc_hir::{Expr, ExprKind};
7+
use rustc_middle::ty;
8+
use rustc_span::symbol::sym;
9+
10+
declare_lint! {
11+
/// The `noop_method_call` lint detects specific calls to noop methods
12+
/// such as a calling `<&T as Clone>::clone` where `T: !Clone`.
13+
///
14+
/// ### Example
15+
///
16+
/// ```rust
17+
/// # #![allow(unused)]
18+
/// struct Foo;
19+
/// let foo = &Foo;
20+
/// let clone: &Foo = foo.clone();
21+
/// ```
22+
///
23+
/// {{produces}}
24+
///
25+
/// ### Explanation
26+
///
27+
/// Some method calls are noops meaning that they do nothing. Usually such methods
28+
/// are the result of blanket implementations that happen to create some method invocations
29+
/// that end up not doing anything. For instance, `Clone` is implemented on all `&T`, but
30+
/// calling `clone` on a `&T` where `T` does not implement clone, actually doesn't do anything
31+
/// as references are copy. This lint detects these calls and warns the user about them.
32+
pub NOOP_METHOD_CALL,
33+
Warn,
34+
"detects the use of well-known noop methods"
35+
}
36+
37+
declare_lint_pass!(NoopMethodCall => [NOOP_METHOD_CALL]);
38+
39+
impl<'tcx> LateLintPass<'tcx> for NoopMethodCall {
40+
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
41+
// We only care about method calls
42+
if let ExprKind::MethodCall(..) = expr.kind {
43+
// Get the `DefId` only when dealing with an `AssocFn`
44+
if let Some((DefKind::AssocFn, did)) =
45+
cx.typeck_results().type_dependent_def(expr.hir_id)
46+
{
47+
// Check that we're dealing with a trait method
48+
if let Some(trait_id) = cx.tcx.trait_of_item(did) {
49+
let substs = cx.typeck_results().node_substs(expr.hir_id);
50+
// We can't resolve on types that recursively require monomorphization,
51+
// so check that we don't need to perfom substitution
52+
if !substs.needs_subst() {
53+
let param_env = cx.tcx.param_env(trait_id);
54+
// Resolve the trait method instance
55+
if let Ok(Some(i)) = ty::Instance::resolve(cx.tcx, param_env, did, substs) {
56+
// Check that it implements the noop diagnostic
57+
if cx.tcx.is_diagnostic_item(sym::ref_clone_method, i.def_id()) {
58+
let span = expr.span;
59+
60+
cx.struct_span_lint(NOOP_METHOD_CALL, span, |lint| {
61+
let message = "Call to noop method";
62+
lint.build(&message).emit()
63+
});
64+
}
65+
}
66+
}
67+
}
68+
}
69+
}
70+
}
71+
}

compiler/rustc_span/src/symbol.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -887,6 +887,7 @@ symbols! {
887887
receiver,
888888
recursion_limit,
889889
reexport_test_harness_main,
890+
ref_clone_method,
890891
reference,
891892
reflect,
892893
reg,

library/core/src/clone.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@
104104
/// [impls]: #implementors
105105
#[stable(feature = "rust1", since = "1.0.0")]
106106
#[lang = "clone"]
107+
#[rustc_diagnostic_item = "Clone"]
107108
pub trait Clone: Sized {
108109
/// Returns a copy of the value.
109110
///
@@ -221,6 +222,7 @@ mod impls {
221222
#[stable(feature = "rust1", since = "1.0.0")]
222223
impl<T: ?Sized> Clone for &T {
223224
#[inline]
225+
#[rustc_diagnostic_item = "ref_clone_method"]
224226
fn clone(&self) -> Self {
225227
*self
226228
}

0 commit comments

Comments
 (0)