diff options
Diffstat (limited to 'compiler/rustc_lint/src')
| -rw-r--r-- | compiler/rustc_lint/src/builtin.rs | 20 | ||||
| -rw-r--r-- | compiler/rustc_lint/src/context.rs | 35 | ||||
| -rw-r--r-- | compiler/rustc_lint/src/context/diagnostics.rs | 383 | ||||
| -rw-r--r-- | compiler/rustc_lint/src/impl_trait_overcaptures.rs | 23 | ||||
| -rw-r--r-- | compiler/rustc_lint/src/levels.rs | 42 | ||||
| -rw-r--r-- | compiler/rustc_lint/src/lints.rs | 178 | ||||
| -rw-r--r-- | compiler/rustc_lint/src/non_fmt_panic.rs | 3 | ||||
| -rw-r--r-- | compiler/rustc_lint/src/non_local_def.rs | 216 |
8 files changed, 505 insertions, 395 deletions
diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index 85d54ce563d..ba42eae3441 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -1950,14 +1950,22 @@ declare_lint_pass!(ExplicitOutlivesRequirements => [EXPLICIT_OUTLIVES_REQUIREMEN impl ExplicitOutlivesRequirements { fn lifetimes_outliving_lifetime<'tcx>( + tcx: TyCtxt<'tcx>, inferred_outlives: &'tcx [(ty::Clause<'tcx>, Span)], - def_id: DefId, + item: DefId, + lifetime: DefId, ) -> Vec<ty::Region<'tcx>> { + let item_generics = tcx.generics_of(item); + inferred_outlives .iter() .filter_map(|(clause, _)| match clause.kind().skip_binder() { ty::ClauseKind::RegionOutlives(ty::OutlivesPredicate(a, b)) => match *a { - ty::ReEarlyParam(ebr) if ebr.def_id == def_id => Some(b), + ty::ReEarlyParam(ebr) + if item_generics.region_param(ebr, tcx).def_id == lifetime => + { + Some(b) + } _ => None, }, _ => None, @@ -1986,9 +1994,12 @@ impl ExplicitOutlivesRequirements { bounds: &hir::GenericBounds<'_>, inferred_outlives: &[ty::Region<'tcx>], predicate_span: Span, + item: DefId, ) -> Vec<(usize, Span)> { use rustc_middle::middle::resolve_bound_vars::ResolvedArg; + let item_generics = tcx.generics_of(item); + bounds .iter() .enumerate() @@ -2000,7 +2011,7 @@ impl ExplicitOutlivesRequirements { let is_inferred = match tcx.named_bound_var(lifetime.hir_id) { Some(ResolvedArg::EarlyBound(def_id)) => inferred_outlives .iter() - .any(|r| matches!(**r, ty::ReEarlyParam(ebr) if { ebr.def_id == def_id })), + .any(|r| matches!(**r, ty::ReEarlyParam(ebr) if { item_generics.region_param(ebr, tcx).def_id == def_id })), _ => false, }; @@ -2109,7 +2120,9 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitOutlivesRequirements { { ( Self::lifetimes_outliving_lifetime( + cx.tcx, inferred_outlives, + item.owner_id.to_def_id(), region_def_id, ), &predicate.bounds, @@ -2152,6 +2165,7 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitOutlivesRequirements { bounds, &relevant_lifetimes, predicate_span, + item.owner_id.to_def_id(), ); bound_count += bound_spans.len(); diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs index c23a67f6131..56f07a2b5e9 100644 --- a/compiler/rustc_lint/src/context.rs +++ b/compiler/rustc_lint/src/context.rs @@ -21,7 +21,7 @@ use crate::passes::{EarlyLintPassObject, LateLintPassObject}; use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::sync; use rustc_data_structures::unord::UnordMap; -use rustc_errors::{Diag, DiagMessage, LintDiagnostic, MultiSpan}; +use rustc_errors::{Diag, LintDiagnostic, MultiSpan}; use rustc_feature::Features; use rustc_hir as hir; use rustc_hir::def::Res; @@ -539,7 +539,9 @@ impl EarlyContext<'_> { span: MultiSpan, diagnostic: BuiltinLintDiag, ) { - diagnostics::emit_buffered_lint(self, lint, span, diagnostic) + self.opt_span_lint(lint, Some(span), |diag| { + diagnostics::decorate_lint(self.sess(), diagnostic, diag); + }); } } @@ -556,7 +558,6 @@ pub trait LintContext { &self, lint: &'static Lint, span: Option<S>, - msg: impl Into<DiagMessage>, decorate: impl for<'a, 'b> FnOnce(&'b mut Diag<'a, ()>), ); @@ -568,8 +569,8 @@ pub trait LintContext { span: S, decorator: impl for<'a> LintDiagnostic<'a, ()>, ) { - self.opt_span_lint(lint, Some(span), decorator.msg(), |diag| { - decorator.decorate_lint(diag); + self.opt_span_lint(lint, Some(span), |lint| { + decorator.decorate_lint(lint); }); } @@ -581,17 +582,16 @@ pub trait LintContext { &self, lint: &'static Lint, span: S, - msg: impl Into<DiagMessage>, decorate: impl for<'a, 'b> FnOnce(&'b mut Diag<'a, ()>), ) { - self.opt_span_lint(lint, Some(span), msg, decorate); + self.opt_span_lint(lint, Some(span), decorate); } /// Emit a lint from a lint struct (some type that implements `LintDiagnostic`, typically /// generated by `#[derive(LintDiagnostic)]`). fn emit_lint(&self, lint: &'static Lint, decorator: impl for<'a> LintDiagnostic<'a, ()>) { - self.opt_span_lint(lint, None as Option<Span>, decorator.msg(), |diag| { - decorator.decorate_lint(diag); + self.opt_span_lint(lint, None as Option<Span>, |lint| { + decorator.decorate_lint(lint); }); } @@ -599,13 +599,8 @@ pub trait LintContext { /// /// [`lint_level`]: rustc_middle::lint::lint_level#decorate-signature #[rustc_lint_diagnostics] - fn lint( - &self, - lint: &'static Lint, - msg: impl Into<DiagMessage>, - decorate: impl for<'a, 'b> FnOnce(&'b mut Diag<'a, ()>), - ) { - self.opt_span_lint(lint, None as Option<Span>, msg, decorate); + fn lint(&self, lint: &'static Lint, decorate: impl for<'a, 'b> FnOnce(&'b mut Diag<'a, ()>)) { + self.opt_span_lint(lint, None as Option<Span>, decorate); } /// This returns the lint level for the given lint at the current location. @@ -668,14 +663,13 @@ impl<'tcx> LintContext for LateContext<'tcx> { &self, lint: &'static Lint, span: Option<S>, - msg: impl Into<DiagMessage>, decorate: impl for<'a, 'b> FnOnce(&'b mut Diag<'a, ()>), ) { let hir_id = self.last_node_with_lint_attrs; match span { - Some(s) => self.tcx.node_span_lint(lint, hir_id, s, msg, decorate), - None => self.tcx.node_lint(lint, hir_id, msg, decorate), + Some(s) => self.tcx.node_span_lint(lint, hir_id, s, decorate), + None => self.tcx.node_lint(lint, hir_id, decorate), } } @@ -695,10 +689,9 @@ impl LintContext for EarlyContext<'_> { &self, lint: &'static Lint, span: Option<S>, - msg: impl Into<DiagMessage>, decorate: impl for<'a, 'b> FnOnce(&'b mut Diag<'a, ()>), ) { - self.builder.opt_span_lint(lint, span.map(|s| s.into()), msg, decorate) + self.builder.opt_span_lint(lint, span.map(|s| s.into()), decorate) } fn get_lint_level(&self, lint: &'static Lint) -> Level { diff --git a/compiler/rustc_lint/src/context/diagnostics.rs b/compiler/rustc_lint/src/context/diagnostics.rs index 23c5e0a9f5f..26f34486a3d 100644 --- a/compiler/rustc_lint/src/context/diagnostics.rs +++ b/compiler/rustc_lint/src/context/diagnostics.rs @@ -4,24 +4,19 @@ use std::borrow::Cow; use rustc_ast::util::unicode::TEXT_FLOW_CONTROL_CHARS; -use rustc_errors::Applicability; -use rustc_errors::{elided_lifetime_in_path_suggestion, DiagArgValue, MultiSpan}; +use rustc_errors::elided_lifetime_in_path_suggestion; +use rustc_errors::{Applicability, Diag, DiagArgValue, LintDiagnostic}; use rustc_middle::middle::stability; -use rustc_session::lint::{BuiltinLintDiag, Lint}; +use rustc_session::lint::BuiltinLintDiag; +use rustc_session::Session; use rustc_span::BytePos; use tracing::debug; -use crate::{lints, EarlyContext, LintContext as _}; +use crate::lints; mod check_cfg; -pub(super) fn emit_buffered_lint( - ctx: &EarlyContext<'_>, - lint: &'static Lint, - span: MultiSpan, - diagnostic: BuiltinLintDiag, -) { - let sess = ctx.sess(); +pub(super) fn decorate_lint(sess: &Session, diagnostic: BuiltinLintDiag, diag: &mut Diag<'_, ()>) { match diagnostic { BuiltinLintDiag::UnicodeTextFlow(comment_span, content) => { let spans: Vec<_> = content @@ -40,16 +35,14 @@ pub(super) fn emit_buffered_lint( let suggestions = (!spans.is_empty()).then_some(lints::UnicodeTextFlowSuggestion { spans: spans.iter().map(|(_c, span)| *span).collect(), }); - ctx.emit_span_lint( - lint, - span, - lints::UnicodeTextFlow { - comment_span, - characters, - suggestions, - num_codepoints: spans.len(), - }, - ) + + lints::UnicodeTextFlow { + comment_span, + characters, + suggestions, + num_codepoints: spans.len(), + } + .decorate_lint(diag); } BuiltinLintDiag::AbsPathWithModule(mod_span) => { let (replacement, applicability) = match sess.source_map().span_to_snippet(mod_span) { @@ -62,48 +55,35 @@ pub(super) fn emit_buffered_lint( } Err(_) => ("crate::<path>".to_string(), Applicability::HasPlaceholders), }; - ctx.emit_span_lint( - lint, - span, - lints::AbsPathWithModule { - sugg: lints::AbsPathWithModuleSugg { - span: mod_span, - applicability, - replacement, - }, - }, - ); - } - BuiltinLintDiag::ProcMacroDeriveResolutionFallback { span: macro_span, ns, ident } => ctx - .emit_span_lint( - lint, - span, - lints::ProcMacroDeriveResolutionFallback { span: macro_span, ns, ident }, - ), - BuiltinLintDiag::MacroExpandedMacroExportsAccessedByAbsolutePaths(span_def) => ctx - .emit_span_lint( - lint, - span, - lints::MacroExpandedMacroExportsAccessedByAbsolutePaths { definition: span_def }, - ), + lints::AbsPathWithModule { + sugg: lints::AbsPathWithModuleSugg { span: mod_span, applicability, replacement }, + } + .decorate_lint(diag); + } + BuiltinLintDiag::ProcMacroDeriveResolutionFallback { span: macro_span, ns, ident } => { + lints::ProcMacroDeriveResolutionFallback { span: macro_span, ns, ident } + .decorate_lint(diag) + } + BuiltinLintDiag::MacroExpandedMacroExportsAccessedByAbsolutePaths(span_def) => { + lints::MacroExpandedMacroExportsAccessedByAbsolutePaths { definition: span_def } + .decorate_lint(diag) + } + BuiltinLintDiag::ElidedLifetimesInPaths(n, path_span, incl_angl_brckt, insertion_span) => { - ctx.emit_span_lint( - lint, - span, - lints::ElidedLifetimesInPaths { - subdiag: elided_lifetime_in_path_suggestion( - sess.source_map(), - n, - path_span, - incl_angl_brckt, - insertion_span, - ), - }, - ); + lints::ElidedLifetimesInPaths { + subdiag: elided_lifetime_in_path_suggestion( + sess.source_map(), + n, + path_span, + incl_angl_brckt, + insertion_span, + ), + } + .decorate_lint(diag); } BuiltinLintDiag::UnknownCrateTypes { span, candidate } => { let sugg = candidate.map(|candidate| lints::UnknownCrateTypesSub { span, candidate }); - ctx.emit_span_lint(lint, span, lints::UnknownCrateTypes { sugg }); + lints::UnknownCrateTypes { sugg }.decorate_lint(diag); } BuiltinLintDiag::UnusedImports { remove_whole_use, @@ -120,18 +100,15 @@ pub(super) fn emit_buffered_lint( let test_module_span = test_module_span.map(|span| sess.source_map().guess_head_span(span)); - ctx.emit_span_lint( - lint, - span, - lints::UnusedImports { - sugg, - test_module_span, - num_snippets: span_snippets.len(), - span_snippets: DiagArgValue::StrListSepByAnd( - span_snippets.into_iter().map(Cow::Owned).collect(), - ), - }, - ); + lints::UnusedImports { + sugg, + test_module_span, + num_snippets: span_snippets.len(), + span_snippets: DiagArgValue::StrListSepByAnd( + span_snippets.into_iter().map(Cow::Owned).collect(), + ), + } + .decorate_lint(diag); } BuiltinLintDiag::RedundantImport(spans, ident) => { let subs = spans @@ -145,7 +122,7 @@ pub(super) fn emit_buffered_lint( })(span) }) .collect(); - ctx.emit_span_lint(lint, span, lints::RedundantImport { subs, ident }); + lints::RedundantImport { subs, ident }.decorate_lint(diag); } BuiltinLintDiag::DeprecatedMacro { suggestion, @@ -159,90 +136,63 @@ pub(super) fn emit_buffered_lint( kind: "macro".to_owned(), suggestion, }); - ctx.emit_span_lint( - lint, - span, - stability::Deprecated { sub, kind: "macro".to_owned(), path, note, since_kind }, - ); + + stability::Deprecated { sub, kind: "macro".to_owned(), path, note, since_kind } + .decorate_lint(diag); } BuiltinLintDiag::UnusedDocComment(attr_span) => { - ctx.emit_span_lint(lint, span, lints::UnusedDocComment { span: attr_span }); + lints::UnusedDocComment { span: attr_span }.decorate_lint(diag); } BuiltinLintDiag::PatternsInFnsWithoutBody { span: remove_span, ident, is_foreign } => { let sub = lints::PatternsInFnsWithoutBodySub { ident, span: remove_span }; - - ctx.emit_span_lint( - lint, - span, - if is_foreign { - lints::PatternsInFnsWithoutBody::Foreign { sub } - } else { - lints::PatternsInFnsWithoutBody::Bodiless { sub } - }, - ); + if is_foreign { + lints::PatternsInFnsWithoutBody::Foreign { sub } + } else { + lints::PatternsInFnsWithoutBody::Bodiless { sub } + } + .decorate_lint(diag); } BuiltinLintDiag::MissingAbi(label_span, default_abi) => { - ctx.emit_span_lint( - lint, - span, - lints::MissingAbi { span: label_span, default_abi: default_abi.name() }, - ); + lints::MissingAbi { span: label_span, default_abi: default_abi.name() } + .decorate_lint(diag); } BuiltinLintDiag::LegacyDeriveHelpers(label_span) => { - ctx.emit_span_lint(lint, span, lints::LegacyDeriveHelpers { span: label_span }); + lints::LegacyDeriveHelpers { span: label_span }.decorate_lint(diag); } BuiltinLintDiag::ProcMacroBackCompat { crate_name, fixed_version } => { - ctx.emit_span_lint( - lint, - span, - lints::ProcMacroBackCompat { crate_name, fixed_version }, - ); + lints::ProcMacroBackCompat { crate_name, fixed_version }.decorate_lint(diag); } BuiltinLintDiag::OrPatternsBackCompat(suggestion_span, suggestion) => { - ctx.emit_span_lint( - lint, - span, - lints::OrPatternsBackCompat { span: suggestion_span, suggestion }, - ); + lints::OrPatternsBackCompat { span: suggestion_span, suggestion }.decorate_lint(diag); } BuiltinLintDiag::ReservedPrefix(label_span, prefix) => { - ctx.emit_span_lint( - lint, - span, - lints::ReservedPrefix { - label: label_span, - suggestion: label_span.shrink_to_hi(), - prefix, - }, - ); + lints::ReservedPrefix { + label: label_span, + suggestion: label_span.shrink_to_hi(), + prefix, + } + .decorate_lint(diag); } BuiltinLintDiag::UnusedBuiltinAttribute { attr_name, macro_name, invoc_span } => { - ctx.emit_span_lint( - lint, - span, - lints::UnusedBuiltinAttribute { invoc_span, attr_name, macro_name }, - ); + lints::UnusedBuiltinAttribute { invoc_span, attr_name, macro_name }.decorate_lint(diag); } BuiltinLintDiag::TrailingMacro(is_trailing, name) => { - ctx.emit_span_lint(lint, span, lints::TrailingMacro { is_trailing, name }); + lints::TrailingMacro { is_trailing, name }.decorate_lint(diag); } BuiltinLintDiag::BreakWithLabelAndLoop(sugg_span) => { - ctx.emit_span_lint( - lint, - span, - lints::BreakWithLabelAndLoop { - sub: lints::BreakWithLabelAndLoopSub { - left: sugg_span.shrink_to_lo(), - right: sugg_span.shrink_to_hi(), - }, + lints::BreakWithLabelAndLoop { + sub: lints::BreakWithLabelAndLoopSub { + left: sugg_span.shrink_to_lo(), + right: sugg_span.shrink_to_hi(), }, - ); + } + .decorate_lint(diag); } BuiltinLintDiag::UnexpectedCfgName(name, value) => { - ctx.emit_span_lint(lint, span, check_cfg::unexpected_cfg_name(sess, name, value)); + check_cfg::unexpected_cfg_name(sess, name, value).decorate_lint(diag); } BuiltinLintDiag::UnexpectedCfgValue(name, value) => { - ctx.emit_span_lint(lint, span, check_cfg::unexpected_cfg_value(sess, name, value)); + check_cfg::unexpected_cfg_value(sess, name, value).decorate_lint(diag); } BuiltinLintDiag::DeprecatedWhereclauseLocation(left_sp, sugg) => { let suggestion = match sugg { @@ -253,7 +203,7 @@ pub(super) fn emit_buffered_lint( }, None => lints::DeprecatedWhereClauseLocationSugg::RemoveWhere { span: left_sp }, }; - ctx.emit_span_lint(lint, span, lints::DeprecatedWhereClauseLocation { suggestion }); + lints::DeprecatedWhereClauseLocation { suggestion }.decorate_lint(diag); } BuiltinLintDiag::SingleUseLifetime { param_span, @@ -280,15 +230,12 @@ pub(super) fn emit_buffered_lint( None }; - ctx.emit_span_lint( - lint, - span, - lints::SingleUseLifetime { suggestion, param_span, use_span, ident }, - ); + lints::SingleUseLifetime { suggestion, param_span, use_span, ident } + .decorate_lint(diag); } BuiltinLintDiag::SingleUseLifetime { use_span: None, deletion_span, ident, .. } => { debug!(?deletion_span); - ctx.emit_span_lint(lint, span, lints::UnusedLifetime { deletion_span, ident }); + lints::UnusedLifetime { deletion_span, ident }.decorate_lint(diag); } BuiltinLintDiag::NamedArgumentUsedPositionally { position_sp_to_replace, @@ -316,35 +263,29 @@ pub(super) fn emit_buffered_lint( (None, String::new()) }; - ctx.emit_span_lint( - lint, - span, - lints::NamedArgumentUsedPositionally { - named_arg_sp, - position_label_sp: position_sp_for_msg, - suggestion, - name, - named_arg_name, - }, - ) + lints::NamedArgumentUsedPositionally { + named_arg_sp, + position_label_sp: position_sp_for_msg, + suggestion, + name, + named_arg_name, + } + .decorate_lint(diag); } BuiltinLintDiag::ByteSliceInPackedStructWithDerive { ty } => { - ctx.emit_span_lint(lint, span, lints::ByteSliceInPackedStructWithDerive { ty }) + lints::ByteSliceInPackedStructWithDerive { ty }.decorate_lint(diag); } BuiltinLintDiag::UnusedExternCrate { removal_span } => { - ctx.emit_span_lint(lint, span, lints::UnusedExternCrate { removal_span }) + lints::UnusedExternCrate { removal_span }.decorate_lint(diag); } BuiltinLintDiag::ExternCrateNotIdiomatic { vis_span, ident_span } => { let suggestion_span = vis_span.between(ident_span); let code = if vis_span.is_empty() { "use " } else { " use " }; - ctx.emit_span_lint( - lint, - span, - lints::ExternCrateNotIdiomatic { span: suggestion_span, code }, - ); + + lints::ExternCrateNotIdiomatic { span: suggestion_span, code }.decorate_lint(diag); } BuiltinLintDiag::AmbiguousGlobImports { diag: ambiguity } => { - ctx.emit_span_lint(lint, span, lints::AmbiguousGlobImports { ambiguity }); + lints::AmbiguousGlobImports { ambiguity }.decorate_lint(diag); } BuiltinLintDiag::AmbiguousGlobReexports { name, @@ -352,16 +293,13 @@ pub(super) fn emit_buffered_lint( first_reexport_span, duplicate_reexport_span, } => { - ctx.emit_span_lint( - lint, - span, - lints::AmbiguousGlobReexports { - first_reexport: first_reexport_span, - duplicate_reexport: duplicate_reexport_span, - name, - namespace, - }, - ); + lints::AmbiguousGlobReexports { + first_reexport: first_reexport_span, + duplicate_reexport: duplicate_reexport_span, + name, + namespace, + } + .decorate_lint(diag); } BuiltinLintDiag::HiddenGlobReexports { name, @@ -369,127 +307,112 @@ pub(super) fn emit_buffered_lint( glob_reexport_span, private_item_span, } => { - ctx.emit_span_lint( - lint, - span, - lints::HiddenGlobReexports { - glob_reexport: glob_reexport_span, - private_item: private_item_span, + lints::HiddenGlobReexports { + glob_reexport: glob_reexport_span, + private_item: private_item_span, - name, - namespace, - }, - ); + name, + namespace, + } + .decorate_lint(diag); } BuiltinLintDiag::UnusedQualifications { removal_span } => { - ctx.emit_span_lint(lint, span, lints::UnusedQualifications { removal_span }); + lints::UnusedQualifications { removal_span }.decorate_lint(diag); } BuiltinLintDiag::AssociatedConstElidedLifetime { elided, span: lt_span } => { let lt_span = if elided { lt_span.shrink_to_hi() } else { lt_span }; let code = if elided { "'static " } else { "'static" }; - ctx.emit_span_lint( - lint, - span, - lints::AssociatedConstElidedLifetime { span: lt_span, code, elided }, - ); + lints::AssociatedConstElidedLifetime { span: lt_span, code, elided } + .decorate_lint(diag); } BuiltinLintDiag::RedundantImportVisibility { max_vis, span: vis_span, import_vis } => { - ctx.emit_span_lint( - lint, - span, - lints::RedundantImportVisibility { span: vis_span, help: (), max_vis, import_vis }, - ); + lints::RedundantImportVisibility { span: vis_span, help: (), max_vis, import_vis } + .decorate_lint(diag); } BuiltinLintDiag::UnknownDiagnosticAttribute { span: typo_span, typo_name } => { let typo = typo_name.map(|typo_name| lints::UnknownDiagnosticAttributeTypoSugg { span: typo_span, typo_name, }); - ctx.emit_span_lint(lint, span, lints::UnknownDiagnosticAttribute { typo }); + lints::UnknownDiagnosticAttribute { typo }.decorate_lint(diag); } BuiltinLintDiag::MacroUseDeprecated => { - ctx.emit_span_lint(lint, span, lints::MacroUseDeprecated) + lints::MacroUseDeprecated.decorate_lint(diag); } - BuiltinLintDiag::UnusedMacroUse => ctx.emit_span_lint(lint, span, lints::UnusedMacroUse), + BuiltinLintDiag::UnusedMacroUse => lints::UnusedMacroUse.decorate_lint(diag), BuiltinLintDiag::PrivateExternCrateReexport(ident) => { - ctx.emit_span_lint(lint, span, lints::PrivateExternCrateReexport { ident }) + lints::PrivateExternCrateReexport { ident }.decorate_lint(diag); } - BuiltinLintDiag::UnusedLabel => ctx.emit_span_lint(lint, span, lints::UnusedLabel), + BuiltinLintDiag::UnusedLabel => lints::UnusedLabel.decorate_lint(diag), BuiltinLintDiag::MacroIsPrivate(ident) => { - ctx.emit_span_lint(lint, span, lints::MacroIsPrivate { ident }) + lints::MacroIsPrivate { ident }.decorate_lint(diag); } BuiltinLintDiag::UnusedMacroDefinition(name) => { - ctx.emit_span_lint(lint, span, lints::UnusedMacroDefinition { name }) + lints::UnusedMacroDefinition { name }.decorate_lint(diag); } BuiltinLintDiag::MacroRuleNeverUsed(n, name) => { - ctx.emit_span_lint(lint, span, lints::MacroRuleNeverUsed { n: n + 1, name }) + lints::MacroRuleNeverUsed { n: n + 1, name }.decorate_lint(diag); } BuiltinLintDiag::UnstableFeature(msg) => { - ctx.emit_span_lint(lint, span, lints::UnstableFeature { msg }) + lints::UnstableFeature { msg }.decorate_lint(diag); } BuiltinLintDiag::AvoidUsingIntelSyntax => { - ctx.emit_span_lint(lint, span, lints::AvoidIntelSyntax) + lints::AvoidIntelSyntax.decorate_lint(diag); } BuiltinLintDiag::AvoidUsingAttSyntax => { - ctx.emit_span_lint(lint, span, lints::AvoidAttSyntax) + lints::AvoidAttSyntax.decorate_lint(diag); } BuiltinLintDiag::IncompleteInclude => { - ctx.emit_span_lint(lint, span, lints::IncompleteInclude) + lints::IncompleteInclude.decorate_lint(diag); } BuiltinLintDiag::UnnameableTestItems => { - ctx.emit_span_lint(lint, span, lints::UnnameableTestItems) + lints::UnnameableTestItems.decorate_lint(diag); } BuiltinLintDiag::DuplicateMacroAttribute => { - ctx.emit_span_lint(lint, span, lints::DuplicateMacroAttribute) + lints::DuplicateMacroAttribute.decorate_lint(diag); } BuiltinLintDiag::CfgAttrNoAttributes => { - ctx.emit_span_lint(lint, span, lints::CfgAttrNoAttributes) + lints::CfgAttrNoAttributes.decorate_lint(diag); } BuiltinLintDiag::CrateTypeInCfgAttr => { - ctx.emit_span_lint(lint, span, lints::CrateTypeInCfgAttr) + lints::CrateTypeInCfgAttr.decorate_lint(diag); } BuiltinLintDiag::CrateNameInCfgAttr => { - ctx.emit_span_lint(lint, span, lints::CrateNameInCfgAttr) + lints::CrateNameInCfgAttr.decorate_lint(diag); } BuiltinLintDiag::MissingFragmentSpecifier => { - ctx.emit_span_lint(lint, span, lints::MissingFragmentSpecifier) + lints::MissingFragmentSpecifier.decorate_lint(diag); } BuiltinLintDiag::MetaVariableStillRepeating(name) => { - ctx.emit_span_lint(lint, span, lints::MetaVariableStillRepeating { name }) + lints::MetaVariableStillRepeating { name }.decorate_lint(diag); } BuiltinLintDiag::MetaVariableWrongOperator => { - ctx.emit_span_lint(lint, span, lints::MetaVariableWrongOperator) + lints::MetaVariableWrongOperator.decorate_lint(diag); } BuiltinLintDiag::DuplicateMatcherBinding => { - ctx.emit_span_lint(lint, span, lints::DuplicateMatcherBinding) + lints::DuplicateMatcherBinding.decorate_lint(diag); } BuiltinLintDiag::UnknownMacroVariable(name) => { - ctx.emit_span_lint(lint, span, lints::UnknownMacroVariable { name }) - } - BuiltinLintDiag::UnusedCrateDependency { extern_crate, local_crate } => ctx.emit_span_lint( - lint, - span, - lints::UnusedCrateDependency { extern_crate, local_crate }, - ), - BuiltinLintDiag::WasmCAbi => ctx.emit_span_lint(lint, span, lints::WasmCAbi), - BuiltinLintDiag::IllFormedAttributeInput { suggestions } => ctx.emit_span_lint( - lint, - span, + lints::UnknownMacroVariable { name }.decorate_lint(diag); + } + BuiltinLintDiag::UnusedCrateDependency { extern_crate, local_crate } => { + lints::UnusedCrateDependency { extern_crate, local_crate }.decorate_lint(diag) + } + BuiltinLintDiag::WasmCAbi => lints::WasmCAbi.decorate_lint(diag), + BuiltinLintDiag::IllFormedAttributeInput { suggestions } => { lints::IllFormedAttributeInput { num_suggestions: suggestions.len(), suggestions: DiagArgValue::StrListSepByAnd( suggestions.into_iter().map(|s| format!("`{s}`").into()).collect(), ), - }, - ), - BuiltinLintDiag::InnerAttributeUnstable { is_macro } => ctx.emit_span_lint( - lint, - span, - if is_macro { - lints::InnerAttributeUnstable::InnerMacroAttribute - } else { - lints::InnerAttributeUnstable::CustomInnerAttribute - }, - ), + } + .decorate_lint(diag) + } + BuiltinLintDiag::InnerAttributeUnstable { is_macro } => if is_macro { + lints::InnerAttributeUnstable::InnerMacroAttribute + } else { + lints::InnerAttributeUnstable::CustomInnerAttribute + } + .decorate_lint(diag), } } diff --git a/compiler/rustc_lint/src/impl_trait_overcaptures.rs b/compiler/rustc_lint/src/impl_trait_overcaptures.rs index 30bf80b915b..a311c274a6b 100644 --- a/compiler/rustc_lint/src/impl_trait_overcaptures.rs +++ b/compiler/rustc_lint/src/impl_trait_overcaptures.rs @@ -5,11 +5,11 @@ use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_macros::LintDiagnostic; +use rustc_middle::bug; use rustc_middle::middle::resolve_bound_vars::ResolvedArg; use rustc_middle::ty::{ self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, }; -use rustc_middle::{bug, span_bug}; use rustc_session::{declare_lint, declare_lint_pass}; use rustc_span::{sym, BytePos, Span}; @@ -303,20 +303,12 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for VisitOpaqueTypes<'tcx> { ResolvedArg::EarlyBound(def_id) | ResolvedArg::LateBound(_, _, def_id), ) => { if self.tcx.def_kind(self.tcx.parent(def_id)) == DefKind::OpaqueTy { - let (ty::ReEarlyParam(ty::EarlyParamRegion { def_id, .. }) - | ty::ReLateParam(ty::LateParamRegion { - bound_region: ty::BoundRegionKind::BrNamed(def_id, _), - .. - })) = self + let def_id = self .tcx .map_opaque_lifetime_to_parent_lifetime(def_id.expect_local()) - .kind() - else { - span_bug!( - self.tcx.def_span(def_id), - "variable should have been duplicated from a parent" - ); - }; + .opt_param_def_id(self.tcx, self.parent_def_id.to_def_id()) + .expect("variable should have been duplicated from parent"); + explicitly_captured.insert(def_id); } else { explicitly_captured.insert(def_id); @@ -369,6 +361,7 @@ struct ImplTraitOvercapturesLint<'tcx> { impl<'a> LintDiagnostic<'a, ()> for ImplTraitOvercapturesLint<'_> { fn decorate_lint<'b>(self, diag: &'b mut rustc_errors::Diag<'a, ()>) { + diag.primary_message(fluent::lint_impl_trait_overcaptures); diag.arg("self_ty", self.self_ty.to_string()) .arg("num_captured", self.num_captured) .span_note(self.uncaptured_spans, fluent::lint_note) @@ -382,10 +375,6 @@ impl<'a> LintDiagnostic<'a, ()> for ImplTraitOvercapturesLint<'_> { ); } } - - fn msg(&self) -> rustc_errors::DiagMessage { - fluent::lint_impl_trait_overcaptures - } } #[derive(LintDiagnostic)] diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs index 98e321076c5..84645e0ce7f 100644 --- a/compiler/rustc_lint/src/levels.rs +++ b/compiler/rustc_lint/src/levels.rs @@ -16,7 +16,7 @@ use crate::{ use rustc_ast as ast; use rustc_ast_pretty::pprust; use rustc_data_structures::fx::FxIndexMap; -use rustc_errors::{Diag, DiagMessage, LintDiagnostic, MultiSpan}; +use rustc_errors::{Diag, LintDiagnostic, MultiSpan}; use rustc_feature::{Features, GateIssue}; use rustc_hir as hir; use rustc_hir::intravisit::{self, Visitor}; @@ -1064,26 +1064,19 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> { // FIXME: make this translatable #[allow(rustc::diagnostic_outside_of_impl)] #[allow(rustc::untranslatable_diagnostic)] - lint_level( - self.sess, - lint, - level, - src, - Some(span.into()), - fluent::lint_unknown_gated_lint, - |lint| { - lint.arg("name", lint_id.lint.name_lower()); - lint.note(fluent::lint_note); - rustc_session::parse::add_feature_diagnostics_for_issue( - lint, - &self.sess, - feature, - GateIssue::Language, - lint_from_cli, - None, - ); - }, - ); + lint_level(self.sess, lint, level, src, Some(span.into()), |lint| { + lint.primary_message(fluent::lint_unknown_gated_lint); + lint.arg("name", lint_id.lint.name_lower()); + lint.note(fluent::lint_note); + rustc_session::parse::add_feature_diagnostics_for_issue( + lint, + &self.sess, + feature, + GateIssue::Language, + lint_from_cli, + None, + ); + }); } false @@ -1104,11 +1097,10 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> { &self, lint: &'static Lint, span: Option<MultiSpan>, - msg: impl Into<DiagMessage>, decorate: impl for<'a, 'b> FnOnce(&'b mut Diag<'a, ()>), ) { let (level, src) = self.lint_level(lint); - lint_level(self.sess, lint, level, src, span, msg, decorate) + lint_level(self.sess, lint, level, src, span, decorate) } #[track_caller] @@ -1119,7 +1111,7 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> { decorate: impl for<'a> LintDiagnostic<'a, ()>, ) { let (level, src) = self.lint_level(lint); - lint_level(self.sess, lint, level, src, Some(span), decorate.msg(), |lint| { + lint_level(self.sess, lint, level, src, Some(span), |lint| { decorate.decorate_lint(lint); }); } @@ -1127,7 +1119,7 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> { #[track_caller] pub fn emit_lint(&self, lint: &'static Lint, decorate: impl for<'a> LintDiagnostic<'a, ()>) { let (level, src) = self.lint_level(lint); - lint_level(self.sess, lint, level, src, None, decorate.msg(), |lint| { + lint_level(self.sess, lint, level, src, None, |lint| { decorate.decorate_lint(lint); }); } diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index 2f44bc4764e..2edfb8d3df4 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -6,7 +6,7 @@ use crate::errors::RequestedLevel; use crate::fluent_generated as fluent; use rustc_errors::{ codes::*, Applicability, Diag, DiagArgValue, DiagMessage, DiagStyledString, - ElidedLifetimeInPathSubdiag, EmissionGuarantee, LintDiagnostic, SubdiagMessageOp, + ElidedLifetimeInPathSubdiag, EmissionGuarantee, LintDiagnostic, MultiSpan, SubdiagMessageOp, Subdiagnostic, SuggestionStyle, }; use rustc_hir::{def::Namespace, def_id::DefId}; @@ -145,12 +145,9 @@ pub struct BuiltinMissingDebugImpl<'a> { // Needed for def_path_str impl<'a> LintDiagnostic<'a, ()> for BuiltinMissingDebugImpl<'_> { fn decorate_lint<'b>(self, diag: &'b mut rustc_errors::Diag<'a, ()>) { + diag.primary_message(fluent::lint_builtin_missing_debug_impl); diag.arg("debug", self.tcx.def_path_str(self.def_id)); } - - fn msg(&self) -> DiagMessage { - fluent::lint_builtin_missing_debug_impl - } } #[derive(LintDiagnostic)] @@ -250,6 +247,7 @@ pub struct BuiltinUngatedAsyncFnTrackCaller<'a> { impl<'a> LintDiagnostic<'a, ()> for BuiltinUngatedAsyncFnTrackCaller<'_> { fn decorate_lint<'b>(self, diag: &'b mut Diag<'a, ()>) { + diag.primary_message(fluent::lint_ungated_async_fn_track_caller); diag.span_label(self.label, fluent::lint_label); rustc_session::parse::add_feature_diagnostics( diag, @@ -257,10 +255,6 @@ impl<'a> LintDiagnostic<'a, ()> for BuiltinUngatedAsyncFnTrackCaller<'_> { sym::async_fn_track_caller, ); } - - fn msg(&self) -> DiagMessage { - fluent::lint_ungated_async_fn_track_caller - } } #[derive(LintDiagnostic)] @@ -432,6 +426,7 @@ pub struct BuiltinUnpermittedTypeInit<'a> { impl<'a> LintDiagnostic<'a, ()> for BuiltinUnpermittedTypeInit<'_> { fn decorate_lint<'b>(self, diag: &'b mut Diag<'a, ()>) { + diag.primary_message(self.msg); diag.arg("ty", self.ty); diag.span_label(self.label, fluent::lint_builtin_unpermitted_type_init_label); if let InhabitedPredicate::True = self.ty.inhabited_predicate(self.tcx) { @@ -443,10 +438,6 @@ impl<'a> LintDiagnostic<'a, ()> for BuiltinUnpermittedTypeInit<'_> { } self.sub.add_to_diag(diag); } - - fn msg(&self) -> DiagMessage { - self.msg.clone() - } } // FIXME(davidtwco): make translatable @@ -1169,6 +1160,7 @@ pub struct NonFmtPanicUnused { // Used because of two suggestions based on one Option<Span> impl<'a> LintDiagnostic<'a, ()> for NonFmtPanicUnused { fn decorate_lint<'b>(self, diag: &'b mut Diag<'a, ()>) { + diag.primary_message(fluent::lint_non_fmt_panic_unused); diag.arg("count", self.count); diag.note(fluent::lint_note); if let Some(span) = self.suggestion { @@ -1186,10 +1178,6 @@ impl<'a> LintDiagnostic<'a, ()> for NonFmtPanicUnused { ); } } - - fn msg(&self) -> DiagMessage { - fluent::lint_non_fmt_panic_unused - } } #[derive(LintDiagnostic)] @@ -1341,40 +1329,126 @@ pub struct SuspiciousDoubleRefCloneDiag<'a> { } // non_local_defs.rs -#[derive(LintDiagnostic)] pub enum NonLocalDefinitionsDiag { - #[diag(lint_non_local_definitions_impl)] - #[help] - #[note(lint_non_local)] - #[note(lint_exception)] - #[note(lint_non_local_definitions_deprecation)] Impl { depth: u32, body_kind_descr: &'static str, body_name: String, - #[subdiagnostic] cargo_update: Option<NonLocalDefinitionsCargoUpdateNote>, - #[suggestion(lint_const_anon, code = "_", applicability = "machine-applicable")] - const_anon: Option<Span>, + const_anon: Option<Option<Span>>, + move_to: Option<(Span, Vec<Span>)>, + may_remove: Option<(Span, String)>, + has_trait: bool, + self_ty_str: String, + of_trait_str: Option<String>, }, - #[diag(lint_non_local_definitions_macro_rules)] MacroRules { depth: u32, body_kind_descr: &'static str, body_name: String, - #[help] help: Option<()>, - #[help(lint_help_doctest)] doctest_help: Option<()>, - #[note(lint_non_local)] - #[note(lint_exception)] - #[note(lint_non_local_definitions_deprecation)] - notes: (), - #[subdiagnostic] cargo_update: Option<NonLocalDefinitionsCargoUpdateNote>, }, } +impl<'a> LintDiagnostic<'a, ()> for NonLocalDefinitionsDiag { + fn decorate_lint<'b>(self, diag: &'b mut Diag<'a, ()>) { + match self { + NonLocalDefinitionsDiag::Impl { + depth, + body_kind_descr, + body_name, + cargo_update, + const_anon, + move_to, + 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); + diag.note(fluent::lint_with_trait); + } else { + diag.note(fluent::lint_without_trait); + } + + if let Some((move_help, may_move)) = move_to { + let mut ms = MultiSpan::from_span(move_help); + for sp in may_move { + ms.push_span_label(sp, fluent::lint_non_local_definitions_may_move); + } + diag.span_help(ms, fluent::lint_non_local_definitions_impl_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); + } + if let Some(const_anon) = const_anon { + diag.note(fluent::lint_exception); + if let Some(const_anon) = const_anon { + diag.span_suggestion( + const_anon, + fluent::lint_const_anon, + "_", + Applicability::MachineApplicable, + ); + } + } + + diag.note(fluent::lint_non_local_definitions_deprecation); + } + NonLocalDefinitionsDiag::MacroRules { + depth, + body_kind_descr, + body_name, + help, + doctest_help, + cargo_update, + } => { + diag.primary_message(fluent::lint_non_local_definitions_macro_rules); + diag.arg("depth", depth); + diag.arg("body_kind_descr", body_kind_descr); + diag.arg("body_name", body_name); + + if let Some(()) = help { + diag.help(fluent::lint_help); + } + if let Some(()) = doctest_help { + diag.help(fluent::lint_help_doctest); + } + + diag.note(fluent::lint_non_local); + diag.note(fluent::lint_non_local_definitions_deprecation); + + if let Some(cargo_update) = cargo_update { + diag.subdiagnostic(&diag.dcx, cargo_update); + } + } + } + } +} + #[derive(Subdiagnostic)] #[note(lint_non_local_definitions_cargo_update)] pub struct NonLocalDefinitionsCargoUpdateNote { @@ -1411,13 +1485,10 @@ pub struct DropTraitConstraintsDiag<'a> { // Needed for def_path_str impl<'a> LintDiagnostic<'a, ()> for DropTraitConstraintsDiag<'_> { fn decorate_lint<'b>(self, diag: &'b mut Diag<'a, ()>) { + diag.primary_message(fluent::lint_drop_trait_constraints); diag.arg("predicate", self.predicate); diag.arg("needs_drop", self.tcx.def_path_str(self.def_id)); } - - fn msg(&self) -> DiagMessage { - fluent::lint_drop_trait_constraints - } } pub struct DropGlue<'a> { @@ -1428,12 +1499,9 @@ pub struct DropGlue<'a> { // Needed for def_path_str impl<'a> LintDiagnostic<'a, ()> for DropGlue<'_> { fn decorate_lint<'b>(self, diag: &'b mut Diag<'a, ()>) { + diag.primary_message(fluent::lint_drop_glue); diag.arg("needs_drop", self.tcx.def_path_str(self.def_id)); } - - fn msg(&self) -> DiagMessage { - fluent::lint_drop_glue - } } // types.rs @@ -1711,6 +1779,7 @@ pub struct ImproperCTypes<'a> { // Used because of the complexity of Option<DiagMessage>, DiagMessage, and Option<Span> impl<'a> LintDiagnostic<'a, ()> for ImproperCTypes<'_> { fn decorate_lint<'b>(self, diag: &'b mut Diag<'a, ()>) { + diag.primary_message(fluent::lint_improper_ctypes); diag.arg("ty", self.ty); diag.arg("desc", self.desc); diag.span_label(self.label, fluent::lint_label); @@ -1722,10 +1791,6 @@ impl<'a> LintDiagnostic<'a, ()> for ImproperCTypes<'_> { diag.span_note(note, fluent::lint_note); } } - - fn msg(&self) -> DiagMessage { - fluent::lint_improper_ctypes - } } #[derive(LintDiagnostic)] @@ -1854,6 +1919,7 @@ pub enum UnusedDefSuggestion { // Needed because of def_path_str impl<'a> LintDiagnostic<'a, ()> for UnusedDef<'_, '_> { fn decorate_lint<'b>(self, diag: &'b mut Diag<'a, ()>) { + diag.primary_message(fluent::lint_unused_def); diag.arg("pre", self.pre); diag.arg("post", self.post); diag.arg("def", self.cx.tcx.def_path_str(self.def_id)); @@ -1865,10 +1931,6 @@ impl<'a> LintDiagnostic<'a, ()> for UnusedDef<'_, '_> { diag.subdiagnostic(diag.dcx, sugg); } } - - fn msg(&self) -> DiagMessage { - fluent::lint_unused_def - } } #[derive(LintDiagnostic)] @@ -1937,15 +1999,12 @@ pub struct AsyncFnInTraitDiag { impl<'a> LintDiagnostic<'a, ()> for AsyncFnInTraitDiag { fn decorate_lint<'b>(self, diag: &'b mut Diag<'a, ()>) { + diag.primary_message(fluent::lint_async_fn_in_trait); diag.note(fluent::lint_note); if let Some(sugg) = self.sugg { diag.multipart_suggestion(fluent::lint_suggestion, sugg, Applicability::MaybeIncorrect); } } - - fn msg(&self) -> DiagMessage { - fluent::lint_async_fn_in_trait - } } #[derive(LintDiagnostic)] @@ -2273,10 +2332,8 @@ pub struct UnstableFeature { } impl<'a> LintDiagnostic<'a, ()> for UnstableFeature { - fn decorate_lint<'b>(self, _diag: &'b mut Diag<'a, ()>) {} - - fn msg(&self) -> DiagMessage { - self.msg.clone() + fn decorate_lint<'b>(self, diag: &'b mut Diag<'a, ()>) { + diag.primary_message(self.msg); } } @@ -2738,12 +2795,9 @@ pub struct AmbiguousGlobImports { impl<'a, G: EmissionGuarantee> LintDiagnostic<'a, G> for AmbiguousGlobImports { fn decorate_lint<'b>(self, diag: &'b mut Diag<'a, G>) { + diag.primary_message(self.ambiguity.msg.clone()); rustc_errors::report_ambiguity_error(diag, self.ambiguity); } - - fn msg(&self) -> DiagMessage { - DiagMessage::Str(self.ambiguity.msg.clone().into()) - } } #[derive(LintDiagnostic)] diff --git a/compiler/rustc_lint/src/non_fmt_panic.rs b/compiler/rustc_lint/src/non_fmt_panic.rs index a6057afcbd6..c9d67854112 100644 --- a/compiler/rustc_lint/src/non_fmt_panic.rs +++ b/compiler/rustc_lint/src/non_fmt_panic.rs @@ -123,7 +123,8 @@ fn check_panic<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>, arg: &'tc } #[allow(rustc::diagnostic_outside_of_impl)] - cx.span_lint(NON_FMT_PANICS, arg_span, fluent::lint_non_fmt_panic, |lint| { + cx.span_lint(NON_FMT_PANICS, arg_span, |lint| { + lint.primary_message(fluent::lint_non_fmt_panic); lint.arg("name", symbol); lint.note(fluent::lint_note); lint.note(fluent::lint_more_info_note); diff --git a/compiler/rustc_lint/src/non_local_def.rs b/compiler/rustc_lint/src/non_local_def.rs index b3e93748a16..42b03f47a5b 100644 --- a/compiler/rustc_lint/src/non_local_def.rs +++ b/compiler/rustc_lint/src/non_local_def.rs @@ -1,3 +1,6 @@ +use rustc_errors::MultiSpan; +use rustc_hir::intravisit::{self, Visitor}; +use rustc_hir::HirId; use rustc_hir::{def::DefKind, Body, Item, ItemKind, Node, TyKind}; use rustc_hir::{Path, QPath}; use rustc_infer::infer::InferCtxt; @@ -7,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}; @@ -134,35 +138,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; @@ -202,8 +179,7 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions { // Get the span of the parent const item ident (if it's a not a const anon). // // Used to suggest changing the const item to a const anon. - let span_for_const_anon_suggestion = if self.body_depth == 1 - && parent_def_kind == DefKind::Const + let span_for_const_anon_suggestion = if parent_def_kind == DefKind::Const && parent_opt_item_name != Some(kw::Underscore) && let Some(parent) = parent.as_local() && let Node::Item(item) = cx.tcx.hir_node_by_def_id(parent) @@ -215,9 +191,76 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions { None }; + let mut collector = PathCollector { paths: Vec::new() }; + collector.visit_ty(&impl_.self_ty); + if let Some(of_trait) = &impl_.of_trait { + collector.visit_trait_ref(of_trait); + } + collector.visit_generics(&impl_.generics); + + let mut may_move: Vec<Span> = collector + .paths + .into_iter() + .filter_map(|path| { + if let Some(did) = path.res.opt_def_id() + && did_has_local_parent(did, cx.tcx, parent, parent_parent) + { + Some(cx.tcx.def_span(did)) + } else { + None + } + }) + .collect(); + may_move.sort(); + may_move.dedup(); + + 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, + }; + + 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 + }; + let move_to = if may_move.is_empty() { + ms.push_span_label( + cx.tcx.def_span(parent), + fluent::lint_non_local_definitions_impl_move_help, + ); + None + } else { + Some((cx.tcx.def_span(parent), may_move)) + }; + cx.emit_span_lint( NON_LOCAL_DEFINITIONS, - item.span, + ms, NonLocalDefinitionsDiag::Impl { depth: self.body_depth, body_kind_descr: cx.tcx.def_kind_descr(parent_def_kind, parent), @@ -225,7 +268,12 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions { .map(|s| s.to_ident_string()) .unwrap_or_else(|| "<unnameable>".to_string()), cargo_update: cargo_update(), - const_anon: span_for_const_anon_suggestion, + const_anon, + self_ty_str, + of_trait_str, + move_to, + may_remove, + has_trait: impl_.of_trait.is_some(), }, ) } @@ -250,7 +298,6 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions { cargo_update: cargo_update(), help: (!is_at_toplevel_doctest).then_some(()), doctest_help: is_at_toplevel_doctest.then_some(()), - notes: (), }, ) } @@ -270,7 +317,7 @@ fn impl_trait_ref_has_enough_non_local_candidates<'tcx>( tcx: TyCtxt<'tcx>, infer_span: Span, trait_def_id: DefId, - binder: EarlyBinder<TraitRef<'tcx>>, + binder: EarlyBinder<'tcx, TraitRef<'tcx>>, mut did_has_local_parent: impl FnMut(DefId) -> bool, ) -> bool { let infcx = tcx @@ -343,6 +390,54 @@ impl<'a, 'tcx, F: FnMut(DefId) -> bool> TypeFolder<TyCtxt<'tcx>> } } +/// Simple hir::Path collector +struct PathCollector<'tcx> { + paths: Vec<Path<'tcx>>, +} + +impl<'tcx> Visitor<'tcx> for PathCollector<'tcx> { + fn visit_path(&mut self, path: &Path<'tcx>, _id: HirId) { + self.paths.push(path.clone()); // need to clone, bc of the restricted lifetime + intravisit::walk_path(self, path) + } +} + +/// 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. /// @@ -384,3 +479,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)), + } +} |
