mirror of
https://github.com/rust-lang/rust-clippy
synced 2024-11-23 13:13:34 +00:00
Add default_trait_access lint
This commit is contained in:
parent
26bc88d48c
commit
4866309f9d
6 changed files with 141 additions and 0 deletions
63
clippy_lints/src/default_trait_access.rs
Normal file
63
clippy_lints/src/default_trait_access.rs
Normal 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(..) => {},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -111,6 +111,7 @@ pub mod collapsible_if;
|
|||
pub mod const_static_lifetime;
|
||||
pub mod copies;
|
||||
pub mod cyclomatic_complexity;
|
||||
pub mod default_trait_access;
|
||||
pub mod derive;
|
||||
pub mod doc;
|
||||
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 unwrap::Pass);
|
||||
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![
|
||||
|
@ -512,6 +514,7 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry) {
|
|||
copies::IF_SAME_THEN_ELSE,
|
||||
copies::IFS_SAME_COND,
|
||||
cyclomatic_complexity::CYCLOMATIC_COMPLEXITY,
|
||||
default_trait_access::DEFAULT_TRAIT_ACCESS,
|
||||
derive::DERIVE_HASH_XOR_EQ,
|
||||
double_comparison::DOUBLE_COMPARISONS,
|
||||
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,
|
||||
collapsible_if::COLLAPSIBLE_IF,
|
||||
const_static_lifetime::CONST_STATIC_LIFETIME,
|
||||
default_trait_access::DEFAULT_TRAIT_ACCESS,
|
||||
enum_variants::ENUM_VARIANT_NAMES,
|
||||
enum_variants::MODULE_INCEPTION,
|
||||
eq_op::OP_REF,
|
||||
|
|
|
@ -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 DEBUG_FMT_METHOD: [&str; 4] = ["core", "fmt", "Debug", "fmt"];
|
||||
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 DOUBLE_ENDED_ITERATOR: [&str; 4] = ["core", "iter", "traits", "DoubleEndedIterator"];
|
||||
pub const DROP: [&str; 3] = ["core", "mem", "drop"];
|
||||
|
|
39
tests/ui/default_trait_access.rs
Normal file
39
tests/ui/default_trait_access.rs
Normal 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()
|
||||
}
|
||||
}
|
34
tests/ui/default_trait_access.stderr
Normal file
34
tests/ui/default_trait_access.stderr
Normal 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
|
||||
|
0
tests/ui/default_trait_access.stdout
Normal file
0
tests/ui/default_trait_access.stdout
Normal file
Loading…
Reference in a new issue