mirror of
https://github.com/rust-lang/rust.git
synced 2025-04-28 11:07:42 +00:00
Auto merge of #6553 - phansch:field-reassign-with-default-macros, r=flip1995
Fix derive and macro related false positives in `field_reassign_with_default` Closes #6545 changelog: Fix derive and macro related false positives in [`field_reassign_with_default`]
This commit is contained in:
commit
efccfe80e4
@ -8,6 +8,7 @@ use rustc_errors::Applicability;
|
|||||||
use rustc_hir::def::Res;
|
use rustc_hir::def::Res;
|
||||||
use rustc_hir::{Block, Expr, ExprKind, PatKind, QPath, Stmt, StmtKind};
|
use rustc_hir::{Block, Expr, ExprKind, PatKind, QPath, Stmt, StmtKind};
|
||||||
use rustc_lint::{LateContext, LateLintPass};
|
use rustc_lint::{LateContext, LateLintPass};
|
||||||
|
use rustc_middle::lint::in_external_macro;
|
||||||
use rustc_middle::ty;
|
use rustc_middle::ty;
|
||||||
use rustc_session::{declare_tool_lint, impl_lint_pass};
|
use rustc_session::{declare_tool_lint, impl_lint_pass};
|
||||||
use rustc_span::symbol::{Ident, Symbol};
|
use rustc_span::symbol::{Ident, Symbol};
|
||||||
@ -120,6 +121,8 @@ impl LateLintPass<'_> for Default {
|
|||||||
// only take `let ...` statements
|
// only take `let ...` statements
|
||||||
if let StmtKind::Local(local) = stmt.kind;
|
if let StmtKind::Local(local) = stmt.kind;
|
||||||
if let Some(expr) = local.init;
|
if let Some(expr) = local.init;
|
||||||
|
if !any_parent_is_automatically_derived(cx.tcx, expr.hir_id);
|
||||||
|
if !in_external_macro(cx.tcx.sess, expr.span);
|
||||||
// only take bindings to identifiers
|
// only take bindings to identifiers
|
||||||
if let PatKind::Binding(_, binding_id, ident, _) = local.pat.kind;
|
if let PatKind::Binding(_, binding_id, ident, _) = local.pat.kind;
|
||||||
// only when assigning `... = Default::default()`
|
// only when assigning `... = Default::default()`
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
//!
|
//!
|
||||||
//! This lint is **warn** by default
|
//! This lint is **warn** by default
|
||||||
|
|
||||||
use crate::utils::{snippet_opt, span_lint_and_then};
|
use crate::utils::{is_automatically_derived, snippet_opt, span_lint_and_then};
|
||||||
use if_chain::if_chain;
|
use if_chain::if_chain;
|
||||||
use rustc_errors::Applicability;
|
use rustc_errors::Applicability;
|
||||||
use rustc_hir::{BindingAnnotation, BorrowKind, Expr, ExprKind, HirId, Item, Mutability, Pat, PatKind};
|
use rustc_hir::{BindingAnnotation, BorrowKind, Expr, ExprKind, HirId, Item, Mutability, Pat, PatKind};
|
||||||
@ -10,7 +10,6 @@ use rustc_lint::{LateContext, LateLintPass};
|
|||||||
use rustc_middle::ty;
|
use rustc_middle::ty;
|
||||||
use rustc_middle::ty::adjustment::{Adjust, Adjustment};
|
use rustc_middle::ty::adjustment::{Adjust, Adjustment};
|
||||||
use rustc_session::{declare_tool_lint, impl_lint_pass};
|
use rustc_session::{declare_tool_lint, impl_lint_pass};
|
||||||
use rustc_span::sym;
|
|
||||||
|
|
||||||
declare_clippy_lint! {
|
declare_clippy_lint! {
|
||||||
/// **What it does:** Checks for address of operations (`&`) that are going to
|
/// **What it does:** Checks for address of operations (`&`) that are going to
|
||||||
@ -116,7 +115,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessBorrow {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn check_item(&mut self, _: &LateContext<'tcx>, item: &'tcx Item<'_>) {
|
fn check_item(&mut self, _: &LateContext<'tcx>, item: &'tcx Item<'_>) {
|
||||||
if item.attrs.iter().any(|a| a.has_name(sym::automatically_derived)) {
|
if is_automatically_derived(item.attrs) {
|
||||||
debug_assert!(self.derived_item.is_none());
|
debug_assert!(self.derived_item.is_none());
|
||||||
self.derived_item = Some(item.hir_id);
|
self.derived_item = Some(item.hir_id);
|
||||||
}
|
}
|
||||||
|
@ -94,3 +94,19 @@ macro_rules! large_enum_variant {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! field_reassign_with_default {
|
||||||
|
() => {
|
||||||
|
#[derive(Default)]
|
||||||
|
struct A {
|
||||||
|
pub i: i32,
|
||||||
|
pub j: i64,
|
||||||
|
}
|
||||||
|
fn lint() {
|
||||||
|
let mut a: A = Default::default();
|
||||||
|
a.i = 42;
|
||||||
|
a;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
#![crate_type = "proc-macro"]
|
#![crate_type = "proc-macro"]
|
||||||
#![feature(repr128, proc_macro_quote)]
|
#![feature(repr128, proc_macro_quote)]
|
||||||
#![allow(incomplete_features)]
|
#![allow(incomplete_features)]
|
||||||
|
#![allow(clippy::field_reassign_with_default)]
|
||||||
#![allow(clippy::eq_op)]
|
#![allow(clippy::eq_op)]
|
||||||
|
|
||||||
extern crate proc_macro;
|
extern crate proc_macro;
|
||||||
@ -23,3 +24,20 @@ pub fn derive(_: TokenStream) -> TokenStream {
|
|||||||
};
|
};
|
||||||
output
|
output
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[proc_macro_derive(FieldReassignWithDefault)]
|
||||||
|
pub fn derive_foo(_input: TokenStream) -> TokenStream {
|
||||||
|
quote! {
|
||||||
|
#[derive(Default)]
|
||||||
|
struct A {
|
||||||
|
pub i: i32,
|
||||||
|
pub j: i64,
|
||||||
|
}
|
||||||
|
#[automatically_derived]
|
||||||
|
fn lint() {
|
||||||
|
let mut a: A = Default::default();
|
||||||
|
a.i = 42;
|
||||||
|
a;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,5 +1,18 @@
|
|||||||
|
// aux-build:proc_macro_derive.rs
|
||||||
|
// aux-build:macro_rules.rs
|
||||||
|
|
||||||
#![warn(clippy::field_reassign_with_default)]
|
#![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)]
|
#[derive(Default)]
|
||||||
struct A {
|
struct A {
|
||||||
i: i32,
|
i: i32,
|
||||||
@ -120,6 +133,9 @@ fn main() {
|
|||||||
// don't expand macros in the suggestion (#6522)
|
// don't expand macros in the suggestion (#6522)
|
||||||
let mut a: C = C::default();
|
let mut a: C = C::default();
|
||||||
a.i = vec![1];
|
a.i = vec![1];
|
||||||
|
|
||||||
|
// Don't lint in external macros
|
||||||
|
field_reassign_with_default!();
|
||||||
}
|
}
|
||||||
|
|
||||||
mod m {
|
mod m {
|
||||||
|
@ -1,84 +1,84 @@
|
|||||||
error: field assignment outside of initializer for an instance created with Default::default()
|
error: field assignment outside of initializer for an instance created with Default::default()
|
||||||
--> $DIR/field_reassign_with_default.rs:35:5
|
--> $DIR/field_reassign_with_default.rs:48:5
|
||||||
|
|
|
|
||||||
LL | a.i = 42;
|
LL | a.i = 42;
|
||||||
| ^^^^^^^^^
|
| ^^^^^^^^^
|
||||||
|
|
|
|
||||||
= note: `-D clippy::field-reassign-with-default` implied by `-D warnings`
|
= note: `-D clippy::field-reassign-with-default` implied by `-D warnings`
|
||||||
note: consider initializing the variable with `A { i: 42, ..Default::default() }` and removing relevant reassignments
|
note: consider initializing the variable with `main::A { i: 42, ..Default::default() }` and removing relevant reassignments
|
||||||
--> $DIR/field_reassign_with_default.rs:34:5
|
--> $DIR/field_reassign_with_default.rs:47:5
|
||||||
|
|
|
|
||||||
LL | let mut a: A = Default::default();
|
LL | let mut a: A = Default::default();
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: field assignment outside of initializer for an instance created with Default::default()
|
error: field assignment outside of initializer for an instance created with Default::default()
|
||||||
--> $DIR/field_reassign_with_default.rs:75:5
|
--> $DIR/field_reassign_with_default.rs:88:5
|
||||||
|
|
|
|
||||||
LL | a.j = 43;
|
LL | a.j = 43;
|
||||||
| ^^^^^^^^^
|
| ^^^^^^^^^
|
||||||
|
|
|
|
||||||
note: consider initializing the variable with `A { j: 43, i: 42 }` and removing relevant reassignments
|
note: consider initializing the variable with `main::A { j: 43, i: 42 }` and removing relevant reassignments
|
||||||
--> $DIR/field_reassign_with_default.rs:74:5
|
--> $DIR/field_reassign_with_default.rs:87:5
|
||||||
|
|
|
|
||||||
LL | let mut a: A = Default::default();
|
LL | let mut a: A = Default::default();
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: field assignment outside of initializer for an instance created with Default::default()
|
error: field assignment outside of initializer for an instance created with Default::default()
|
||||||
--> $DIR/field_reassign_with_default.rs:80:5
|
--> $DIR/field_reassign_with_default.rs:93:5
|
||||||
|
|
|
|
||||||
LL | a.i = 42;
|
LL | a.i = 42;
|
||||||
| ^^^^^^^^^
|
| ^^^^^^^^^
|
||||||
|
|
|
|
||||||
note: consider initializing the variable with `A { i: 42, j: 44 }` and removing relevant reassignments
|
note: consider initializing the variable with `main::A { i: 42, j: 44 }` and removing relevant reassignments
|
||||||
--> $DIR/field_reassign_with_default.rs:79:5
|
--> $DIR/field_reassign_with_default.rs:92:5
|
||||||
|
|
|
|
||||||
LL | let mut a: A = Default::default();
|
LL | let mut a: A = Default::default();
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: field assignment outside of initializer for an instance created with Default::default()
|
error: field assignment outside of initializer for an instance created with Default::default()
|
||||||
--> $DIR/field_reassign_with_default.rs:86:5
|
--> $DIR/field_reassign_with_default.rs:99:5
|
||||||
|
|
|
|
||||||
LL | a.i = 42;
|
LL | a.i = 42;
|
||||||
| ^^^^^^^^^
|
| ^^^^^^^^^
|
||||||
|
|
|
|
||||||
note: consider initializing the variable with `A { i: 42, ..Default::default() }` and removing relevant reassignments
|
note: consider initializing the variable with `main::A { i: 42, ..Default::default() }` and removing relevant reassignments
|
||||||
--> $DIR/field_reassign_with_default.rs:85:5
|
--> $DIR/field_reassign_with_default.rs:98:5
|
||||||
|
|
|
|
||||||
LL | let mut a = A::default();
|
LL | let mut a = A::default();
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: field assignment outside of initializer for an instance created with Default::default()
|
error: field assignment outside of initializer for an instance created with Default::default()
|
||||||
--> $DIR/field_reassign_with_default.rs:96:5
|
--> $DIR/field_reassign_with_default.rs:109:5
|
||||||
|
|
|
|
||||||
LL | a.i = Default::default();
|
LL | a.i = Default::default();
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
|
||||||
note: consider initializing the variable with `A { i: Default::default(), ..Default::default() }` and removing relevant reassignments
|
note: consider initializing the variable with `main::A { i: Default::default(), ..Default::default() }` and removing relevant reassignments
|
||||||
--> $DIR/field_reassign_with_default.rs:95:5
|
--> $DIR/field_reassign_with_default.rs:108:5
|
||||||
|
|
|
|
||||||
LL | let mut a: A = Default::default();
|
LL | let mut a: A = Default::default();
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: field assignment outside of initializer for an instance created with Default::default()
|
error: field assignment outside of initializer for an instance created with Default::default()
|
||||||
--> $DIR/field_reassign_with_default.rs:100:5
|
--> $DIR/field_reassign_with_default.rs:113:5
|
||||||
|
|
|
|
||||||
LL | a.i = Default::default();
|
LL | a.i = Default::default();
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
|
||||||
note: consider initializing the variable with `A { i: Default::default(), j: 45 }` and removing relevant reassignments
|
note: consider initializing the variable with `main::A { i: Default::default(), j: 45 }` and removing relevant reassignments
|
||||||
--> $DIR/field_reassign_with_default.rs:99:5
|
--> $DIR/field_reassign_with_default.rs:112:5
|
||||||
|
|
|
|
||||||
LL | let mut a: A = Default::default();
|
LL | let mut a: A = Default::default();
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: field assignment outside of initializer for an instance created with Default::default()
|
error: field assignment outside of initializer for an instance created with Default::default()
|
||||||
--> $DIR/field_reassign_with_default.rs:122:5
|
--> $DIR/field_reassign_with_default.rs:135:5
|
||||||
|
|
|
|
||||||
LL | a.i = vec![1];
|
LL | a.i = vec![1];
|
||||||
| ^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^
|
||||||
|
|
|
|
||||||
note: consider initializing the variable with `C { i: vec![1], ..Default::default() }` and removing relevant reassignments
|
note: consider initializing the variable with `C { i: vec![1], ..Default::default() }` and removing relevant reassignments
|
||||||
--> $DIR/field_reassign_with_default.rs:121:5
|
--> $DIR/field_reassign_with_default.rs:134:5
|
||||||
|
|
|
|
||||||
LL | let mut a: C = C::default();
|
LL | let mut a: C = C::default();
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
Loading…
Reference in New Issue
Block a user