From 264c198d7c1aa182bef4a99f87d456e5a04ca5aa Mon Sep 17 00:00:00 2001 From: clubby789 Date: Sat, 25 Feb 2023 18:18:51 +0000 Subject: [PATCH] Add lint for `String` in diagnostic implementation --- compiler/rustc_lint/locales/en-US.ftl | 3 +++ compiler/rustc_lint/src/internal.rs | 34 +++++++++++++++++++++++++-- compiler/rustc_lint/src/lib.rs | 1 + compiler/rustc_lint/src/lints.rs | 5 ++++ compiler/rustc_span/src/symbol.rs | 1 + 5 files changed, 42 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_lint/locales/en-US.ftl b/compiler/rustc_lint/locales/en-US.ftl index b1e7cc69a809b..5e4561e6762af 100644 --- a/compiler/rustc_lint/locales/en-US.ftl +++ b/compiler/rustc_lint/locales/en-US.ftl @@ -90,6 +90,9 @@ lint_non_existant_doc_keyword = found non-existing keyword `{$keyword}` used in lint_diag_out_of_impl = diagnostics should only be created in `IntoDiagnostic`/`AddToDiagnostic` impls +lint_string_in_diag = use of String in diagnostic + .note = this could indicate incorrectly eagerly converting to a string + lint_untranslatable_diag = diagnostics should be created using translatable messages lint_bad_opt_access = {$msg} diff --git a/compiler/rustc_lint/src/internal.rs b/compiler/rustc_lint/src/internal.rs index 2fd0ef3cda8b7..017384015a63a 100644 --- a/compiler/rustc_lint/src/internal.rs +++ b/compiler/rustc_lint/src/internal.rs @@ -3,7 +3,7 @@ use crate::lints::{ BadOptAccessDiag, DefaultHashTypesDiag, DiagOutOfImpl, LintPassByHand, NonExistantDocKeyword, - QueryInstability, TyQualified, TykindDiag, TykindKind, UntranslatableDiag, + QueryInstability, StringInDiagnostic, TyQualified, TykindDiag, TykindKind, UntranslatableDiag, }; use crate::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext}; use rustc_ast as ast; @@ -338,7 +338,14 @@ declare_tool_lint! { report_in_external_macro: true } -declare_lint_pass!(Diagnostics => [ UNTRANSLATABLE_DIAGNOSTIC, DIAGNOSTIC_OUTSIDE_OF_IMPL ]); +declare_tool_lint! { + pub rustc::STRING_IN_DIAGNOSTIC, + Warn, + "prevent the use of `String` in diagnostics, which could indicate incorrect eager conversion", + report_in_external_macro: true +} + +declare_lint_pass!(Diagnostics => [ UNTRANSLATABLE_DIAGNOSTIC, DIAGNOSTIC_OUTSIDE_OF_IMPL, STRING_IN_DIAGNOSTIC ]); impl LateLintPass<'_> for Diagnostics { fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { @@ -395,6 +402,29 @@ impl LateLintPass<'_> for Diagnostics { } } +impl EarlyLintPass for Diagnostics { + fn check_item(&mut self, cx: &EarlyContext<'_>, item: &ast::Item) { + if cx.sess().find_by_name(&item.attrs, sym::diag).is_none() { + return; + } + + let variants = match &item.kind { + ast::ItemKind::Struct(variant, _) => vec![variant], + ast::ItemKind::Enum(enum_def, _) => enum_def.variants.iter().map(|v| &v.data).collect(), + _ => vec![], + }; + + for field in variants.iter().flat_map(|d| d.fields()) { + if let ast::TyKind::Path(_, path) = &field.ty.kind + && let [path] = path.segments.as_ref() + && path.ident.name == sym::String + { + cx.emit_spanned_lint(STRING_IN_DIAGNOSTIC, path.span(), StringInDiagnostic); + } + } + } +} + declare_tool_lint! { pub rustc::BAD_OPT_ACCESS, Deny, diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index 2070ffea4d99e..ac63b22547211 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -514,6 +514,7 @@ fn register_internals(store: &mut LintStore) { store.register_lints(&TyTyKind::get_lints()); store.register_late_pass(|_| Box::new(TyTyKind)); store.register_lints(&Diagnostics::get_lints()); + store.register_early_pass(|| Box::new(Diagnostics)); store.register_late_pass(|_| Box::new(Diagnostics)); store.register_lints(&BadOptAccess::get_lints()); store.register_late_pass(|_| Box::new(BadOptAccess)); diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index 2d9aa9074be79..6235c90d08a8a 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -800,6 +800,11 @@ pub struct NonExistantDocKeyword { #[diag(lint_diag_out_of_impl)] pub struct DiagOutOfImpl; +#[derive(LintDiagnostic)] +#[diag(lint_string_in_diag)] +#[note] +pub struct StringInDiagnostic; + #[derive(LintDiagnostic)] #[diag(lint_untranslatable_diag)] pub struct UntranslatableDiag; diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 37d2aea42ad8f..e232722ea9167 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -608,6 +608,7 @@ symbols! { derive_default_enum, destruct, destructuring_assignment, + diag, diagnostic, direct, discriminant_kind,