From 78fce795d8084e288278270438a49df6172dd36c Mon Sep 17 00:00:00 2001 From: Rejyr Date: Thu, 10 Nov 2022 19:32:30 -0500 Subject: [PATCH] refactor: refactor to derive for some lints. --- .../locales/en-US/lint.ftl | 4 +- compiler/rustc_lint/src/builtin.rs | 16 +- compiler/rustc_lint/src/expect.rs | 6 +- compiler/rustc_lint/src/levels.rs | 13 +- compiler/rustc_lint/src/lints.rs | 176 +++++++----------- compiler/rustc_lint/src/types.rs | 26 +-- 6 files changed, 100 insertions(+), 141 deletions(-) diff --git a/compiler/rustc_error_messages/locales/en-US/lint.ftl b/compiler/rustc_error_messages/locales/en-US/lint.ftl index 5330ce504b2..1518adf8e4e 100644 --- a/compiler/rustc_error_messages/locales/en-US/lint.ftl +++ b/compiler/rustc_error_messages/locales/en-US/lint.ftl @@ -15,6 +15,7 @@ lint_enum_intrinsics_mem_variant = lint_expectation = this lint expectation is unfulfilled .note = the `unfulfilled_lint_expectations` lint can't be expected and will always produce this message + .rationale = {$rationale} lint_for_loops_over_fallibles = for loop over {$article} `{$ty}`. This is more readably written as an `if let` statement @@ -39,7 +40,8 @@ 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_renamed_or_removed_lint = {$msg} + .suggestion = use the new name lint_unknown_lint = unknown lint: `{$name}` diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index 8a34afb1ff5..1dae563577a 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -26,7 +26,8 @@ use crate::{ BuiltinAnonymousParams, BuiltinBoxPointers, BuiltinConstNoMangle, BuiltinDeprecatedAttrUsed, BuiltinDerefNullptr, BuiltinEllipsisInclusiveRangePatternsLint, BuiltinExplicitOutlives, BuiltinExplicitOutlivesSuggestion, BuiltinIncompleteFeatures, - BuiltinKeywordIdents, BuiltinMissingCopyImpl, BuiltinMissingDebugImpl, BuiltinMissingDoc, + BuiltinIncompleteFeaturesHelp, BuiltinIncompleteFeaturesNote, BuiltinKeywordIdents, + BuiltinMissingCopyImpl, BuiltinMissingDebugImpl, BuiltinMissingDoc, BuiltinMutablesTransmutes, BuiltinNoMangleGeneric, BuiltinNonShorthandFieldPatterns, BuiltinSpecialModuleNameUsed, BuiltinTrivialBounds, BuiltinUnexpectedCliConfigName, BuiltinUnexpectedCliConfigValue, BuiltinUnnameableTestItems, BuiltinUnreachablePub, @@ -2379,14 +2380,17 @@ impl EarlyLintPass for IncompleteFeatures { .chain(features.declared_lib_features.iter().map(|(name, span)| (name, span))) .filter(|(&name, _)| features.incomplete(name)) .for_each(|(&name, &span)| { + let note = rustc_feature::find_feature_issue(name, GateIssue::Language) + .map(|n| BuiltinIncompleteFeaturesNote { n }); + let help = if HAS_MIN_FEATURES.contains(&name) { + Some(BuiltinIncompleteFeaturesHelp) + } else { + None + }; cx.emit_spanned_lint( INCOMPLETE_FEATURES, span, - BuiltinIncompleteFeatures { - name, - note: rustc_feature::find_feature_issue(name, GateIssue::Language), - help: HAS_MIN_FEATURES.contains(&name).then_some(()), - }, + BuiltinIncompleteFeatures { name, note, help }, ); }); } diff --git a/compiler/rustc_lint/src/expect.rs b/compiler/rustc_lint/src/expect.rs index c0e62a8d9fc..8985ccee0cd 100644 --- a/compiler/rustc_lint/src/expect.rs +++ b/compiler/rustc_lint/src/expect.rs @@ -1,6 +1,6 @@ #![deny(rustc::untranslatable_diagnostic)] #![deny(rustc::diagnostic_outside_of_impl)] -use crate::lints::Expectation; +use crate::lints::{Expectation, ExpectationNote}; use rustc_middle::ty::query::Providers; use rustc_middle::ty::TyCtxt; use rustc_session::lint::builtin::UNFULFILLED_LINT_EXPECTATIONS; @@ -29,11 +29,13 @@ fn check_expectations(tcx: TyCtxt<'_>, tool_filter: Option) { if !fulfilled_expectations.contains(&id) && tool_filter.map_or(true, |filter| expectation.lint_tool == Some(filter)) { + let rationale = expectation.reason.map(|rationale| ExpectationNote { rationale }); + let note = expectation.is_unfulfilled_lint_expectations.then_some(()); tcx.emit_spanned_lint( UNFULFILLED_LINT_EXPECTATIONS, *hir_id, expectation.emission_span, - Expectation { expectation }, + Expectation { rationale, note }, ); } } else { diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs index b335f330f5d..500b1f36558 100644 --- a/compiler/rustc_lint/src/levels.rs +++ b/compiler/rustc_lint/src/levels.rs @@ -4,7 +4,7 @@ use crate::context::{CheckLintNameResult, LintStore}; use crate::late::unerased_lint_store; use crate::lints::{ DeprecatedLintName, IgnoredUnlessCrateSpecified, OverruledAtributeLint, RenamedOrRemovedLint, - UnknownLint, + RenamedOrRemovedLintSuggestion, UnknownLint, UnknownLintSuggestion, }; use rustc_ast as ast; use rustc_ast_pretty::pprust; @@ -887,10 +887,15 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> { _ if !self.warn_about_weird_lints => {} CheckLintNameResult::Warning(msg, renamed) => { + let suggestion = + renamed.as_ref().map(|replace| RenamedOrRemovedLintSuggestion { + suggestion: sp, + replace: replace.as_str(), + }); self.emit_spanned_lint( RENAMED_AND_REMOVED_LINTS, sp.into(), - RenamedOrRemovedLint { msg, suggestion: sp, renamed }, + RenamedOrRemovedLint { msg, suggestion }, ); } CheckLintNameResult::NoLint(suggestion) => { @@ -899,10 +904,12 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> { } else { name.to_string() }; + let suggestion = suggestion + .map(|replace| UnknownLintSuggestion { suggestion: sp, replace }); self.emit_spanned_lint( UNKNOWN_LINTS, sp.into(), - UnknownLint { name, suggestion: sp, replace: suggestion }, + UnknownLint { name, suggestion }, ); } } diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index a3549346604..faeb396ce8c 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -3,10 +3,7 @@ use std::num::NonZeroU32; use rustc_errors::{fluent, AddToDiagnostic, Applicability, DecorateLint, DiagnosticMessage}; use rustc_hir::def_id::DefId; use rustc_macros::{LintDiagnostic, Subdiagnostic}; -use rustc_middle::{ - lint::LintExpectation, - ty::{Predicate, Ty, TyCtxt}, -}; +use rustc_middle::ty::{Predicate, Ty, TyCtxt}; use rustc_span::{edition::Edition, symbol::Ident, Span, Symbol}; use crate::{errors::OverruledAttributeSub, LateContext}; @@ -80,6 +77,7 @@ pub struct BuiltinMissingDebugImpl<'a> { pub def_id: DefId, } +// Needed for def_path_str impl<'a> DecorateLint<'a, ()> for BuiltinMissingDebugImpl<'_> { fn decorate_lint<'b>( self, @@ -225,31 +223,24 @@ pub struct BuiltinExplicitOutlivesSuggestion { pub applicability: Applicability, } +#[derive(LintDiagnostic)] +#[diag(lint_builtin_incomplete_features)] pub struct BuiltinIncompleteFeatures { pub name: Symbol, - pub note: Option, - pub help: Option<()>, + #[subdiagnostic] + pub note: Option, + #[subdiagnostic] + pub help: Option, } -impl<'a> DecorateLint<'a, ()> for BuiltinIncompleteFeatures { - 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(n) = self.note { - diag.set_arg("n", n); - diag.note(fluent::note); - } - if let Some(_) = self.help { - diag.help(fluent::help); - } - diag - } +#[derive(Subdiagnostic)] +#[help(help)] +pub struct BuiltinIncompleteFeaturesHelp; - fn msg(&self) -> DiagnosticMessage { - fluent::lint_builtin_incomplete_features - } +#[derive(Subdiagnostic)] +#[note(note)] +pub struct BuiltinIncompleteFeaturesNote { + pub n: NonZeroU32, } // FIXME: migrate "the type `{}` does not permit {}" @@ -308,29 +299,19 @@ pub struct EnumIntrinsicsMemVariant<'a> { } // expect.rs -pub struct Expectation<'a> { - pub expectation: &'a LintExpectation, +#[derive(LintDiagnostic)] +#[diag(lint_expectation)] +pub struct Expectation { + #[subdiagnostic] + pub rationale: Option, + #[note] + pub note: Option<()>, } -impl<'a> DecorateLint<'a, ()> for Expectation<'_> { - fn decorate_lint<'b>( - self, - diag: &'b mut rustc_errors::DiagnosticBuilder<'a, ()>, - ) -> &'b mut rustc_errors::DiagnosticBuilder<'a, ()> { - if let Some(rationale) = self.expectation.reason { - diag.note(rationale.as_str()); - } - - if self.expectation.is_unfulfilled_lint_expectations { - diag.note(fluent::note); - } - - diag - } - - fn msg(&self) -> DiagnosticMessage { - fluent::lint_expectation - } +#[derive(Subdiagnostic)] +#[note(rationale)] +pub struct ExpectationNote { + pub rationale: Symbol, } // for_loops_over_fallibles.rs @@ -511,59 +492,37 @@ pub struct DeprecatedLintName<'a> { pub replace: &'a str, } +// FIXME: Non-translatable msg +#[derive(LintDiagnostic)] +#[diag(lint_renamed_or_removed_lint)] pub struct RenamedOrRemovedLint<'a> { pub msg: &'a str, + #[subdiagnostic] + pub suggestion: Option>, +} + +#[derive(Subdiagnostic)] +#[suggestion(suggestion, code = "{replace}", applicability = "machine-applicable")] +pub struct RenamedOrRemovedLintSuggestion<'a> { + #[primary_span] pub suggestion: Span, - pub renamed: &'a Option, + pub replace: &'a str, } -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> { +#[derive(LintDiagnostic)] +#[diag(lint_unknown_lint)] +pub struct UnknownLint { pub name: String, - pub suggestion: Span, - pub replace: &'a Option, + #[subdiagnostic] + pub suggestion: 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(Subdiagnostic)] +#[suggestion(suggestion, code = "{replace}", applicability = "maybe-incorrect")] +pub struct UnknownLintSuggestion { + #[primary_span] + pub suggestion: Span, + pub replace: Symbol, } #[derive(LintDiagnostic)] @@ -618,6 +577,7 @@ pub struct NonFmtPanicUnused { pub suggestion: Option, } +// Used because of two suggestions based on one Option impl<'a> DecorateLint<'a, ()> for NonFmtPanicUnused { fn decorate_lint<'b>( self, @@ -803,6 +763,7 @@ pub struct DropTraitConstraintsDiag<'a> { pub def_id: DefId, } +// Needed for def_path_str impl<'a> DecorateLint<'a, ()> for DropTraitConstraintsDiag<'_> { fn decorate_lint<'b>( self, @@ -822,6 +783,7 @@ pub struct DropGlue<'a> { pub def_id: DefId, } +// Needed for def_path_str impl<'a> DecorateLint<'a, ()> for DropGlue<'_> { fn decorate_lint<'b>( self, @@ -902,35 +864,22 @@ pub enum OverflowingBinHexSub<'a> { Help { suggestion_ty: &'a str }, } +#[derive(LintDiagnostic)] +#[diag(lint_overflowing_int)] +#[note] pub struct OverflowingInt<'a> { pub ty: &'a str, pub lit: String, pub min: i128, pub max: u128, - pub suggestion_ty: Option<&'a str>, + #[subdiagnostic] + pub help: Option>, } -// FIXME: refactor with `Option<&'a str>` in macro -impl<'a> DecorateLint<'a, ()> for OverflowingInt<'_> { - fn decorate_lint<'b>( - self, - diag: &'b mut rustc_errors::DiagnosticBuilder<'a, ()>, - ) -> &'b mut rustc_errors::DiagnosticBuilder<'a, ()> { - diag.set_arg("ty", self.ty); - diag.set_arg("lit", self.lit); - diag.set_arg("min", self.min); - diag.set_arg("max", self.max); - diag.note(fluent::note); - if let Some(suggestion_ty) = self.suggestion_ty { - diag.set_arg("suggestion_ty", suggestion_ty); - diag.help(fluent::help); - } - diag - } - - fn msg(&self) -> rustc_errors::DiagnosticMessage { - fluent::lint_overflowing_int - } +#[derive(Subdiagnostic)] +#[help(help)] +pub struct OverflowingIntHelp<'a> { + pub suggestion_ty: &'a str, } #[derive(LintDiagnostic)] @@ -972,6 +921,7 @@ pub struct ImproperCTypes<'a> { pub span_note: Option, } +// Used because of the complexity of Option, DiagnosticMessage, and Option impl<'a> DecorateLint<'a, ()> for ImproperCTypes<'_> { fn decorate_lint<'b>( self, @@ -1074,7 +1024,7 @@ pub struct UnusedDef<'a, 'b> { pub note: Option, } -// FIXME: refactor with `Option` in macro +// Needed because of def_path_str impl<'a> DecorateLint<'a, ()> for UnusedDef<'_, '_> { fn decorate_lint<'b>( self, diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs index a112292eb14..1300a2fe27a 100644 --- a/compiler/rustc_lint/src/types.rs +++ b/compiler/rustc_lint/src/types.rs @@ -3,7 +3,7 @@ use crate::lints::{ AtomicOrderingFence, AtomicOrderingLoad, AtomicOrderingStore, ImproperCTypes, InvalidAtomicOrderingDiag, OnlyCastu8ToChar, OverflowingBinHex, OverflowingBinHexSign, - OverflowingBinHexSub, OverflowingInt, OverflowingLiteral, OverflowingUInt, + OverflowingBinHexSub, OverflowingInt, OverflowingIntHelp, OverflowingLiteral, OverflowingUInt, RangeEndpointOutOfRange, UnusedComparisons, VariantSizeDifferencesDiag, }; use crate::{LateContext, LateLintPass, LintContext}; @@ -339,24 +339,18 @@ fn lint_int_literal<'tcx>( return; } + let lit = cx + .sess() + .source_map() + .span_to_snippet(lit.span) + .expect("must get snippet from literal"); + let help = get_type_suggestion(cx.typeck_results().node_type(e.hir_id), v, negative) + .map(|suggestion_ty| OverflowingIntHelp { suggestion_ty }); + cx.emit_spanned_lint( OVERFLOWING_LITERALS, e.span, - OverflowingInt { - ty: t.name_str(), - lit: cx - .sess() - .source_map() - .span_to_snippet(lit.span) - .expect("must get snippet from literal"), - min, - max, - suggestion_ty: get_type_suggestion( - cx.typeck_results().node_type(e.hir_id), - v, - negative, - ), - }, + OverflowingInt { ty: t.name_str(), lit, min, max, help }, ); } }