Skip to content

Commit 493354a

Browse files
ebrotohegza
authored andcommitted
Avoid triggering default_trait_access
Do not trigger `default_trait_access` on a span already linted by `field_reassigned_with_default`.
1 parent 4399b24 commit 493354a

File tree

4 files changed

+81
-81
lines changed

4 files changed

+81
-81
lines changed

clippy_lints/src/field_reassign_with_default.rs renamed to clippy_lints/src/default.rs

+72-8
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,36 @@
1-
use crate::utils::{contains_name, match_def_path, paths, qpath_res, snippet, span_lint_and_note};
1+
use crate::utils::{any_parent_is_automatically_derived, contains_name, match_def_path, paths, qpath_res, snippet};
2+
use crate::utils::{span_lint_and_note, span_lint_and_sugg};
23
use if_chain::if_chain;
4+
use rustc_data_structures::fx::FxHashSet;
5+
use rustc_errors::Applicability;
36
use rustc_hir::def::Res;
47
use rustc_hir::{Block, Expr, ExprKind, PatKind, QPath, Stmt, StmtKind};
8+
use rustc_lint::{LateContext, LateLintPass};
59
use rustc_middle::ty::{self, Adt, Ty};
10+
use rustc_session::{declare_tool_lint, impl_lint_pass};
611
use rustc_span::symbol::{Ident, Symbol};
12+
use rustc_span::Span;
713

8-
use rustc_lint::{LateContext, LateLintPass};
9-
use rustc_session::{declare_lint_pass, declare_tool_lint};
14+
declare_clippy_lint! {
15+
/// **What it does:** Checks for literal calls to `Default::default()`.
16+
///
17+
/// **Why is this bad?** It's more clear to the reader to use the name of the type whose default is
18+
/// being gotten than the generic `Default`.
19+
///
20+
/// **Known problems:** None.
21+
///
22+
/// **Example:**
23+
/// ```rust
24+
/// // Bad
25+
/// let s: String = Default::default();
26+
///
27+
/// // Good
28+
/// let s = String::default();
29+
/// ```
30+
pub DEFAULT_TRAIT_ACCESS,
31+
pedantic,
32+
"checks for literal calls to `Default::default()`"
33+
}
1034

