Add default_trait_access lint

This commit is contained in:
Daniel Wagner-Hall 2018-06-14 08:57:27 +01:00
parent 26bc88d48c
commit 4866309f9d
6 changed files with 141 additions and 0 deletions

View file

@ -0,0 +1,63 @@
use rustc::hir::*;
use rustc::lint::*;
use crate::utils::{match_def_path, opt_def_id, paths, span_lint_and_sugg};
/// **What it does:** Checks for literal calls to `Default::default()`.
///
/// **Why is this bad?** It's more clear to the reader to use the name of the type whose default is
/// being gotten than the generic `Default`.
///
/// **Known problems:** None.
///
/// **Example:**
/// ```rust
/// // Bad
/// let s: String = Default::default();
///
/// // Good
/// let s = String::default();
/// ```
declare_clippy_lint! {
pub DEFAULT_TRAIT_ACCESS,
style,
"checks for literal calls to Default::default()"
}
#[derive(Copy, Clone)]
pub struct DefaultTraitAccess;
impl LintPass for DefaultTraitAccess {
fn get_lints(&self) -> LintArray {
lint_array!(DEFAULT_TRAIT_ACCESS)
}
}
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for DefaultTraitAccess {
fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
if_chain! {
if let ExprCall(ref path, ..) = expr.node;
if let ExprPath(ref qpath) = path.node;
if let Some(def_id) = opt_def_id(cx.tables.qpath_def(qpath, path.hir_id));
if match_def_path(cx.tcx, def_id, &paths::DEFAULT_TRAIT_METHOD);
then {
match qpath {
QPath::Resolved(..) => {
// TODO: Work out a way to put "whatever the imported way of referencing
// this type in this file" rather than a fully-qualified type.
let replacement = format!("{}::default()", cx.tables.expr_ty(expr));
span_lint_and_sugg(
cx,
DEFAULT_TRAIT_ACCESS,
expr.span,
&format!("Calling {} is more clear than this expression", replacement),
"try",
replacement);
},
QPath::TypeRelative(..) => {},
}
}
}
}
}

View file

