non_local_defs: point to Self and Trait to give more context
This commit is contained in:
parent
b71952904d
commit
98273ec612
15 changed files with 311 additions and 69 deletions
|
@ -13,6 +13,7 @@ rustc_errors = { path = "../rustc_errors" }
|
|||
rustc_feature = { path = "../rustc_feature" }
|
||||
rustc_fluent_macro = { path = "../rustc_fluent_macro" }
|
||||
rustc_hir = { path = "../rustc_hir" }
|
||||
rustc_hir_pretty = { path = "../rustc_hir_pretty" }
|
||||
rustc_index = { path = "../rustc_index" }
|
||||
rustc_infer = { path = "../rustc_infer" }
|
||||
rustc_macros = { path = "../rustc_macros" }
|
||||
|
|
|
@ -567,6 +567,10 @@ lint_non_local_definitions_macro_rules = non-local `macro_rules!` definition, `#
|
|||
|
||||
lint_non_local_definitions_may_move = may need to be moved as well
|
||||
|
||||
lint_non_local_definitions_of_trait_not_local = `{$of_trait_str}` is not local
|
||||
|
||||
lint_non_local_definitions_self_ty_not_local = `{$self_ty_str}` is not local
|
||||
|
||||
lint_non_snake_case = {$sort} `{$name}` should have a snake case name
|
||||
.rename_or_convert_suggestion = rename the identifier or convert it to a snake case raw identifier
|
||||
.cannot_convert_note = `{$sc}` cannot be used as a raw identifier
|
||||
|
|
|
@ -1340,6 +1340,8 @@ pub enum NonLocalDefinitionsDiag {
|
|||
may_move: Vec<Span>,
|
||||
may_remove: Option<(Span, String)>,
|
||||
has_trait: bool,
|
||||
self_ty_str: String,
|
||||
of_trait_str: Option<String>,
|
||||
},
|
||||
MacroRules {
|
||||
depth: u32,
|
||||
|
@ -1364,11 +1366,17 @@ impl<'a> LintDiagnostic<'a, ()> for NonLocalDefinitionsDiag {
|
|||
may_move,
|
||||
may_remove,
|
||||
has_trait,
|
||||
self_ty_str,
|
||||
of_trait_str,
|
||||
} => {
|
||||
diag.primary_message(fluent::lint_non_local_definitions_impl);
|
||||
diag.arg("depth", depth);
|
||||
diag.arg("body_kind_descr", body_kind_descr);
|
||||
diag.arg("body_name", body_name);
|
||||
diag.arg("self_ty_str", self_ty_str);
|
||||
if let Some(of_trait_str) = of_trait_str {
|
||||
diag.arg("of_trait_str", of_trait_str);
|
||||
}
|
||||
|
||||
if has_trait {
|
||||
diag.note(fluent::lint_bounds);
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
use rustc_errors::MultiSpan;
|
||||
use rustc_hir::intravisit::{self, Visitor};
|
||||
use rustc_hir::HirId;
|
||||
use rustc_hir::{def::DefKind, Body, Item, ItemKind, Node, TyKind};
|
||||
|
@ -9,12 +10,13 @@ use rustc_middle::ty::{EarlyBinder, TraitRef, TypeSuperFoldable};
|
|||
use rustc_session::{declare_lint, impl_lint_pass};
|
||||
use rustc_span::def_id::{DefId, LOCAL_CRATE};
|
||||
use rustc_span::Span;
|
||||
use rustc_span::{sym, symbol::kw, ExpnKind, MacroKind};
|
||||
use rustc_span::{sym, symbol::kw, ExpnKind, MacroKind, Symbol};
|
||||
use rustc_trait_selection::infer::TyCtxtInferExt;
|
||||
use rustc_trait_selection::traits::error_reporting::ambiguity::{
|
||||
compute_applicable_impls_for_diagnostics, CandidateSource,
|
||||
};
|
||||
|
||||
use crate::fluent_generated as fluent;
|
||||
use crate::lints::{NonLocalDefinitionsCargoUpdateNote, NonLocalDefinitionsDiag};
|
||||
use crate::{LateContext, LateLintPass, LintContext};
|
||||
|
||||
|
@ -201,11 +203,7 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions {
|
|||
.into_iter()
|
||||
.filter_map(|path| {
|
||||
if path_has_local_parent(&path, cx, parent, parent_parent) {
|
||||
if let Some(args) = &path.segments.last().unwrap().args {
|
||||
Some(path.span.until(args.span_ext))
|
||||
} else {
|
||||
Some(path.span)
|
||||
}
|
||||
Some(path_span_without_args(&path))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
|
@ -227,9 +225,29 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions {
|
|||
_ => None,
|
||||
};
|
||||
|
||||
let impl_span = item.span.shrink_to_lo().to(impl_.self_ty.span);
|
||||
let mut ms = MultiSpan::from_span(impl_span);
|
||||
|
||||
let (self_ty_span, self_ty_str) =
|
||||
self_ty_kind_for_diagnostic(&impl_.self_ty, cx.tcx);
|
||||
|
||||
ms.push_span_label(
|
||||
self_ty_span,
|
||||
fluent::lint_non_local_definitions_self_ty_not_local,
|
||||
);
|
||||
let of_trait_str = if let Some(of_trait) = &impl_.of_trait {
|
||||
ms.push_span_label(
|
||||
path_span_without_args(&of_trait.path),
|
||||
fluent::lint_non_local_definitions_of_trait_not_local,
|
||||
);
|
||||
Some(path_name_to_string(&of_trait.path))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
cx.emit_span_lint(
|
||||
NON_LOCAL_DEFINITIONS,
|
||||
item.span.shrink_to_lo().to(impl_.self_ty.span),
|
||||
ms,
|
||||
NonLocalDefinitionsDiag::Impl {
|
||||
depth: self.body_depth,
|
||||
move_help: item.span,
|
||||
|
@ -239,6 +257,8 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions {
|
|||
.unwrap_or_else(|| "<unnameable>".to_string()),
|
||||
cargo_update: cargo_update(),
|
||||
const_anon,
|
||||
self_ty_str,
|
||||
of_trait_str,
|
||||
may_move,
|
||||
may_remove,
|
||||
has_trait: impl_.of_trait.is_some(),
|
||||
|
@ -447,3 +467,52 @@ fn did_has_local_parent(
|
|||
false
|
||||
}
|
||||
}
|
||||
|
||||
/// Return for a given `Path` the span until the last args
|
||||
fn path_span_without_args(path: &Path<'_>) -> Span {
|
||||
if let Some(args) = &path.segments.last().unwrap().args {
|
||||
path.span.until(args.span_ext)
|
||||
} else {
|
||||
path.span
|
||||
}
|
||||
}
|
||||
|
||||
/// Return a "error message-able" ident for the last segment of the `Path`
|
||||
fn path_name_to_string(path: &Path<'_>) -> String {
|
||||
path.segments.last().unwrap().ident.name.to_ident_string()
|
||||
}
|
||||
|
||||
/// Compute the `Span` and visual representation for the `Self` we want to point at;
|
||||
/// It follows part of the actual logic of non-local, and if possible return the least
|
||||
/// amount possible for the span and representation.
|
||||
fn self_ty_kind_for_diagnostic(ty: &rustc_hir::Ty<'_>, tcx: TyCtxt<'_>) -> (Span, String) {
|
||||
match ty.kind {
|
||||
TyKind::Path(QPath::Resolved(_, ty_path)) => (
|
||||
path_span_without_args(ty_path),
|
||||
ty_path
|
||||
.res
|
||||
.opt_def_id()
|
||||
.map(|did| tcx.opt_item_name(did))
|
||||
.flatten()
|
||||
.as_ref()
|
||||
.map(|s| Symbol::as_str(s))
|
||||
.unwrap_or("<unnameable>")
|
||||
.to_string(),
|
||||
),
|
||||
TyKind::TraitObject([principle_poly_trait_ref, ..], _, _) => {
|
||||
let path = &principle_poly_trait_ref.trait_ref.path;
|
||||
(
|
||||
path_span_without_args(path),
|
||||
path.res
|
||||
.opt_def_id()
|
||||
.map(|did| tcx.opt_item_name(did))
|
||||
.flatten()
|
||||
.as_ref()
|
||||
.map(|s| Symbol::as_str(s))
|
||||
.unwrap_or("<unnameable>")
|
||||
.to_string(),
|
||||
)
|
||||
}
|
||||
_ => (ty.span, rustc_hir_pretty::ty_to_string(&tcx, ty)),
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue