From 504f3af70ea4cb2ce13f9272babb4e59b61fd88e Mon Sep 17 00:00:00 2001 From: Marcel Hellwig Date: Mon, 14 Feb 2022 13:22:36 +0100 Subject: [PATCH] Don't lint Default::default if it is the udpate syntax base An Update Syntax looks like this: Foo { a: 3, ..Default::default() } Don't lint `Default::default` here --- clippy_lints/src/default.rs | 16 +++++++++++++++- tests/ui/default_trait_access.fixed | 15 +++++++++++++-- tests/ui/default_trait_access.rs | 15 +++++++++++++-- 3 files changed, 41 insertions(+), 5 deletions(-) diff --git a/clippy_lints/src/default.rs b/clippy_lints/src/default.rs index 3070588483c2..06e6bf986c2a 100644 --- a/clippy_lints/src/default.rs +++ b/clippy_lints/src/default.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::{span_lint_and_note, span_lint_and_sugg}; use clippy_utils::source::snippet_with_macro_callsite; use clippy_utils::ty::{has_drop, is_copy}; -use clippy_utils::{any_parent_is_automatically_derived, contains_name, match_def_path, paths}; +use clippy_utils::{any_parent_is_automatically_derived, contains_name, get_parent_expr, match_def_path, paths}; use if_chain::if_chain; use rustc_data_structures::fx::FxHashSet; use rustc_errors::Applicability; @@ -88,6 +88,7 @@ impl<'tcx> LateLintPass<'tcx> for Default { if let ExprKind::Path(ref qpath) = path.kind; if let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id(); if match_def_path(cx, def_id, &paths::DEFAULT_TRAIT_METHOD); + if !is_update_syntax_base(cx, expr); // Detect and ignore ::default() because these calls do explicitly name the type. if let QPath::Resolved(None, _path) = qpath; let expr_ty = cx.typeck_results().expr_ty(expr); @@ -290,3 +291,16 @@ fn field_reassigned_by_stmt<'tcx>(this: &Stmt<'tcx>, binding_name: Symbol) -> Op } } } + +/// Returns whether `expr` is the update syntax base: `Foo { a: 1, .. base }` +fn is_update_syntax_base<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> bool { + if_chain! { + if let Some(parent) = get_parent_expr(cx, expr); + if let ExprKind::Struct(_, _, Some(base)) = parent.kind; + then { + base.hir_id == expr.hir_id + } else { + false + } + } +} diff --git a/tests/ui/default_trait_access.fixed b/tests/ui/default_trait_access.fixed index 9114d8754dcc..264dd4efaeb8 100644 --- a/tests/ui/default_trait_access.fixed +++ b/tests/ui/default_trait_access.fixed @@ -46,9 +46,14 @@ fn main() { let s19 = ::default(); + let s20 = UpdateSyntax { + s: "foo", + ..Default::default() + }; + println!( - "[{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}], [{:?}]", - s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, s11, s12, s13, s14, s15, s16, s17, s18, s19, + "[{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}]", + s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, s11, s12, s13, s14, s15, s16, s17, s18, s19, s20, ); } @@ -86,3 +91,9 @@ struct ArrayDerivedDefault { #[derive(Debug, Default)] struct TupleStructDerivedDefault(String); + +#[derive(Debug, Default)] +struct UpdateSyntax { + pub s: &'static str, + pub u: u64, +} diff --git a/tests/ui/default_trait_access.rs b/tests/ui/default_trait_access.rs index 8a5f0d6a7497..a0930fab8e7c 100644 --- a/tests/ui/default_trait_access.rs +++ b/tests/ui/default_trait_access.rs @@ -46,9 +46,14 @@ fn main() { let s19 = ::default(); + let s20 = UpdateSyntax { + s: "foo", + ..Default::default() + }; + println!( - "[{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}], [{:?}]", - s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, s11, s12, s13, s14, s15, s16, s17, s18, s19, + "[{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}]", + s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, s11, s12, s13, s14, s15, s16, s17, s18, s19, s20, ); } @@ -86,3 +91,9 @@ struct ArrayDerivedDefault { #[derive(Debug, Default)] struct TupleStructDerivedDefault(String); + +#[derive(Debug, Default)] +struct UpdateSyntax { + pub s: &'static str, + pub u: u64, +}