Skip use_self inside macro expansions of a impl Self block (#13128)

changelog: [`use_self`] Skip if inside macro expansions of a `impl Self`
block
Fixes #13092.
r? Alexendoo
This commit is contained in:
Alex Macleod 2025-02-06 14:43:39 +00:00 committed by GitHub
commit 20b2461938
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 120 additions and 39 deletions

View file

@ -2,7 +2,7 @@ use clippy_config::Conf;
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::is_from_proc_macro;
use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::ty::same_type_and_consts;
use clippy_utils::ty::{same_type_and_consts, ty_from_hir_ty};
use rustc_data_structures::fx::FxHashSet;
use rustc_errors::Applicability;
use rustc_hir::def::{CtorOf, DefKind, Res};
@ -12,7 +12,6 @@ use rustc_hir::{
self as hir, AmbigArg, Expr, ExprKind, FnRetTy, FnSig, GenericArgsParentheses, GenericParam, GenericParamKind,
HirId, Impl, ImplItemKind, Item, ItemKind, Pat, PatExpr, PatExprKind, PatKind, Path, QPath, Ty, TyKind,
};
use rustc_hir_analysis::lower_ty;
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::Ty as MiddleTy;
use rustc_session::impl_lint_pass;
@ -73,7 +72,6 @@ impl UseSelf {
enum StackItem {
Check {
impl_id: LocalDefId,
in_body: u32,
types_to_skip: FxHashSet<HirId>,
},
NoCheck,
@ -96,8 +94,8 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf {
.as_ref()
.is_none_or(|params| params.parenthesized == GenericArgsParentheses::No)
&& !item.span.from_expansion()
// expensive, should be last check
&& !is_from_proc_macro(cx, item)
// expensive, should be last check
{
// Self cannot be used inside const generic parameters
let types_to_skip = generics
@ -117,7 +115,6 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf {
.collect();
StackItem::Check {
impl_id: item.owner_id.def_id,
in_body: 0,
types_to_skip,
}
} else {
@ -131,6 +128,11 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf {
}
fn check_impl_item(&mut self, cx: &LateContext<'_>, impl_item: &hir::ImplItem<'_>) {
// Checking items of `impl Self` blocks in which macro expands into.
if impl_item.span.from_expansion() {
self.stack.push(StackItem::NoCheck);
return;
}
// We want to skip types in trait `impl`s that aren't declared as `Self` in the trait
// declaration. The collection of those types is all this method implementation does.
if let ImplItemKind::Fn(FnSig { decl, .. }, ..) = impl_item.kind
@ -186,18 +188,11 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf {
}
}
fn check_body(&mut self, _: &LateContext<'_>, _: &hir::Body<'_>) {
// `lower_ty` cannot be called in `Body`s or it will panic (sometimes). But in bodies
// we can use `cx.typeck_results.node_type(..)` to get the `ty::Ty` from a `hir::Ty`.
// However the `node_type()` method can *only* be called in bodies.
if let Some(&mut StackItem::Check { ref mut in_body, .. }) = self.stack.last_mut() {
*in_body = in_body.saturating_add(1);
}
}
fn check_body_post(&mut self, _: &LateContext<'_>, _: &hir::Body<'_>) {
if let Some(&mut StackItem::Check { ref mut in_body, .. }) = self.stack.last_mut() {
*in_body = in_body.saturating_sub(1);
fn check_impl_item_post(&mut self, _: &LateContext<'_>, impl_item: &hir::ImplItem<'_>) {
if impl_item.span.from_expansion()
&& let Some(StackItem::NoCheck) = self.stack.last()
{
self.stack.pop();
}
}
@ -206,7 +201,6 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf {
&& self.msrv.meets(msrvs::TYPE_ALIAS_ENUM_VARIANTS)
&& let Some(&StackItem::Check {
impl_id,
in_body,
ref types_to_skip,
}) = self.stack.last()
&& let TyKind::Path(QPath::Resolved(_, path)) = hir_ty.kind
@ -215,12 +209,7 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf {
Res::SelfTyParam { .. } | Res::SelfTyAlias { .. } | Res::Def(DefKind::TyParam, _)
)
&& !types_to_skip.contains(&hir_ty.hir_id)
&& let ty = if in_body > 0 {
cx.typeck_results().node_type(hir_ty.hir_id)
} else {
// We don't care about ignoring infer vars here
lower_ty(cx.tcx, hir_ty.as_unambig_ty())
}
&& let ty = ty_from_hir_ty(cx, hir_ty.as_unambig_ty())
&& let impl_ty = cx.tcx.type_of(impl_id).instantiate_identity()
&& same_type_and_consts(ty, impl_ty)
// Ensure the type we encounter and the one from the impl have the same lifetime parameters. It may be that

View file

@ -1,10 +1,9 @@
use clippy_utils::diagnostics::span_lint_and_help;
use clippy_utils::ty::{is_normalizable, is_type_diagnostic_item};
use clippy_utils::ty::{is_normalizable, is_type_diagnostic_item, ty_from_hir_ty};
use rustc_hir::{self as hir, AmbigArg, HirId, ItemKind, Node};
use rustc_hir_analysis::lower_ty;
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::layout::LayoutOf as _;
use rustc_middle::ty::{self, Ty, TypeVisitableExt};
use rustc_middle::ty::{self, TypeVisitableExt};
use rustc_session::declare_lint_pass;
use rustc_span::sym;
@ -82,15 +81,3 @@ fn in_trait_impl(cx: &LateContext<'_>, hir_id: HirId) -> bool {
}
false
}
fn ty_from_hir_ty<'tcx>(cx: &LateContext<'tcx>, hir_ty: &hir::Ty<'tcx>) -> Ty<'tcx> {
cx.maybe_typeck_results()
.and_then(|results| {
if results.hir_owner == hir_ty.hir_id.owner {
results.node_type_opt(hir_ty.hir_id)
} else {
None
}
})
.unwrap_or_else(|| lower_ty(cx.tcx, hir_ty))
}