about summary refs log tree commit diff
diff options
context:
space:
mode:
authorAndrew Houts <ahouts4@gmail.com>2020-12-17 21:09:55 -0600
committerAndrew Houts <ahouts4@gmail.com>2020-12-17 21:28:16 -0600
commit1eb7608a2e7284eff2d0ba80705f1cf28a1117e5 (patch)
tree1fcffdbb3a7ef81b0b7df681fbc4c2896eee4e81
parent5c00931642357c835d5ba292d8c642ef7389021b (diff)
downloadrust-1eb7608a2e7284eff2d0ba80705f1cf28a1117e5.tar.gz
rust-1eb7608a2e7284eff2d0ba80705f1cf28a1117e5.zip
make needless_update ignore non_exhaustive structs
-rw-r--r--clippy_lints/src/needless_update.rs21
-rw-r--r--tests/ui/needless_update.rs11
-rw-r--r--tests/ui/needless_update.stderr2
3 files changed, 31 insertions, 3 deletions
diff --git a/clippy_lints/src/needless_update.rs b/clippy_lints/src/needless_update.rs
index 98e9078094a..1e387b518c3 100644
--- a/clippy_lints/src/needless_update.rs
+++ b/clippy_lints/src/needless_update.rs
@@ -21,7 +21,14 @@ declare_clippy_lint! {
     /// #     z: i32,
     /// # }
     /// # let zero_point = Point { x: 0, y: 0, z: 0 };
-    ///
+    /// #
+    /// # #[non_exhaustive]
+    /// # struct Options {
+    /// #     a: bool,
+    /// #     b: i32,
+    /// # }
+    /// # let default_options = Options { a: false, b: 0 };
+    /// #
     /// // Bad
     /// Point {
     ///     x: 1,
@@ -36,6 +43,14 @@ declare_clippy_lint! {
     ///     y: 1,
     ///     ..zero_point
     /// };
+    ///
+    /// // this lint is not applied to structs marked with [non_exhaustive](https://doc.rust-lang.org/reference/attributes/type_system.html)
+    /// // Ok
+    /// Options {
+    ///     a: true,
+    ///     b: 321,
+    ///     ..default_options
+    ///  };
     /// ```
     pub NEEDLESS_UPDATE,
     complexity,
@@ -49,7 +64,9 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessUpdate {
         if let ExprKind::Struct(_, ref fields, Some(ref base)) = expr.kind {
             let ty = cx.typeck_results().expr_ty(expr);
             if let ty::Adt(def, _) = ty.kind() {
-                if fields.len() == def.non_enum_variant().fields.len() {
+                if fields.len() == def.non_enum_variant().fields.len()
+                    && !def.variants[0_usize.into()].is_field_list_non_exhaustive()
+                {
                     span_lint(
                         cx,
                         NEEDLESS_UPDATE,
diff --git a/tests/ui/needless_update.rs b/tests/ui/needless_update.rs
index bfa005a19f9..b93ff048a62 100644
--- a/tests/ui/needless_update.rs
+++ b/tests/ui/needless_update.rs
@@ -6,9 +6,20 @@ struct S {
     pub b: i32,
 }
 
+#[non_exhaustive]
+struct T {
+    pub x: i32,
+    pub y: i32,
+}
+
 fn main() {
     let base = S { a: 0, b: 0 };
     S { ..base }; // no error
     S { a: 1, ..base }; // no error
     S { a: 1, b: 1, ..base };
+
+    let base = T { x: 0, y: 0 };
+    T { ..base }; // no error
+    T { x: 1, ..base }; // no error
+    T { x: 1, y: 1, ..base }; // no error
 }
diff --git a/tests/ui/needless_update.stderr b/tests/ui/needless_update.stderr
index 133c834880d..b154b3b306d 100644
--- a/tests/ui/needless_update.stderr
+++ b/tests/ui/needless_update.stderr
@@ -1,5 +1,5 @@
 error: struct update has no effect, all the fields in the struct have already been specified
-  --> $DIR/needless_update.rs:13:23
+  --> $DIR/needless_update.rs:19:23
    |
 LL |     S { a: 1, b: 1, ..base };
    |                       ^^^^