First version of noop-lint
This commit is contained in:
parent
cbca5689a5
commit
040735c110
@ -57,6 +57,7 @@ mod methods;
|
|||||||
mod non_ascii_idents;
|
mod non_ascii_idents;
|
||||||
mod non_fmt_panic;
|
mod non_fmt_panic;
|
||||||
mod nonstandard_style;
|
mod nonstandard_style;
|
||||||
|
mod noop_method_call;
|
||||||
mod passes;
|
mod passes;
|
||||||
mod redundant_semicolon;
|
mod redundant_semicolon;
|
||||||
mod traits;
|
mod traits;
|
||||||
@ -83,6 +84,7 @@ use methods::*;
|
|||||||
use non_ascii_idents::*;
|
use non_ascii_idents::*;
|
||||||
use non_fmt_panic::NonPanicFmt;
|
use non_fmt_panic::NonPanicFmt;
|
||||||
use nonstandard_style::*;
|
use nonstandard_style::*;
|
||||||
|
use noop_method_call::*;
|
||||||
use redundant_semicolon::*;
|
use redundant_semicolon::*;
|
||||||
use traits::*;
|
use traits::*;
|
||||||
use types::*;
|
use types::*;
|
||||||
@ -170,6 +172,7 @@ macro_rules! late_lint_passes {
|
|||||||
DropTraitConstraints: DropTraitConstraints,
|
DropTraitConstraints: DropTraitConstraints,
|
||||||
TemporaryCStringAsPtr: TemporaryCStringAsPtr,
|
TemporaryCStringAsPtr: TemporaryCStringAsPtr,
|
||||||
NonPanicFmt: NonPanicFmt,
|
NonPanicFmt: NonPanicFmt,
|
||||||
|
NoopMethodCall: NoopMethodCall,
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
71
compiler/rustc_lint/src/noop_method_call.rs
Normal file
71
compiler/rustc_lint/src/noop_method_call.rs
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
use crate::context::LintContext;
|
||||||
|
use crate::rustc_middle::ty::TypeFoldable;
|
||||||
|
use crate::LateContext;
|
||||||
|
use crate::LateLintPass;
|
||||||
|
use rustc_hir::def::DefKind;
|
||||||
|
use rustc_hir::{Expr, ExprKind};
|
||||||
|
use rustc_middle::ty;
|
||||||
|
use rustc_span::symbol::sym;
|
||||||
|
|
||||||
|
declare_lint! {
|
||||||
|
/// The `noop_method_call` lint detects specific calls to noop methods
|
||||||
|
/// such as a calling `<&T as Clone>::clone` where `T: !Clone`.
|
||||||
|
///
|
||||||
|
/// ### Example
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// # #![allow(unused)]
|
||||||
|
/// struct Foo;
|
||||||
|
/// let foo = &Foo;
|
||||||
|
/// let clone: &Foo = foo.clone();
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// {{produces}}
|
||||||
|
///
|
||||||
|
/// ### Explanation
|
||||||
|
///
|
||||||
|
/// Some method calls are noops meaning that they do nothing. Usually such methods
|
||||||
|
/// are the result of blanket implementations that happen to create some method invocations
|
||||||
|
/// that end up not doing anything. For instance, `Clone` is implemented on all `&T`, but
|
||||||
|
/// 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,
|
||||||
|
Warn,
|
||||||
|
"detects the use of well-known noop methods"
|
||||||
|
}
|
||||||
|
|
||||||
|
declare_lint_pass!(NoopMethodCall => [NOOP_METHOD_CALL]);
|
||||||
|
|
||||||
|
impl<'tcx> LateLintPass<'tcx> for NoopMethodCall {
|
||||||
|
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
|
||||||
|
// We only care about method calls
|
||||||
|
if let ExprKind::MethodCall(..) = expr.kind {
|
||||||
|
// Get the `DefId` only when dealing with an `AssocFn`
|
||||||
|
if let Some((DefKind::AssocFn, did)) =
|
||||||
|
cx.typeck_results().type_dependent_def(expr.hir_id)
|
||||||
|
{
|
||||||
|
// Check that we're dealing with a trait method
|
||||||
|
if let Some(trait_id) = cx.tcx.trait_of_item(did) {
|
||||||
|
let substs = cx.typeck_results().node_substs(expr.hir_id);
|
||||||
|
// We can't resolve on types that recursively require monomorphization,
|
||||||
|
// so check that we don't need to perfom substitution
|
||||||
|
if !substs.needs_subst() {
|
||||||
|
let param_env = cx.tcx.param_env(trait_id);
|
||||||
|
// Resolve the trait method instance
|
||||||
|
if let Ok(Some(i)) = ty::Instance::resolve(cx.tcx, param_env, did, substs) {
|
||||||
|
// Check that it implements the noop diagnostic
|
||||||
|
if cx.tcx.is_diagnostic_item(sym::ref_clone_method, i.def_id()) {
|
||||||
|
let span = expr.span;
|
||||||
|
|
||||||
|
cx.struct_span_lint(NOOP_METHOD_CALL, span, |lint| {
|
||||||
|
let message = "Call to noop method";
|
||||||
|
lint.build(&message).emit()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -915,6 +915,7 @@ symbols! {
|
|||||||
receiver,
|
receiver,
|
||||||
recursion_limit,
|
recursion_limit,
|
||||||
reexport_test_harness_main,
|
reexport_test_harness_main,
|
||||||
|
ref_clone_method,
|
||||||
reference,
|
reference,
|
||||||
reflect,
|
reflect,
|
||||||
reg,
|
reg,
|
||||||
|
@ -104,6 +104,7 @@
|
|||||||
/// [impls]: #implementors
|
/// [impls]: #implementors
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
#[lang = "clone"]
|
#[lang = "clone"]
|
||||||
|
#[rustc_diagnostic_item = "Clone"]
|
||||||
pub trait Clone: Sized {
|
pub trait Clone: Sized {
|
||||||
/// Returns a copy of the value.
|
/// Returns a copy of the value.
|
||||||
///
|
///
|
||||||
@ -221,6 +222,7 @@ mod impls {
|
|||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
impl<T: ?Sized> Clone for &T {
|
impl<T: ?Sized> Clone for &T {
|
||||||
#[inline]
|
#[inline]
|
||||||
|
#[rustc_diagnostic_item = "ref_clone_method"]
|
||||||
fn clone(&self) -> Self {
|
fn clone(&self) -> Self {
|
||||||
*self
|
*self
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user