1135
declare_clippy_lint! {
1236
/// **What it does:** Checks for immediate reassignment of fields initialized
@@ -19,12 +43,14 @@ declare_clippy_lint! {
1943
/// **Example:**
2044
/// Bad:
2145
/// ```
46+
/// # #[derive(Default)]
2247
/// # struct A { i: i32 }
2348
/// let mut a: A = Default::default();
2449
/// a.i = 42;
2550
/// ```
2651
/// Use instead:
2752
/// ```
53+
/// # #[derive(Default)]
2854
/// # struct A { i: i32 }
2955
/// let a = A {
3056
/// i: 42,
@@ -36,9 +62,46 @@ declare_clippy_lint! {
3662
"binding initialized with Default should have its fields set in the initializer"
3763
}
3864

39-
declare_lint_pass!(FieldReassignWithDefault => [FIELD_REASSIGN_WITH_DEFAULT]);
65+
#[derive(Default)]
66+
pub struct Default {
67+
// Spans linted by `field_reassign_with_default`.
68+
reassigned_linted: FxHashSet<Span>,
69+
}
70+
71+
impl_lint_pass!(Default => [DEFAULT_TRAIT_ACCESS, FIELD_REASSIGN_WITH_DEFAULT]);
72+
73+
impl LateLintPass<'_> for Default {
74+
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
75+
if_chain! {
76+
// Avoid cases already linted by `field_reassign_with_default`
77+
if !self.reassigned_linted.contains(&expr.span);
78+
if let ExprKind::Call(ref path, ..) = expr.kind;
79+
if !any_parent_is_automatically_derived(cx.tcx, expr.hir_id);
80+
if let ExprKind::Path(ref qpath) = path.kind;
81+
if let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id();
82+
if match_def_path(cx, def_id, &paths::DEFAULT_TRAIT_METHOD);
83+
// Detect and ignore <Foo as Default>::default() because these calls do explicitly name the type.
84+
if let QPath::Resolved(None, _path) = qpath;
85+
then {
86+
let expr_ty = cx.typeck_results().expr_ty(expr);
87+
if let ty::Adt(def, ..) = expr_ty.kind() {
88+
// TODO: Work out a way to put "whatever the imported way of referencing
89+
// this type in this file" rather than a fully-qualified type.
90+
let replacement = format!("{}::default()", cx.tcx.def_path_str(def.did));
91+
span_lint_and_sugg(
92+
cx,
93+
DEFAULT_TRAIT_ACCESS,
94+
expr.span,
95+
&format!("calling `{}` is more clear than this expression", replacement),
96+
"try",
97+
replacement,
98+
Applicability::Unspecified, // First resolve the TODO above
99+
);
100+
}
101+
}
102+
}
103+
}
40104

41-
impl LateLintPass<'_> for FieldReassignWithDefault {
42105
fn check_block<'tcx>(&mut self, cx: &LateContext<'tcx>, block: &Block<'tcx>) {
43106
// find all binding statements like `let mut _ = T::default()` where `T::default()` is the
44107
// `default` method of the `Default` trait, and store statement index in current block being
@@ -47,7 +110,7 @@ impl LateLintPass<'_> for FieldReassignWithDefault {
47110

48111
// start from the `let mut _ = _::default();` and look at all the following
49112
// statements, see if they re-assign the fields of the binding
50-
for (stmt_idx, binding_name, binding_type) in binding_statements_using_default {
113+
for (stmt_idx, binding_name, binding_type, span) in binding_statements_using_default {
51114
// the last statement of a block cannot trigger the lint
52115
if stmt_idx == block.stmts.len() - 1 {
53116
break;
@@ -145,6 +208,7 @@ impl LateLintPass<'_> for FieldReassignWithDefault {
145208
sugg
146209
),
147210
);
211+
self.reassigned_linted.insert(span);
148212
}
149213
}
150214
}
@@ -171,7 +235,7 @@ fn is_expr_default<'tcx>(expr: &'tcx Expr<'tcx>, cx: &LateContext<'tcx>) -> bool
171235
fn enumerate_bindings_using_default<'tcx>(
172236
cx: &LateContext<'tcx>,
173237
block: &Block<'tcx>,
174-
) -> Vec<(usize, Symbol, Ty<'tcx>)> {
238+
) -> Vec<(usize, Symbol, Ty<'tcx>, Span)> {
175239
block
176240
.stmts
177241
.iter()
@@ -189,7 +253,7 @@ fn enumerate_bindings_using_default<'tcx>(
189253
if let Some(ref expr) = local.init;
190254
if is_expr_default(expr, cx);
191255
then {
192-
Some((idx, ident.name, ty))
256+
Some((idx, ident.name, ty, expr.span))
193257
} else {
194258
None
195259
}

clippy_lints/src/default_trait_access.rs

-62
This file was deleted.

clippy_lints/src/lib.rs

+7-9
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,7 @@ mod copies;
175175
mod copy_iterator;
176176
mod create_dir;
177177
mod dbg_macro;
178-
mod default_trait_access;
178+
mod default;
179179
mod dereference;
180180
mod derive;
181181
mod disallowed_method;
@@ -198,7 +198,6 @@ mod excessive_bools;
198198
mod exit;
199199
mod explicit_write;
200200
mod fallible_impl_from;
201-
mod field_reassign_with_default;
202201
mod float_equality_without_abs;
203202
mod float_literal;
204203
mod floating_point_arithmetic;
@@ -537,7 +536,8 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
537536
&copy_iterator::COPY_ITERATOR,
538537
&create_dir::CREATE_DIR,
539538
&dbg_macro::DBG_MACRO,
540-
&default_trait_access::DEFAULT_TRAIT_ACCESS,
539+
&default::DEFAULT_TRAIT_ACCESS,
540+
&default::FIELD_REASSIGN_WITH_DEFAULT,
541541
&dereference::EXPLICIT_DEREF_METHODS,
542542
&derive::DERIVE_HASH_XOR_EQ,
543543
&derive::DERIVE_ORD_XOR_PARTIAL_ORD,
@@ -576,7 +576,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
576576
&exit::EXIT,
577577
&explicit_write::EXPLICIT_WRITE,
578578
&fallible_impl_from::FALLIBLE_IMPL_FROM,
579-
&field_reassign_with_default::FIELD_REASSIGN_WITH_DEFAULT,
580579
&float_equality_without_abs::FLOAT_EQUALITY_WITHOUT_ABS,
581580
&float_literal::EXCESSIVE_PRECISION,
582581
&float_literal::LOSSY_FLOAT_LITERAL,
@@ -1050,7 +1049,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
10501049
store.register_late_pass(|| box neg_cmp_op_on_partial_ord::NoNegCompOpForPartialOrd);
10511050
store.register_late_pass(|| box unwrap::Unwrap);
10521051
store.register_late_pass(|| box duration_subsec::DurationSubsec);
1053-
store.register_late_pass(|| box default_trait_access::DefaultTraitAccess);
10541052
store.register_late_pass(|| box indexing_slicing::IndexingSlicing);
10551053
store.register_late_pass(|| box non_copy_const::NonCopyConst);
10561054
store.register_late_pass(|| box ptr_offset_with_cast::PtrOffsetWithCast);
@@ -1101,7 +1099,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
11011099
let enum_variant_name_threshold = conf.enum_variant_name_threshold;
11021100
store.register_early_pass(move || box enum_variants::EnumVariantNames::new(enum_variant_name_threshold));
11031101
store.register_early_pass(|| box tabs_in_doc_comments::TabsInDocComments);
1104-
store.register_late_pass(|| box field_reassign_with_default::FieldReassignWithDefault);
1102+
store.register_late_pass(|| box default::Default::default());
11051103
store.register_late_pass(|| box unused_self::UnusedSelf);
11061104
store.register_late_pass(|| box mutable_debug_assertion::DebugAssertWithMutCall);
11071105
store.register_late_pass(|| box exit::Exit);
@@ -1214,7 +1212,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
12141212
LintId::of(&checked_conversions::CHECKED_CONVERSIONS),
12151213
LintId::of(&copies::SAME_FUNCTIONS_IN_IF_CONDITION),
12161214
LintId::of(&copy_iterator::COPY_ITERATOR),
1217-
LintId::of(&default_trait_access::DEFAULT_TRAIT_ACCESS),
1215+
LintId::of(&default::DEFAULT_TRAIT_ACCESS),
12181216
LintId::of(&dereference::EXPLICIT_DEREF_METHODS),
12191217
LintId::of(&derive::EXPL_IMPL_CLONE_ON_COPY),
12201218
LintId::of(&derive::UNSAFE_DERIVE_DESERIALIZE),
@@ -1323,6 +1321,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
13231321
LintId::of(&comparison_chain::COMPARISON_CHAIN),
13241322
LintId::of(&copies::IFS_SAME_COND),
13251323
LintId::of(&copies::IF_SAME_THEN_ELSE),
1324+
LintId::of(&default::FIELD_REASSIGN_WITH_DEFAULT),
13261325
LintId::of(&derive::DERIVE_HASH_XOR_EQ),
13271326
LintId::of(&derive::DERIVE_ORD_XOR_PARTIAL_ORD),
13281327
LintId::of(&doc::MISSING_SAFETY_DOC),
@@ -1346,7 +1345,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
13461345
LintId::of(&eval_order_dependence::DIVERGING_SUB_EXPRESSION),
13471346
LintId::of(&eval_order_dependence::EVAL_ORDER_DEPENDENCE),
13481347
LintId::of(&explicit_write::EXPLICIT_WRITE),
1349-
LintId::of(&field_reassign_with_default::FIELD_REASSIGN_WITH_DEFAULT),
13501348
LintId::of(&float_equality_without_abs::FLOAT_EQUALITY_WITHOUT_ABS),
13511349
LintId::of(&float_literal::EXCESSIVE_PRECISION),
13521350
LintId::of(&format::USELESS_FORMAT),
@@ -1584,13 +1582,13 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
15841582
LintId::of(&blocks_in_if_conditions::BLOCKS_IN_IF_CONDITIONS),
15851583
LintId::of(&collapsible_if::COLLAPSIBLE_IF),
15861584
LintId::of(&comparison_chain::COMPARISON_CHAIN),
1585+
LintId::of(&default::FIELD_REASSIGN_WITH_DEFAULT),
15871586
LintId::of(&doc::MISSING_SAFETY_DOC),
15881587
LintId::of(&doc::NEEDLESS_DOCTEST_MAIN),
15891588
LintId::of(&enum_variants::ENUM_VARIANT_NAMES),
15901589
LintId::of(&enum_variants::MODULE_INCEPTION),
15911590
LintId::of(&eq_op::OP_REF),
15921591
LintId::of(&eta_reduction::REDUNDANT_CLOSURE),
1593-
LintId::of(&field_reassign_with_default::FIELD_REASSIGN_WITH_DEFAULT),
15941592
LintId::of(&float_literal::EXCESSIVE_PRECISION),
15951593
LintId::of(&formatting::SUSPICIOUS_ASSIGNMENT_FORMATTING),
15961594
LintId::of(&formatting::SUSPICIOUS_ELSE_FORMATTING),

src/lintlist/mod.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -359,7 +359,7 @@ vec![
359359
group: "pedantic",
360360
desc: "checks for literal calls to `Default::default()`",
361361
deprecation: None,
362-
module: "default_trait_access",
362+
module: "default",
363363
},
364364
Lint {
365365
name: "deprecated_cfg_attr",
@@ -632,7 +632,7 @@ vec![
632632
group: "style",
633633
desc: "binding initialized with Default should have its fields set in the initializer",
634634
deprecation: None,
635-
module: "field_reassign_with_default",
635+
module: "default",
636636
},
637637
Lint {
638638
name: "filetype_is_file",

0 commit comments

Comments
 (0)