Add deny lint to prevent untranslatable diagnostics using static strings
This commit is contained in:
parent
a7aa20517c
commit
eeb527602a
@ -99,6 +99,8 @@ lint_diag_out_of_impl =
|
|||||||
|
|
||||||
lint_untranslatable_diag = diagnostics should be created using translatable messages
|
lint_untranslatable_diag = diagnostics should be created using translatable messages
|
||||||
|
|
||||||
|
lint_trivial_untranslatable_diag = diagnostic with static strings only
|
||||||
|
|
||||||
lint_bad_opt_access = {$msg}
|
lint_bad_opt_access = {$msg}
|
||||||
|
|
||||||
lint_cstring_ptr = getting the inner pointer of a temporary `CString`
|
lint_cstring_ptr = getting the inner pointer of a temporary `CString`
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
use crate::lints::{
|
use crate::lints::{
|
||||||
BadOptAccessDiag, DefaultHashTypesDiag, DiagOutOfImpl, LintPassByHand, NonExistentDocKeyword,
|
BadOptAccessDiag, DefaultHashTypesDiag, DiagOutOfImpl, LintPassByHand, NonExistentDocKeyword,
|
||||||
QueryInstability, TyQualified, TykindDiag, TykindKind, UntranslatableDiag,
|
QueryInstability, TyQualified, TykindDiag, TykindKind, UntranslatableDiag,
|
||||||
|
UntranslatableDiagnosticTrivial,
|
||||||
};
|
};
|
||||||
use crate::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext};
|
use crate::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext};
|
||||||
use rustc_ast as ast;
|
use rustc_ast as ast;
|
||||||
@ -366,7 +367,15 @@ declare_tool_lint! {
|
|||||||
report_in_external_macro: true
|
report_in_external_macro: true
|
||||||
}
|
}
|
||||||
|
|
||||||
declare_lint_pass!(Diagnostics => [ UNTRANSLATABLE_DIAGNOSTIC, DIAGNOSTIC_OUTSIDE_OF_IMPL ]);
|
declare_tool_lint! {
|
||||||
|
/// The `untranslatable_diagnostic_trivial` lint detects diagnostics created using only static strings.
|
||||||
|
pub rustc::UNTRANSLATABLE_DIAGNOSTIC_TRIVIAL,
|
||||||
|
Deny,
|
||||||
|
"prevent creation of diagnostics which cannot be translated, which use only static strings",
|
||||||
|
report_in_external_macro: true
|
||||||
|
}
|
||||||
|
|
||||||
|
declare_lint_pass!(Diagnostics => [ UNTRANSLATABLE_DIAGNOSTIC, DIAGNOSTIC_OUTSIDE_OF_IMPL, UNTRANSLATABLE_DIAGNOSTIC_TRIVIAL ]);
|
||||||
|
|
||||||
impl LateLintPass<'_> for Diagnostics {
|
impl LateLintPass<'_> for Diagnostics {
|
||||||
fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
|
fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
|
||||||
@ -423,6 +432,75 @@ impl LateLintPass<'_> for Diagnostics {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl EarlyLintPass for Diagnostics {
|
||||||
|
#[allow(unused_must_use)]
|
||||||
|
fn check_stmt(&mut self, cx: &EarlyContext<'_>, stmt: &ast::Stmt) {
|
||||||
|
// Looking for a straight chain of method calls from 'struct_span_err' to 'emit'.
|
||||||
|
let ast::StmtKind::Semi(expr) = &stmt.kind else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
let ast::ExprKind::MethodCall(meth) = &expr.kind else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
if meth.seg.ident.name != sym::emit || !meth.args.is_empty() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let mut segments = vec![];
|
||||||
|
let mut cur = &meth.receiver;
|
||||||
|
let fake = &[].into();
|
||||||
|
loop {
|
||||||
|
match &cur.kind {
|
||||||
|
ast::ExprKind::Call(func, args) => {
|
||||||
|
if let ast::ExprKind::Path(_, path) = &func.kind {
|
||||||
|
segments.push((path.segments.last().unwrap().ident.name, args))
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
ast::ExprKind::MethodCall(method) => {
|
||||||
|
segments.push((method.seg.ident.name, &method.args));
|
||||||
|
cur = &method.receiver;
|
||||||
|
}
|
||||||
|
ast::ExprKind::MacCall(mac) => {
|
||||||
|
segments.push((mac.path.segments.last().unwrap().ident.name, fake));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
segments.reverse();
|
||||||
|
if segments.is_empty() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if segments[0].0.as_str() != "struct_span_err" {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if !segments.iter().all(|(name, args)| {
|
||||||
|
let arg = match name.as_str() {
|
||||||
|
"struct_span_err" | "span_note" | "span_label" | "span_help" => &args[1],
|
||||||
|
"note" | "help" => &args[0],
|
||||||
|
_ => {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if let ast::ExprKind::Lit(lit) = arg.kind
|
||||||
|
&& let ast::token::LitKind::Str = lit.kind {
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
cx.emit_spanned_lint(
|
||||||
|
UNTRANSLATABLE_DIAGNOSTIC_TRIVIAL,
|
||||||
|
stmt.span,
|
||||||
|
UntranslatableDiagnosticTrivial,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
declare_tool_lint! {
|
declare_tool_lint! {
|
||||||
/// The `bad_opt_access` lint detects accessing options by field instead of
|
/// The `bad_opt_access` lint detects accessing options by field instead of
|
||||||
/// the wrapper function.
|
/// the wrapper function.
|
||||||
|
@ -518,6 +518,7 @@ fn register_internals(store: &mut LintStore) {
|
|||||||
store.register_lints(&TyTyKind::get_lints());
|
store.register_lints(&TyTyKind::get_lints());
|
||||||
store.register_late_pass(|_| Box::new(TyTyKind));
|
store.register_late_pass(|_| Box::new(TyTyKind));
|
||||||
store.register_lints(&Diagnostics::get_lints());
|
store.register_lints(&Diagnostics::get_lints());
|
||||||
|
store.register_early_pass(|| Box::new(Diagnostics));
|
||||||
store.register_late_pass(|_| Box::new(Diagnostics));
|
store.register_late_pass(|_| Box::new(Diagnostics));
|
||||||
store.register_lints(&BadOptAccess::get_lints());
|
store.register_lints(&BadOptAccess::get_lints());
|
||||||
store.register_late_pass(|_| Box::new(BadOptAccess));
|
store.register_late_pass(|_| Box::new(BadOptAccess));
|
||||||
|
@ -820,6 +820,10 @@ pub struct DiagOutOfImpl;
|
|||||||
#[diag(lint_untranslatable_diag)]
|
#[diag(lint_untranslatable_diag)]
|
||||||
pub struct UntranslatableDiag;
|
pub struct UntranslatableDiag;
|
||||||
|
|
||||||
|
#[derive(LintDiagnostic)]
|
||||||
|
#[diag(lint_trivial_untranslatable_diag)]
|
||||||
|
pub struct UntranslatableDiagnosticTrivial;
|
||||||
|
|
||||||
#[derive(LintDiagnostic)]
|
#[derive(LintDiagnostic)]
|
||||||
#[diag(lint_bad_opt_access)]
|
#[diag(lint_bad_opt_access)]
|
||||||
pub struct BadOptAccessDiag<'a> {
|
pub struct BadOptAccessDiag<'a> {
|
||||||
|
@ -651,6 +651,7 @@ symbols! {
|
|||||||
edition_panic,
|
edition_panic,
|
||||||
eh_catch_typeinfo,
|
eh_catch_typeinfo,
|
||||||
eh_personality,
|
eh_personality,
|
||||||
|
emit,
|
||||||
emit_enum,
|
emit_enum,
|
||||||
emit_enum_variant,
|
emit_enum_variant,
|
||||||
emit_enum_variant_arg,
|
emit_enum_variant_arg,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user