@ -111,6 +111,7 @@ pub mod collapsible_if;
pub mod const_static_lifetime; pub mod const_static_lifetime;
pub mod copies; pub mod copies;
pub mod cyclomatic_complexity; pub mod cyclomatic_complexity;
pub mod default_trait_access;
pub mod derive; pub mod derive;
pub mod doc; pub mod doc;
pub mod double_comparison; pub mod double_comparison;
@ -425,6 +426,7 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry) {
reg.register_late_lint_pass(box neg_cmp_op_on_partial_ord::NoNegCompOpForPartialOrd); reg.register_late_lint_pass(box neg_cmp_op_on_partial_ord::NoNegCompOpForPartialOrd);
reg.register_late_lint_pass(box unwrap::Pass); reg.register_late_lint_pass(box unwrap::Pass);
reg.register_late_lint_pass(box duration_subsec::DurationSubsec); reg.register_late_lint_pass(box duration_subsec::DurationSubsec);
reg.register_late_lint_pass(box default_trait_access::DefaultTraitAccess);
reg.register_lint_group("clippy_restriction", vec![ reg.register_lint_group("clippy_restriction", vec![
@ -512,6 +514,7 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry) {
copies::IF_SAME_THEN_ELSE, copies::IF_SAME_THEN_ELSE,
copies::IFS_SAME_COND, copies::IFS_SAME_COND,
cyclomatic_complexity::CYCLOMATIC_COMPLEXITY, cyclomatic_complexity::CYCLOMATIC_COMPLEXITY,
default_trait_access::DEFAULT_TRAIT_ACCESS,
derive::DERIVE_HASH_XOR_EQ, derive::DERIVE_HASH_XOR_EQ,
double_comparison::DOUBLE_COMPARISONS, double_comparison::DOUBLE_COMPARISONS,
double_parens::DOUBLE_PARENS, double_parens::DOUBLE_PARENS,
@ -709,6 +712,7 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry) {
block_in_if_condition::BLOCK_IN_IF_CONDITION_STMT, block_in_if_condition::BLOCK_IN_IF_CONDITION_STMT,
collapsible_if::COLLAPSIBLE_IF, collapsible_if::COLLAPSIBLE_IF,
const_static_lifetime::CONST_STATIC_LIFETIME, const_static_lifetime::CONST_STATIC_LIFETIME,
default_trait_access::DEFAULT_TRAIT_ACCESS,
enum_variants::ENUM_VARIANT_NAMES, enum_variants::ENUM_VARIANT_NAMES,
enum_variants::MODULE_INCEPTION, enum_variants::MODULE_INCEPTION,
eq_op::OP_REF, eq_op::OP_REF,

View file

@ -24,6 +24,7 @@ pub const C_VOID: [&str; 4] = ["std", "os", "raw", "c_void"];
pub const C_VOID_LIBC: [&str; 2] = ["libc", "c_void"]; pub const C_VOID_LIBC: [&str; 2] = ["libc", "c_void"];
pub const DEBUG_FMT_METHOD: [&str; 4] = ["core", "fmt", "Debug", "fmt"]; pub const DEBUG_FMT_METHOD: [&str; 4] = ["core", "fmt", "Debug", "fmt"];
pub const DEFAULT_TRAIT: [&str; 3] = ["core", "default", "Default"]; pub const DEFAULT_TRAIT: [&str; 3] = ["core", "default", "Default"];
pub const DEFAULT_TRAIT_METHOD: [&str; 4] = ["core", "default", "Default", "default"];
pub const DISPLAY_FMT_METHOD: [&str; 4] = ["core", "fmt", "Display", "fmt"]; pub const DISPLAY_FMT_METHOD: [&str; 4] = ["core", "fmt", "Display", "fmt"];
pub const DOUBLE_ENDED_ITERATOR: [&str; 4] = ["core", "iter", "traits", "DoubleEndedIterator"]; pub const DOUBLE_ENDED_ITERATOR: [&str; 4] = ["core", "iter", "traits", "DoubleEndedIterator"];
pub const DROP: [&str; 3] = ["core", "mem", "drop"]; pub const DROP: [&str; 3] = ["core", "mem", "drop"];

View file

@ -0,0 +1,39 @@
#![warn(default_trait_access)]
use std::default::Default as D2;
use std::string;
use std::default;
fn main() {
let s1: String = Default::default();
let s2 = String::default();
let s3: String = D2::default();
let s4: String = std::default::Default::default();
let s5 = string::String::default();
let s6: String = default::Default::default();
let s7 = std::string::String::default();
let s8: String = DefaultFactory::make_t_badly();
let s9: String = DefaultFactory::make_t_nicely();
println!("[{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}]", s1, s2, s3, s4, s5, s6, s7, s8, s9);
}
struct DefaultFactory;
impl DefaultFactory {
pub fn make_t_badly<T: Default>() -> T {
Default::default()
}
pub fn make_t_nicely<T: Default>() -> T {
T::default()
}
}

View file

@ -0,0 +1,34 @@
error: Calling std::string::String::default() is more clear than this expression
--> $DIR/default_trait_access.rs:8:22
|
8 | let s1: String = Default::default();
| ^^^^^^^^^^^^^^^^^^ help: try: `std::string::String::default()`
|
= note: `-D default-trait-access` implied by `-D warnings`
error: Calling std::string::String::default() is more clear than this expression
--> $DIR/default_trait_access.rs:12:22
|
12 | let s3: String = D2::default();
| ^^^^^^^^^^^^^ help: try: `std::string::String::default()`
error: Calling std::string::String::default() is more clear than this expression
--> $DIR/default_trait_access.rs:14:22
|
14 | let s4: String = std::default::Default::default();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::string::String::default()`
error: Calling std::string::String::default() is more clear than this expression
--> $DIR/default_trait_access.rs:18:22
|
18 | let s6: String = default::Default::default();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::string::String::default()`
error: Calling T::default() is more clear than this expression
--> $DIR/default_trait_access.rs:33:9
|
33 | Default::default()
| ^^^^^^^^^^^^^^^^^^ help: try: `T::default()`
error: aborting due to 5 previous errors

View file