non_local_defs: suggest removing leading ref/ptr to make the impl local

This commit is contained in:
Urgau 2024-05-15 14:55:40 +02:00
parent ab23fd8dea
commit b71952904d
6 changed files with 75 additions and 34 deletions

View file

@ -1338,6 +1338,7 @@ pub enum NonLocalDefinitionsDiag {
const_anon: Option<Option<Span>>,
move_help: Span,
may_move: Vec<Span>,
may_remove: Option<(Span, String)>,
has_trait: bool,
},
MacroRules {
@ -1361,6 +1362,7 @@ impl<'a> LintDiagnostic<'a, ()> for NonLocalDefinitionsDiag {
const_anon,
move_help,
may_move,
may_remove,
has_trait,
} => {
diag.primary_message(fluent::lint_non_local_definitions_impl);
@ -1379,7 +1381,17 @@ impl<'a> LintDiagnostic<'a, ()> for NonLocalDefinitionsDiag {
for sp in may_move {
ms.push_span_label(sp, fluent::lint_non_local_definitions_may_move);
}
diag.span_help(ms, fluent::lint_help);
diag.span_help(ms, fluent::lint_move_help);
if let Some((span, part)) = may_remove {
diag.arg("may_remove_part", part);
diag.span_suggestion(
span,
fluent::lint_remove_help,
"",
Applicability::MaybeIncorrect,
);
}
if let Some(cargo_update) = cargo_update {
diag.subdiagnostic(&diag.dcx, cargo_update);

View file

@ -136,35 +136,8 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions {
};
// Part 1: Is the Self type local?
let self_ty_has_local_parent = match impl_.self_ty.kind {
TyKind::Path(QPath::Resolved(_, ty_path)) => {
path_has_local_parent(ty_path, cx, parent, parent_parent)
}
TyKind::TraitObject([principle_poly_trait_ref, ..], _, _) => {
path_has_local_parent(
principle_poly_trait_ref.trait_ref.path,
cx,
parent,
parent_parent,
)
}
TyKind::TraitObject([], _, _)
| TyKind::InferDelegation(_, _)
| TyKind::Slice(_)
| TyKind::Array(_, _)
| TyKind::Ptr(_)
| TyKind::Ref(_, _)
| TyKind::BareFn(_)
| TyKind::Never
| TyKind::Tup(_)
| TyKind::Path(_)
| TyKind::Pat(..)
| TyKind::AnonAdt(_)
| TyKind::OpaqueDef(_, _, _)
| TyKind::Typeof(_)
| TyKind::Infer
| TyKind::Err(_) => false,
};
let self_ty_has_local_parent =
ty_has_local_parent(&impl_.self_ty.kind, cx, parent, parent_parent);
if self_ty_has_local_parent {
return;
@ -242,6 +215,18 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions {
let const_anon = matches!(parent_def_kind, DefKind::Const | DefKind::Static { .. })
.then_some(span_for_const_anon_suggestion);
let may_remove = match &impl_.self_ty.kind {
TyKind::Ptr(mut_ty) | TyKind::Ref(_, mut_ty)
if ty_has_local_parent(&mut_ty.ty.kind, cx, parent, parent_parent) =>
{
let type_ =
if matches!(impl_.self_ty.kind, TyKind::Ptr(_)) { "*" } else { "&" };
let part = format!("{}{}", type_, mut_ty.mutbl.prefix_str());
Some((impl_.self_ty.span.shrink_to_lo().until(mut_ty.ty.span), part))
}
_ => None,
};
cx.emit_span_lint(
NON_LOCAL_DEFINITIONS,
item.span.shrink_to_lo().to(impl_.self_ty.span),
@ -255,6 +240,7 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions {
cargo_update: cargo_update(),
const_anon,
may_move,
may_remove,
has_trait: impl_.of_trait.is_some(),
},
)
@ -384,6 +370,42 @@ impl<'tcx> Visitor<'tcx> for PathCollector<'tcx> {
}
}
/// Given a `Ty` we check if the (outermost) type is local.
fn ty_has_local_parent(
ty_kind: &TyKind<'_>,
cx: &LateContext<'_>,
impl_parent: DefId,
impl_parent_parent: Option<DefId>,
) -> bool {
match ty_kind {
TyKind::Path(QPath::Resolved(_, ty_path)) => {
path_has_local_parent(ty_path, cx, impl_parent, impl_parent_parent)
}
TyKind::TraitObject([principle_poly_trait_ref, ..], _, _) => path_has_local_parent(
principle_poly_trait_ref.trait_ref.path,
cx,
impl_parent,
impl_parent_parent,
),
TyKind::TraitObject([], _, _)
| TyKind::InferDelegation(_, _)
| TyKind::Slice(_)
| TyKind::Array(_, _)
| TyKind::Ptr(_)
| TyKind::Ref(_, _)
| TyKind::BareFn(_)
| TyKind::Never
| TyKind::Tup(_)
| TyKind::Path(_)
| TyKind::Pat(..)
| TyKind::AnonAdt(_)
| TyKind::OpaqueDef(_, _, _)
| TyKind::Typeof(_)
| TyKind::Infer
| TyKind::Err(_) => false,
}
}
/// Given a path and a parent impl def id, this checks if the if parent resolution
/// def id correspond to the def id of the parent impl definition.
///