summaryrefslogtreecommitdiffstats
path: root/src/tools/clippy/tests/ui/field_reassign_with_default.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/tools/clippy/tests/ui/field_reassign_with_default.rs')
-rw-r--r--src/tools/clippy/tests/ui/field_reassign_with_default.rs249
1 files changed, 249 insertions, 0 deletions
diff --git a/src/tools/clippy/tests/ui/field_reassign_with_default.rs b/src/tools/clippy/tests/ui/field_reassign_with_default.rs
new file mode 100644
index 000000000..7367910ea
--- /dev/null
+++ b/src/tools/clippy/tests/ui/field_reassign_with_default.rs
@@ -0,0 +1,249 @@
+// aux-build:proc_macro_derive.rs
+// aux-build:macro_rules.rs
+
+#![warn(clippy::field_reassign_with_default)]
+
+#[macro_use]
+extern crate proc_macro_derive;
+#[macro_use]
+extern crate macro_rules;
+
+// Don't lint on derives that derive `Default`
+// See https://github.com/rust-lang/rust-clippy/issues/6545
+#[derive(FieldReassignWithDefault)]
+struct DerivedStruct;
+
+#[derive(Default)]
+struct A {
+ i: i32,
+ j: i64,
+}
+
+struct B {
+ i: i32,
+ j: i64,
+}
+
+#[derive(Default)]
+struct C {
+ i: Vec<i32>,
+ j: i64,
+}
+
+#[derive(Default)]
+struct D {
+ a: Option<i32>,
+ b: Option<i32>,
+}
+
+macro_rules! m {
+ ($key:ident: $value:tt) => {{
+ let mut data = $crate::D::default();
+ data.$key = Some($value);
+ data
+ }};
+}
+
+/// Implements .next() that returns a different number each time.
+struct SideEffect(i32);
+
+impl SideEffect {
+ fn new() -> SideEffect {
+ SideEffect(0)
+ }
+ fn next(&mut self) -> i32 {
+ self.0 += 1;
+ self.0
+ }
+}
+
+fn main() {
+ // wrong, produces first error in stderr
+ let mut a: A = Default::default();
+ a.i = 42;
+
+ // right
+ let mut a: A = Default::default();
+
+ // right
+ let a = A {
+ i: 42,
+ ..Default::default()
+ };
+
+ // right
+ let mut a: A = Default::default();
+ if a.i == 0 {
+ a.j = 12;
+ }
+
+ // right
+ let mut a: A = Default::default();
+ let b = 5;
+
+ // right
+ let mut b = 32;
+ let mut a: A = Default::default();
+ b = 2;
+
+ // right
+ let b: B = B { i: 42, j: 24 };
+
+ // right
+ let mut b: B = B { i: 42, j: 24 };
+ b.i = 52;
+
+ // right
+ let mut b = B { i: 15, j: 16 };
+ let mut a: A = Default::default();
+ b.i = 2;
+
+ // wrong, produces second error in stderr
+ let mut a: A = Default::default();
+ a.j = 43;
+ a.i = 42;
+
+ // wrong, produces third error in stderr
+ let mut a: A = Default::default();
+ a.i = 42;
+ a.j = 43;
+ a.j = 44;
+
+ // wrong, produces fourth error in stderr
+ let mut a = A::default();
+ a.i = 42;
+
+ // wrong, but does not produce an error in stderr, because we can't produce a correct kind of
+ // suggestion with current implementation
+ let mut c: (i32, i32) = Default::default();
+ c.0 = 42;
+ c.1 = 21;
+
+ // wrong, produces the fifth error in stderr
+ let mut a: A = Default::default();
+ a.i = Default::default();
+
+ // wrong, produces the sixth error in stderr
+ let mut a: A = Default::default();
+ a.i = Default::default();
+ a.j = 45;
+
+ // right, because an assignment refers to another field
+ let mut x = A::default();
+ x.i = 42;
+ x.j = 21 + x.i as i64;
+
+ // right, we bail out if there's a reassignment to the same variable, since there is a risk of
+ // side-effects affecting the outcome
+ let mut x = A::default();
+ let mut side_effect = SideEffect::new();
+ x.i = side_effect.next();
+ x.j = 2;
+ x.i = side_effect.next();
+
+ // don't lint - some private fields
+ let mut x = m::F::default();
+ x.a = 1;
+
+ // don't expand macros in the suggestion (#6522)
+ let mut a: C = C::default();
+ a.i = vec![1];
+
+ // Don't lint in external macros
+ field_reassign_with_default!();
+
+ // be sure suggestion is correct with generics
+ let mut a: Wrapper<bool> = Default::default();
+ a.i = true;
+
+ let mut a: WrapperMulti<i32, i64> = Default::default();
+ a.i = 42;
+
+ // Don't lint in macros
+ m! {
+ a: 42
+ };
+}
+
+mod m {
+ #[derive(Default)]
+ pub struct F {
+ pub a: u64,
+ b: u64,
+ }
+}
+
+#[derive(Default)]
+struct Wrapper<T> {
+ i: T,
+}
+
+#[derive(Default)]
+struct WrapperMulti<T, U> {
+ i: T,
+ j: U,
+}
+
+mod issue6312 {
+ use std::sync::atomic::AtomicBool;
+ use std::sync::Arc;
+
+ // do not lint: type implements `Drop` but not all fields are `Copy`
+ #[derive(Clone, Default)]
+ pub struct ImplDropNotAllCopy {
+ name: String,
+ delay_data_sync: Arc<AtomicBool>,
+ }
+
+ impl Drop for ImplDropNotAllCopy {
+ fn drop(&mut self) {
+ self.close()
+ }
+ }
+
+ impl ImplDropNotAllCopy {
+ fn new(name: &str) -> Self {
+ let mut f = ImplDropNotAllCopy::default();
+ f.name = name.to_owned();
+ f
+ }
+ fn close(&self) {}
+ }
+
+ // lint: type implements `Drop` and all fields are `Copy`
+ #[derive(Clone, Default)]
+ pub struct ImplDropAllCopy {
+ name: usize,
+ delay_data_sync: bool,
+ }
+
+ impl Drop for ImplDropAllCopy {
+ fn drop(&mut self) {
+ self.close()
+ }
+ }
+
+ impl ImplDropAllCopy {
+ fn new(name: &str) -> Self {
+ let mut f = ImplDropAllCopy::default();
+ f.name = name.len();
+ f
+ }
+ fn close(&self) {}
+ }
+
+ // lint: type does not implement `Drop` though all fields are `Copy`
+ #[derive(Clone, Default)]
+ pub struct NoDropAllCopy {
+ name: usize,
+ delay_data_sync: bool,
+ }
+
+ impl NoDropAllCopy {
+ fn new(name: &str) -> Self {
+ let mut f = NoDropAllCopy::default();
+ f.name = name.len();
+ f
+ }
+ }
+}