diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index 83d8dce1540..7e92b2d6b3d 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -2,10 +2,114 @@ use rustc_errors::{fluent, AddSubdiagnostic, Applicability, DecorateLint, Emissi use rustc_hir::def_id::DefId; use rustc_macros::{LintDiagnostic, SessionSubdiagnostic}; use rustc_middle::ty::{Predicate, Ty, TyCtxt}; -use rustc_span::{Span, Symbol}; +use rustc_span::{symbol::Ident, Span, Symbol}; use crate::LateContext; +#[derive(LintDiagnostic)] +#[diag(lint_non_camel_case_type)] +pub struct NonCamelCaseType<'a> { + pub sort: &'a str, + pub name: &'a str, + #[subdiagnostic] + pub sub: NonCamelCaseTypeSub, +} + +#[derive(SessionSubdiagnostic)] +pub enum NonCamelCaseTypeSub { + #[label(label)] + Label { + #[primary_span] + span: Span, + }, + #[suggestion(suggestion, code = "{replace}", applicability = "maybe-incorrect")] + Suggestion { + #[primary_span] + span: Span, + replace: String, + }, +} + +#[derive(LintDiagnostic)] +#[diag(lint_non_snake_case)] +pub struct NonSnakeCaseDiag<'a> { + pub sort: &'a str, + pub name: &'a str, + pub sc: String, + #[subdiagnostic] + pub sub: NonSnakeCaseDiagSub, +} + +pub enum NonSnakeCaseDiagSub { + Label { span: Span }, + Help, + RenameOrConvertSuggestion { span: Span, suggestion: Ident }, + ConvertSuggestion { span: Span, suggestion: String }, + SuggestionAndNote { span: Span }, +} + +impl AddSubdiagnostic for NonSnakeCaseDiagSub { + fn add_to_diagnostic(self, diag: &mut rustc_errors::Diagnostic) { + match self { + NonSnakeCaseDiagSub::Label { span } => { + diag.span_label(span, fluent::label); + } + NonSnakeCaseDiagSub::Help => { + diag.help(fluent::help); + } + NonSnakeCaseDiagSub::ConvertSuggestion { span, suggestion } => { + diag.span_suggestion( + span, + fluent::convert_suggestion, + suggestion, + Applicability::MaybeIncorrect, + ); + } + NonSnakeCaseDiagSub::RenameOrConvertSuggestion { span, suggestion } => { + diag.span_suggestion( + span, + fluent::rename_or_convert_suggestion, + suggestion, + Applicability::MaybeIncorrect, + ); + } + NonSnakeCaseDiagSub::SuggestionAndNote { span } => { + diag.note(fluent::cannot_convert_note); + diag.span_suggestion( + span, + fluent::rename_suggestion, + "", + Applicability::MaybeIncorrect, + ); + } + }; + } +} + +#[derive(LintDiagnostic)] +#[diag(lint_non_upper_case_global)] +pub struct NonUpperCaseGlobal<'a> { + pub sort: &'a str, + pub name: &'a str, + #[subdiagnostic] + pub sub: NonUpperCaseGlobalSub, +} + +#[derive(SessionSubdiagnostic)] +pub enum NonUpperCaseGlobalSub { + #[label(label)] + Label { + #[primary_span] + span: Span, + }, + #[suggestion(suggestion, code = "{replace}", applicability = "maybe-incorrect")] + Suggestion { + #[primary_span] + span: Span, + replace: String, + }, +} + #[derive(LintDiagnostic)] #[diag(lint_noop_method_call)] #[note] diff --git a/compiler/rustc_lint/src/nonstandard_style.rs b/compiler/rustc_lint/src/nonstandard_style.rs index f37d6e9a63d..34e3751c061 100644 --- a/compiler/rustc_lint/src/nonstandard_style.rs +++ b/compiler/rustc_lint/src/nonstandard_style.rs @@ -1,7 +1,12 @@ +#![deny(rustc::untranslatable_diagnostic)] +#![deny(rustc::diagnostic_outside_of_impl)] +use crate::lints::{ + NonCamelCaseType, NonCamelCaseTypeSub, NonSnakeCaseDiag, NonSnakeCaseDiagSub, + NonUpperCaseGlobal, NonUpperCaseGlobalSub, +}; use crate::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext}; use rustc_ast as ast; use rustc_attr as attr; -use rustc_errors::{fluent, Applicability}; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::intravisit::FnKind; @@ -136,30 +141,17 @@ impl NonCamelCaseTypes { let name = ident.name.as_str(); if !is_camel_case(name) { - cx.struct_span_lint( + let cc = to_camel_case(name); + let sub = if *name != cc { + NonCamelCaseTypeSub::Suggestion { span: ident.span, replace: cc } + } else { + NonCamelCaseTypeSub::Label { span: ident.span } + }; + cx.emit_spanned_lint( NON_CAMEL_CASE_TYPES, ident.span, - fluent::lint_non_camel_case_type, - |lint| { - let cc = to_camel_case(name); - // We cannot provide meaningful suggestions - // if the characters are in the category of "Lowercase Letter". - if *name != cc { - lint.span_suggestion( - ident.span, - fluent::suggestion, - to_camel_case(name), - Applicability::MaybeIncorrect, - ); - } else { - lint.span_label(ident.span, fluent::label); - } - - lint.set_arg("sort", sort); - lint.set_arg("name", name); - lint - }, - ) + NonCamelCaseType { sort, name, sub }, + ); } } } @@ -294,47 +286,37 @@ impl NonSnakeCase { let name = ident.name.as_str(); if !is_snake_case(name) { - cx.struct_span_lint(NON_SNAKE_CASE, ident.span, fluent::lint_non_snake_case, |lint| { - let sc = NonSnakeCase::to_snake_case(name); - // We cannot provide meaningful suggestions - // if the characters are in the category of "Uppercase Letter". - if name != sc { - // We have a valid span in almost all cases, but we don't have one when linting a crate - // name provided via the command line. - if !ident.span.is_dummy() { - let sc_ident = Ident::from_str_and_span(&sc, ident.span); - let (message, suggestion) = if sc_ident.is_reserved() { - // We shouldn't suggest a reserved identifier to fix non-snake-case identifiers. - // Instead, recommend renaming the identifier entirely or, if permitted, - // escaping it to create a raw identifier. - if sc_ident.name.can_be_raw() { - (fluent::rename_or_convert_suggestion, sc_ident.to_string()) - } else { - lint.note(fluent::cannot_convert_note); - (fluent::rename_suggestion, String::new()) + let span = ident.span; + let sc = NonSnakeCase::to_snake_case(name); + // We cannot provide meaningful suggestions + // if the characters are in the category of "Uppercase Letter". + let sub = if name != sc { + // We have a valid span in almost all cases, but we don't have one when linting a crate + // name provided via the command line. + if !span.is_dummy() { + let sc_ident = Ident::from_str_and_span(&sc, span); + if sc_ident.is_reserved() { + // We shouldn't suggest a reserved identifier to fix non-snake-case identifiers. + // Instead, recommend renaming the identifier entirely or, if permitted, + // escaping it to create a raw identifier. + if sc_ident.name.can_be_raw() { + NonSnakeCaseDiagSub::RenameOrConvertSuggestion { + span, + suggestion: sc_ident, } } else { - (fluent::convert_suggestion, sc.clone()) - }; - - lint.span_suggestion( - ident.span, - message, - suggestion, - Applicability::MaybeIncorrect, - ); + NonSnakeCaseDiagSub::SuggestionAndNote { span } + } } else { - lint.help(fluent::help); + NonSnakeCaseDiagSub::ConvertSuggestion { span, suggestion: sc.clone() } } } else { - lint.span_label(ident.span, fluent::label); + NonSnakeCaseDiagSub::Help } - - lint.set_arg("sort", sort); - lint.set_arg("name", name); - lint.set_arg("sc", sc); - lint - }); + } else { + NonSnakeCaseDiagSub::Label { span } + }; + cx.emit_spanned_lint(NON_SNAKE_CASE, span, NonSnakeCaseDiag { sort, name, sc, sub }); } } } @@ -490,30 +472,19 @@ impl NonUpperCaseGlobals { fn check_upper_case(cx: &LateContext<'_>, sort: &str, ident: &Ident) { let name = ident.name.as_str(); if name.chars().any(|c| c.is_lowercase()) { - cx.struct_span_lint( + let uc = NonSnakeCase::to_snake_case(&name).to_uppercase(); + // We cannot provide meaningful suggestions + // if the characters are in the category of "Lowercase Letter". + let sub = if *name != uc { + NonUpperCaseGlobalSub::Suggestion { span: ident.span, replace: uc } + } else { + NonUpperCaseGlobalSub::Label { span: ident.span } + }; + cx.emit_spanned_lint( NON_UPPER_CASE_GLOBALS, ident.span, - fluent::lint_non_upper_case_global, - |lint| { - let uc = NonSnakeCase::to_snake_case(&name).to_uppercase(); - // We cannot provide meaningful suggestions - // if the characters are in the category of "Lowercase Letter". - if *name != uc { - lint.span_suggestion( - ident.span, - fluent::suggestion, - uc, - Applicability::MaybeIncorrect, - ); - } else { - lint.span_label(ident.span, fluent::label); - } - - lint.set_arg("sort", sort); - lint.set_arg("name", name); - lint - }, - ) + NonUpperCaseGlobal { sort, name, sub }, + ); } } }