Auto merge of #13055 - Jarcho:auto_derive, r=Alexendoo

Only check for `automatically_derived` on impl blocks

This brings us in line with how rustc checks for the attribute. Also note that `unused_attributes` will trigger if it's placed anywhere else.

See:
9a21ac8e7e/compiler/rustc_passes/src/dead.rs (L400-L403)
9a21ac8e7e/compiler/rustc_passes/src/liveness.rs (L143-L148)

changelog: none
This commit is contained in:
bors 2024-07-06 12:01:28 +00:00
commit 0c9016aa1e
4 changed files with 25 additions and 14 deletions

View file

@ -1,7 +1,7 @@
use clippy_utils::diagnostics::{span_lint_and_note, span_lint_and_sugg}; use clippy_utils::diagnostics::{span_lint_and_note, span_lint_and_sugg};
use clippy_utils::source::snippet_with_context; use clippy_utils::source::snippet_with_context;
use clippy_utils::ty::{has_drop, is_copy}; use clippy_utils::ty::{has_drop, is_copy};
use clippy_utils::{any_parent_is_automatically_derived, contains_name, get_parent_expr, is_from_proc_macro}; use clippy_utils::{contains_name, get_parent_expr, in_automatically_derived, is_from_proc_macro};
use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::fx::FxHashSet;
use rustc_errors::Applicability; use rustc_errors::Applicability;
use rustc_hir::def::Res; use rustc_hir::def::Res;
@ -84,7 +84,7 @@ impl<'tcx> LateLintPass<'tcx> for Default {
// Avoid cases already linted by `field_reassign_with_default` // Avoid cases already linted by `field_reassign_with_default`
&& !self.reassigned_linted.contains(&expr.span) && !self.reassigned_linted.contains(&expr.span)
&& let ExprKind::Call(path, ..) = expr.kind && let ExprKind::Call(path, ..) = expr.kind
&& !any_parent_is_automatically_derived(cx.tcx, expr.hir_id) && !in_automatically_derived(cx.tcx, expr.hir_id)
&& let ExprKind::Path(ref qpath) = path.kind && let ExprKind::Path(ref qpath) = path.kind
&& let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id() && let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id()
&& cx.tcx.is_diagnostic_item(sym::default_fn, def_id) && cx.tcx.is_diagnostic_item(sym::default_fn, def_id)
@ -113,9 +113,9 @@ impl<'tcx> LateLintPass<'tcx> for Default {
// start from the `let mut _ = _::default();` and look at all the following // start from the `let mut _ = _::default();` and look at all the following
// statements, see if they re-assign the fields of the binding // statements, see if they re-assign the fields of the binding
let stmts_head = match block.stmts { let stmts_head = match block.stmts {
[] | [_] => return,
// Skip the last statement since there cannot possibly be any following statements that re-assign fields. // Skip the last statement since there cannot possibly be any following statements that re-assign fields.
[head @ .., _] if !head.is_empty() => head, [head @ .., _] => head,
_ => return,
}; };
for (stmt_idx, stmt) in stmts_head.iter().enumerate() { for (stmt_idx, stmt) in stmts_head.iter().enumerate() {
// find all binding statements like `let mut _ = T::default()` where `T::default()` is the // find all binding statements like `let mut _ = T::default()` where `T::default()` is the
@ -124,7 +124,7 @@ impl<'tcx> LateLintPass<'tcx> for Default {
let (local, variant, binding_name, binding_type, span) = if let StmtKind::Let(local) = stmt.kind let (local, variant, binding_name, binding_type, span) = if let StmtKind::Let(local) = stmt.kind
// only take `let ...` statements // only take `let ...` statements
&& let Some(expr) = local.init && let Some(expr) = local.init
&& !any_parent_is_automatically_derived(cx.tcx, expr.hir_id) && !in_automatically_derived(cx.tcx, expr.hir_id)
&& !expr.span.from_expansion() && !expr.span.from_expansion()
// only take bindings to identifiers // only take bindings to identifiers
&& let PatKind::Binding(_, binding_id, ident, _) = local.pat.kind && let PatKind::Binding(_, binding_id, ident, _) = local.pat.kind

View file

@ -2,8 +2,8 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_then, span_lint_hir_and
use clippy_utils::source::{snippet, snippet_with_context}; use clippy_utils::source::{snippet, snippet_with_context};
use clippy_utils::sugg::Sugg; use clippy_utils::sugg::Sugg;
use clippy_utils::{ use clippy_utils::{
any_parent_is_automatically_derived, fulfill_or_allowed, get_parent_expr, is_lint_allowed, iter_input_pats, fulfill_or_allowed, get_parent_expr, in_automatically_derived, is_lint_allowed, iter_input_pats, last_path_segment,
last_path_segment, SpanlessEq, SpanlessEq,
}; };
use rustc_errors::Applicability; use rustc_errors::Applicability;
use rustc_hir::def::Res; use rustc_hir::def::Res;
@ -206,7 +206,7 @@ impl<'tcx> LateLintPass<'tcx> for LintPass {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
if in_external_macro(cx.sess(), expr.span) if in_external_macro(cx.sess(), expr.span)
|| expr.span.desugaring_kind().is_some() || expr.span.desugaring_kind().is_some()
|| any_parent_is_automatically_derived(cx.tcx, expr.hir_id) || in_automatically_derived(cx.tcx, expr.hir_id)
{ {
return; return;
} }

View file

@ -2,7 +2,7 @@ use clippy_utils::diagnostics::{span_lint_hir, span_lint_hir_and_then};
use clippy_utils::source::snippet_opt; use clippy_utils::source::snippet_opt;
use clippy_utils::ty::has_drop; use clippy_utils::ty::has_drop;
use clippy_utils::{ use clippy_utils::{
any_parent_is_automatically_derived, is_inside_always_const_context, is_lint_allowed, path_to_local, peel_blocks, in_automatically_derived, is_inside_always_const_context, is_lint_allowed, path_to_local, peel_blocks,
}; };
use rustc_errors::Applicability; use rustc_errors::Applicability;
use rustc_hir::def::{DefKind, Res}; use rustc_hir::def::{DefKind, Res};
@ -187,7 +187,7 @@ impl NoEffect {
&& has_no_effect(cx, init) && has_no_effect(cx, init)
&& let PatKind::Binding(_, hir_id, ident, _) = local.pat.kind && let PatKind::Binding(_, hir_id, ident, _) = local.pat.kind
&& ident.name.to_ident_string().starts_with('_') && ident.name.to_ident_string().starts_with('_')
&& !any_parent_is_automatically_derived(cx.tcx, local.hir_id) && !in_automatically_derived(cx.tcx, local.hir_id)
{ {
if let Some(l) = self.local_bindings.last_mut() { if let Some(l) = self.local_bindings.last_mut() {
l.push(hir_id); l.push(hir_id);

View file

@ -103,8 +103,9 @@ use rustc_hir::LangItem::{OptionNone, OptionSome, ResultErr, ResultOk};
use rustc_hir::{ use rustc_hir::{
self as hir, def, Arm, ArrayLen, BindingMode, Block, BlockCheckMode, Body, ByRef, Closure, ConstContext, self as hir, def, Arm, ArrayLen, BindingMode, Block, BlockCheckMode, Body, ByRef, Closure, ConstContext,
Destination, Expr, ExprField, ExprKind, FnDecl, FnRetTy, GenericArgs, HirId, Impl, ImplItem, ImplItemKind, Destination, Expr, ExprField, ExprKind, FnDecl, FnRetTy, GenericArgs, HirId, Impl, ImplItem, ImplItemKind,
ImplItemRef, Item, ItemKind, LangItem, LetStmt, MatchSource, Mutability, Node, OwnerId, Param, Pat, PatKind, Path, ImplItemRef, Item, ItemKind, LangItem, LetStmt, MatchSource, Mutability, Node, OwnerId, OwnerNode, Param, Pat,
PathSegment, PrimTy, QPath, Stmt, StmtKind, TraitItem, TraitItemKind, TraitItemRef, TraitRef, TyKind, UnOp, PatKind, Path, PathSegment, PrimTy, QPath, Stmt, StmtKind, TraitItem, TraitItemKind, TraitItemRef, TraitRef,
TyKind, UnOp,
}; };
use rustc_lexer::{tokenize, TokenKind}; use rustc_lexer::{tokenize, TokenKind};
use rustc_lint::{LateContext, Level, Lint, LintContext}; use rustc_lint::{LateContext, Level, Lint, LintContext};
@ -1924,8 +1925,18 @@ pub fn any_parent_has_attr(tcx: TyCtxt<'_>, node: HirId, symbol: Symbol) -> bool
false false
} }
pub fn any_parent_is_automatically_derived(tcx: TyCtxt<'_>, node: HirId) -> bool { /// Checks if the given HIR node is inside an `impl` block with the `automatically_derived`
any_parent_has_attr(tcx, node, sym::automatically_derived) /// attribute.
pub fn in_automatically_derived(tcx: TyCtxt<'_>, id: HirId) -> bool {
tcx.hir()
.parent_owner_iter(id)
.filter(|(_, node)| matches!(node, OwnerNode::Item(item) if matches!(item.kind, ItemKind::Impl(_))))
.any(|(id, _)| {
has_attr(
tcx.hir().attrs(tcx.local_def_id_to_hir_id(id.def_id)),
sym::automatically_derived,
)
})
} }
/// Matches a function call with the given path and returns the arguments. /// Matches a function call with the given path and returns the arguments.