non_local_defs: suggest removing leading ref/ptr to make the impl local
This commit is contained in:
parent
ab23fd8dea
commit
b71952904d
6 changed files with 75 additions and 34 deletions
|
@ -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);
|
||||
|
|
|
@ -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.
|
||||
///
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue