diff --git a/compiler/rustc_error_messages/locales/en-US/lint.ftl b/compiler/rustc_error_messages/locales/en-US/lint.ftl index 78b8f6aaae9..babdbb1cc19 100644 --- a/compiler/rustc_error_messages/locales/en-US/lint.ftl +++ b/compiler/rustc_error_messages/locales/en-US/lint.ftl @@ -20,6 +20,18 @@ lint_deprecated_lint_name = lint name `{$name}` is deprecated and may not have an effect in the future. .suggestion = change it to +lint_renamed_or_removed_lint_suggestion = use the new name + +lint_unknown_lint = + unknown lint: `{$name}` + .suggestion = did you mean + +lint_ignored_unless_crate_specified = {$level}({$name}) is ignored unless specified at crate level + +lint_unknown_gated_lint = + unknown lint: `{$name}` + .note = the `{$name}` lint is unstable + lint_hidden_unicode_codepoints = unicode codepoint changing visible direction of text present in {$label} .label = this {$label} contains {$count -> [one] an invisible diff --git a/compiler/rustc_lint/src/errors.rs b/compiler/rustc_lint/src/errors.rs index 82ec88fbeeb..0ea643fd69b 100644 --- a/compiler/rustc_lint/src/errors.rs +++ b/compiler/rustc_lint/src/errors.rs @@ -10,12 +10,12 @@ use rustc_span::{Span, Symbol}; #[derive(Diagnostic)] #[diag(lint_overruled_attribute, code = "E0453")] -pub struct OverruledAttribute { +pub struct OverruledAttribute<'a> { #[primary_span] pub span: Span, #[label] pub overruled: Span, - pub lint_level: String, + pub lint_level: &'a str, pub lint_source: Symbol, #[subdiagnostic] pub sub: OverruledAttributeSub, diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs index edbf0c6f37a..b335f330f5d 100644 --- a/compiler/rustc_lint/src/levels.rs +++ b/compiler/rustc_lint/src/levels.rs @@ -1,12 +1,15 @@ +#![deny(rustc::untranslatable_diagnostic)] +#![deny(rustc::diagnostic_outside_of_impl)] use crate::context::{CheckLintNameResult, LintStore}; use crate::late::unerased_lint_store; -use crate::lints::DeprecatedLintName; +use crate::lints::{ + DeprecatedLintName, IgnoredUnlessCrateSpecified, OverruledAtributeLint, RenamedOrRemovedLint, + UnknownLint, +}; use rustc_ast as ast; use rustc_ast_pretty::pprust; use rustc_data_structures::fx::FxHashMap; -use rustc_errors::{ - Applicability, DecorateLint, Diagnostic, DiagnosticBuilder, DiagnosticMessage, MultiSpan, -}; +use rustc_errors::{fluent, DecorateLint, DiagnosticBuilder, DiagnosticMessage, MultiSpan}; use rustc_hir as hir; use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::HirId; @@ -18,6 +21,7 @@ use rustc_middle::lint::{ }; use rustc_middle::ty::query::Providers; use rustc_middle::ty::{RegisteredTools, TyCtxt}; +use rustc_session::lint::builtin::{RENAMED_AND_REMOVED_LINTS, UNKNOWN_LINTS, UNUSED_ATTRIBUTES}; use rustc_session::lint::{ builtin::{self, FORBIDDEN_LINT_GROUPS, SINGLE_USE_LIFETIMES, UNFULFILLED_LINT_EXPECTATIONS}, Level, Lint, LintExpectationId, LintId, @@ -586,57 +590,32 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> { old_src, id_name ); - - let decorate_diag = |diag: &mut Diagnostic| { - diag.span_label(src.span(), "overruled by previous forbid"); - match old_src { - LintLevelSource::Default => { - diag.note(&format!( - "`forbid` lint level is the default for {}", - id.to_string() - )); - } - LintLevelSource::Node { span, reason, .. } => { - diag.span_label(span, "`forbid` level set here"); - if let Some(rationale) = reason { - diag.note(rationale.as_str()); - } - } - LintLevelSource::CommandLine(_, _) => { - diag.note("`forbid` lint level was set on command line"); - } + let sub = match old_src { + LintLevelSource::Default => { + OverruledAttributeSub::DefaultSource { id: id.to_string() } } + LintLevelSource::Node { span, reason, .. } => { + OverruledAttributeSub::NodeSource { span, reason } + } + LintLevelSource::CommandLine(_, _) => OverruledAttributeSub::CommandLineSource, }; if !fcw_warning { self.sess.emit_err(OverruledAttribute { span: src.span(), overruled: src.span(), - lint_level: level.as_str().to_string(), + lint_level: level.as_str(), lint_source: src.name(), - sub: match old_src { - LintLevelSource::Default => { - OverruledAttributeSub::DefaultSource { id: id.to_string() } - } - LintLevelSource::Node { span, reason, .. } => { - OverruledAttributeSub::NodeSource { span, reason } - } - LintLevelSource::CommandLine(_, _) => { - OverruledAttributeSub::CommandLineSource - } - }, + sub, }); } else { - self.struct_lint( + self.emit_spanned_lint( FORBIDDEN_LINT_GROUPS, - Some(src.span().into()), - format!( - "{}({}) incompatible with previous forbid", - level.as_str(), - src.name(), - ), - |lint| { - decorate_diag(lint); - lint + src.span().into(), + OverruledAtributeLint { + overruled: src.span(), + lint_level: level.as_str(), + lint_source: src.name(), + sub, }, ); } @@ -908,54 +887,22 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> { _ if !self.warn_about_weird_lints => {} CheckLintNameResult::Warning(msg, renamed) => { - let lint = builtin::RENAMED_AND_REMOVED_LINTS; - let (renamed_lint_level, src) = self.provider.get_lint_level(lint, &sess); - struct_lint_level( - self.sess, - lint, - renamed_lint_level, - src, - Some(sp.into()), - msg, - |lint| { - if let Some(new_name) = &renamed { - lint.span_suggestion( - sp, - "use the new name", - new_name, - Applicability::MachineApplicable, - ); - } - lint - }, + self.emit_spanned_lint( + RENAMED_AND_REMOVED_LINTS, + sp.into(), + RenamedOrRemovedLint { msg, suggestion: sp, renamed }, ); } CheckLintNameResult::NoLint(suggestion) => { - let lint = builtin::UNKNOWN_LINTS; - let (level, src) = self.provider.get_lint_level(lint, self.sess); let name = if let Some(tool_ident) = tool_ident { format!("{}::{}", tool_ident.name, name) } else { name.to_string() }; - struct_lint_level( - self.sess, - lint, - level, - src, - Some(sp.into()), - format!("unknown lint: `{}`", name), - |lint| { - if let Some(suggestion) = suggestion { - lint.span_suggestion( - sp, - "did you mean", - suggestion, - Applicability::MaybeIncorrect, - ); - } - lint - }, + self.emit_spanned_lint( + UNKNOWN_LINTS, + sp.into(), + UnknownLint { name, suggestion: sp, replace: suggestion }, ); } } @@ -1001,20 +948,10 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> { continue }; - let lint = builtin::UNUSED_ATTRIBUTES; - let (lint_level, lint_src) = self.provider.get_lint_level(lint, &self.sess); - struct_lint_level( - self.sess, - lint, - lint_level, - lint_src, - Some(lint_attr_span.into()), - format!( - "{}({}) is ignored unless specified at crate level", - level.as_str(), - lint_attr_name - ), - |lint| lint, + self.emit_spanned_lint( + UNUSED_ATTRIBUTES, + lint_attr_span.into(), + IgnoredUnlessCrateSpecified { level: level.as_str(), name: lint_attr_name }, ); // don't set a separate error for every lint in the group break; @@ -1038,11 +975,10 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> { level, src, Some(span.into()), - format!("unknown lint: `{}`", lint_id.lint.name_lower()), + fluent::lint_unknown_gated_lint, |lint| { - lint.note( - &format!("the `{}` lint is unstable", lint_id.lint.name_lower(),), - ); + lint.set_arg("name", lint_id.lint.name_lower()); + lint.note(fluent::note); add_feature_diagnostics(lint, &self.sess.parse_sess, feature); lint }, diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index 942497a1d57..eb86bb7b925 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -4,7 +4,7 @@ use rustc_macros::{LintDiagnostic, Subdiagnostic}; use rustc_middle::ty::{Predicate, Ty, TyCtxt}; use rustc_span::{symbol::Ident, Span, Symbol}; -use crate::LateContext; +use crate::{errors::OverruledAttributeSub, LateContext}; // array_into_iter.rs #[derive(LintDiagnostic)] @@ -51,7 +51,18 @@ pub struct EnumIntrinsicsMemVariant<'a> { // levels.rs #[derive(LintDiagnostic)] -#[diag(lint::deprecated_lint_name)] +#[diag(lint_overruled_attribute)] +pub struct OverruledAtributeLint<'a> { + #[label] + pub overruled: Span, + pub lint_level: &'a str, + pub lint_source: Symbol, + #[subdiagnostic] + pub sub: OverruledAttributeSub, +} + +#[derive(LintDiagnostic)] +#[diag(lint_deprecated_lint_name)] pub struct DeprecatedLintName<'a> { pub name: String, #[suggestion(code = "{replace}", applicability = "machine-applicable")] @@ -59,6 +70,68 @@ pub struct DeprecatedLintName<'a> { pub replace: &'a str, } +pub struct RenamedOrRemovedLint<'a> { + pub msg: &'a str, + pub suggestion: Span, + pub renamed: &'a Option, +} + +impl<'a> DecorateLint<'a, ()> for RenamedOrRemovedLint<'_> { + fn decorate_lint<'b>( + self, + diag: &'b mut rustc_errors::DiagnosticBuilder<'a, ()>, + ) -> &'b mut rustc_errors::DiagnosticBuilder<'a, ()> { + if let Some(new_name) = self.renamed { + diag.span_suggestion( + self.suggestion, + fluent::lint_renamed_or_removed_lint_suggestion, + new_name, + Applicability::MachineApplicable, + ); + }; + diag + } + + fn msg(&self) -> rustc_errors::DiagnosticMessage { + rustc_errors::DiagnosticMessage::Str(self.msg.to_string()) + } +} + +pub struct UnknownLint<'a> { + pub name: String, + pub suggestion: Span, + pub replace: &'a Option, +} + +impl<'a> DecorateLint<'a, ()> for UnknownLint<'_> { + fn decorate_lint<'b>( + self, + diag: &'b mut rustc_errors::DiagnosticBuilder<'a, ()>, + ) -> &'b mut rustc_errors::DiagnosticBuilder<'a, ()> { + diag.set_arg("name", self.name); + if let Some(replace) = self.replace { + diag.span_suggestion( + self.suggestion, + fluent::suggestion, + replace, + Applicability::MaybeIncorrect, + ); + }; + diag + } + + fn msg(&self) -> rustc_errors::DiagnosticMessage { + fluent::lint_unknown_lint + } +} + +#[derive(LintDiagnostic)] +#[diag(lint_ignored_unless_crate_specified)] +pub struct IgnoredUnlessCrateSpecified<'a> { + pub level: &'a str, + pub name: Symbol, +} + // methods.rs #[derive(LintDiagnostic)] #[diag(lint_cstring_ptr)]