| //@aux-build:proc_macro_derive.rs |
| //@aux-build:proc_macros.rs |
| |
| #![warn(clippy::field_reassign_with_default)] |
| #![allow(clippy::assigning_clones)] |
| |
| #[macro_use] |
| extern crate proc_macro_derive; |
| extern crate proc_macros; |
| use proc_macros::{external, inline_macros}; |
| |
| // 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>, |
| } |
| |
| /// 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 |
| } |
| } |
| |
| #[inline_macros] |
| fn main() { |
| // wrong, produces first error in stderr |
| let mut a: A = Default::default(); |
| a.i = 42; |
| //~^ field_reassign_with_default |
| |
| // 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; |
| //~^ field_reassign_with_default |
| a.i = 42; |
| |
| // wrong, produces third error in stderr |
| let mut a: A = Default::default(); |
| a.i = 42; |
| //~^ field_reassign_with_default |
| a.j = 43; |
| a.j = 44; |
| |
| // wrong, produces fourth error in stderr |
| let mut a = A::default(); |
| a.i = 42; |
| //~^ field_reassign_with_default |
| |
| // 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(); |
| //~^ field_reassign_with_default |
| |
| // wrong, produces the sixth error in stderr |
| let mut a: A = Default::default(); |
| a.i = Default::default(); |
| //~^ field_reassign_with_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]; |
| //~^ field_reassign_with_default |
| |
| // Don't lint in external macros |
| external! { |
| #[derive(Default)] |
| struct A { |
| pub i: i32, |
| pub j: i64, |
| } |
| fn lint() { |
| let mut a: A = Default::default(); |
| a.i = 42; |
| a; |
| } |
| } |
| |
| // be sure suggestion is correct with generics |
| let mut a: Wrapper<bool> = Default::default(); |
| a.i = true; |
| //~^ field_reassign_with_default |
| |
| let mut a: WrapperMulti<i32, i64> = Default::default(); |
| a.i = 42; |
| //~^ field_reassign_with_default |
| |
| // Don't lint in macros |
| inline!( |
| let mut data = $crate::D::default(); |
| data.$a = Some($42); |
| data |
| ); |
| } |
| |
| 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::Arc; |
| use std::sync::atomic::AtomicBool; |
| |
| // 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(); |
| //~^ field_reassign_with_default |
| 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(); |
| //~^ field_reassign_with_default |
| f |
| } |
| } |
| } |
| |
| struct Collection { |
| items: Vec<i32>, |
| len: usize, |
| } |
| |
| impl Default for Collection { |
| fn default() -> Self { |
| Self { |
| items: vec![1, 2, 3], |
| len: 0, |
| } |
| } |
| } |
| |
| #[allow(clippy::redundant_closure_call)] |
| fn issue10136() { |
| let mut c = Collection::default(); |
| // don't lint, since c.items was used to calculate this value |
| c.len = (|| c.items.len())(); |
| } |