Remove the UNTRANSLATABLE_DIAGNOSTIC and DIAGNOSTIC_OUTSIDE_OF_IMPL lints
This commit is contained in:
parent
0ee7d96253
commit
14484ec016
4 changed files with 5 additions and 177 deletions
|
|
@ -237,9 +237,6 @@ lint_deprecated_where_clause_location = where clause not allowed here
|
|||
.suggestion_move_to_end = move it to the end of the type declaration
|
||||
.suggestion_remove_where = remove this `where`
|
||||
|
||||
lint_diag_out_of_impl =
|
||||
diagnostics should only be created in `Diagnostic`/`Subdiagnostic`/`LintDiagnostic` impls
|
||||
|
||||
lint_doc_alias_duplicated = doc alias is duplicated
|
||||
.label = first defined here
|
||||
|
||||
|
|
@ -992,8 +989,6 @@ lint_unsafe_attr_outside_unsafe_suggestion = wrap the attribute in `unsafe(...)`
|
|||
|
||||
lint_unsupported_group = `{$lint_group}` lint group is not supported with ´--force-warn´
|
||||
|
||||
lint_untranslatable_diag = diagnostics should be created using translatable messages
|
||||
|
||||
lint_unused_allocation = unnecessary allocation, use `&` instead
|
||||
lint_unused_allocation_mut = unnecessary allocation, use `&mut` instead
|
||||
|
||||
|
|
|
|||
|
|
@ -5,18 +5,17 @@ use rustc_hir::attrs::AttributeKind;
|
|||
use rustc_hir::def::Res;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::{Expr, ExprKind, HirId, find_attr};
|
||||
use rustc_middle::ty::{self, GenericArgsRef, PredicatePolarity, Ty};
|
||||
use rustc_middle::ty::{self, GenericArgsRef, PredicatePolarity};
|
||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||
use rustc_span::hygiene::{ExpnKind, MacroKind};
|
||||
use rustc_span::{Span, sym};
|
||||
use tracing::debug;
|
||||
use {rustc_ast as ast, rustc_hir as hir};
|
||||
|
||||
use crate::lints::{
|
||||
BadOptAccessDiag, DefaultHashTypesDiag, DiagOutOfImpl, ImplicitSysrootCrateImportDiag,
|
||||
LintPassByHand, NonGlobImportTypeIrInherent, QueryInstability, QueryUntracked,
|
||||
SpanUseEqCtxtDiag, SymbolInternStringLiteralDiag, TyQualified, TykindDiag, TykindKind,
|
||||
TypeIrDirectUse, TypeIrInherentUsage, TypeIrTraitUsage, UntranslatableDiag,
|
||||
BadOptAccessDiag, DefaultHashTypesDiag, ImplicitSysrootCrateImportDiag, LintPassByHand,
|
||||
NonGlobImportTypeIrInherent, QueryInstability, QueryUntracked, SpanUseEqCtxtDiag,
|
||||
SymbolInternStringLiteralDiag, TyQualified, TykindDiag, TykindKind, TypeIrDirectUse,
|
||||
TypeIrInherentUsage, TypeIrTraitUsage,
|
||||
};
|
||||
use crate::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext};
|
||||
|
||||
|
|
@ -492,162 +491,6 @@ impl EarlyLintPass for LintPassImpl {
|
|||
}
|
||||
}
|
||||
|
||||
declare_tool_lint! {
|
||||
/// The `untranslatable_diagnostic` lint detects messages passed to functions with `impl
|
||||
/// Into<{D,Subd}iagMessage` parameters without using translatable Fluent strings.
|
||||
///
|
||||
/// More details on translatable diagnostics can be found
|
||||
/// [here](https://rustc-dev-guide.rust-lang.org/diagnostics/translation.html).
|
||||
pub rustc::UNTRANSLATABLE_DIAGNOSTIC,
|
||||
Allow,
|
||||
"prevent creation of diagnostics which cannot be translated",
|
||||
report_in_external_macro: true,
|
||||
@eval_always = true
|
||||
}
|
||||
|
||||
declare_tool_lint! {
|
||||
/// The `diagnostic_outside_of_impl` lint detects calls to functions annotated with
|
||||
/// `#[rustc_lint_diagnostics]` that are outside an `Diagnostic`, `Subdiagnostic`, or
|
||||
/// `LintDiagnostic` impl (either hand-written or derived).
|
||||
///
|
||||
/// More details on diagnostics implementations can be found
|
||||
/// [here](https://rustc-dev-guide.rust-lang.org/diagnostics/diagnostic-structs.html).
|
||||
pub rustc::DIAGNOSTIC_OUTSIDE_OF_IMPL,
|
||||
Allow,
|
||||
"prevent diagnostic creation outside of `Diagnostic`/`Subdiagnostic`/`LintDiagnostic` impls",
|
||||
report_in_external_macro: true,
|
||||
@eval_always = true
|
||||
}
|
||||
|
||||
declare_lint_pass!(Diagnostics => [UNTRANSLATABLE_DIAGNOSTIC, DIAGNOSTIC_OUTSIDE_OF_IMPL]);
|
||||
|
||||
impl LateLintPass<'_> for Diagnostics {
|
||||
fn check_expr<'tcx>(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>) {
|
||||
let collect_args_tys_and_spans = |args: &[hir::Expr<'_>], reserve_one_extra: bool| {
|
||||
let mut result = Vec::with_capacity(args.len() + usize::from(reserve_one_extra));
|
||||
result.extend(args.iter().map(|arg| (cx.typeck_results().expr_ty(arg), arg.span)));
|
||||
result
|
||||
};
|
||||
// Only check function calls and method calls.
|
||||
let Some((def_id, span, fn_gen_args, recv, args)) =
|
||||
get_callee_span_generic_args_and_args(cx, expr)
|
||||
else {
|
||||
return;
|
||||
};
|
||||
let mut arg_tys_and_spans = collect_args_tys_and_spans(args, recv.is_some());
|
||||
if let Some(recv) = recv {
|
||||
arg_tys_and_spans.insert(0, (cx.tcx.types.self_param, recv.span)); // dummy inserted for `self`
|
||||
}
|
||||
|
||||
Self::diagnostic_outside_of_impl(cx, span, expr.hir_id, def_id, fn_gen_args);
|
||||
Self::untranslatable_diagnostic(cx, def_id, &arg_tys_and_spans);
|
||||
}
|
||||
}
|
||||
|
||||
impl Diagnostics {
|
||||
// Is the type `{D,Subd}iagMessage`?
|
||||
fn is_diag_message<'cx>(cx: &LateContext<'cx>, ty: Ty<'cx>) -> bool {
|
||||
if let Some(adt_def) = ty.ty_adt_def()
|
||||
&& let Some(name) = cx.tcx.get_diagnostic_name(adt_def.did())
|
||||
&& matches!(name, sym::DiagMessage | sym::SubdiagMessage)
|
||||
{
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
fn untranslatable_diagnostic<'cx>(
|
||||
cx: &LateContext<'cx>,
|
||||
def_id: DefId,
|
||||
arg_tys_and_spans: &[(Ty<'cx>, Span)],
|
||||
) {
|
||||
let fn_sig = cx.tcx.fn_sig(def_id).instantiate_identity().skip_binder();
|
||||
let predicates = cx.tcx.predicates_of(def_id).instantiate_identity(cx.tcx).predicates;
|
||||
for (i, ¶m_ty) in fn_sig.inputs().iter().enumerate() {
|
||||
if let ty::Param(sig_param) = param_ty.kind() {
|
||||
// It is a type parameter. Check if it is `impl Into<{D,Subd}iagMessage>`.
|
||||
for pred in predicates.iter() {
|
||||
if let Some(trait_pred) = pred.as_trait_clause()
|
||||
&& let trait_ref = trait_pred.skip_binder().trait_ref
|
||||
&& trait_ref.self_ty() == param_ty // correct predicate for the param?
|
||||
&& cx.tcx.is_diagnostic_item(sym::Into, trait_ref.def_id)
|
||||
&& let ty1 = trait_ref.args.type_at(1)
|
||||
&& Self::is_diag_message(cx, ty1)
|
||||
{
|
||||
// Calls to methods with an `impl Into<{D,Subd}iagMessage>` parameter must be passed an arg
|
||||
// with type `{D,Subd}iagMessage` or `impl Into<{D,Subd}iagMessage>`. Otherwise, emit an
|
||||
// `UNTRANSLATABLE_DIAGNOSTIC` lint.
|
||||
let (arg_ty, arg_span) = arg_tys_and_spans[i];
|
||||
|
||||
// Is the arg type `{Sub,D}iagMessage`or `impl Into<{Sub,D}iagMessage>`?
|
||||
let is_translatable = Self::is_diag_message(cx, arg_ty)
|
||||
|| matches!(arg_ty.kind(), ty::Param(arg_param) if arg_param.name == sig_param.name);
|
||||
if !is_translatable {
|
||||
cx.emit_span_lint(
|
||||
UNTRANSLATABLE_DIAGNOSTIC,
|
||||
arg_span,
|
||||
UntranslatableDiag,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn diagnostic_outside_of_impl<'cx>(
|
||||
cx: &LateContext<'cx>,
|
||||
span: Span,
|
||||
current_id: HirId,
|
||||
def_id: DefId,
|
||||
fn_gen_args: GenericArgsRef<'cx>,
|
||||
) {
|
||||
// Is the callee marked with `#[rustc_lint_diagnostics]`?
|
||||
let Some(inst) =
|
||||
ty::Instance::try_resolve(cx.tcx, cx.typing_env(), def_id, fn_gen_args).ok().flatten()
|
||||
else {
|
||||
return;
|
||||
};
|
||||
|
||||
if !find_attr!(cx.tcx.get_all_attrs(inst.def_id()), AttributeKind::RustcLintDiagnostics) {
|
||||
return;
|
||||
};
|
||||
|
||||
for (hir_id, _parent) in cx.tcx.hir_parent_iter(current_id) {
|
||||
if let Some(owner_did) = hir_id.as_owner()
|
||||
&& find_attr!(cx.tcx.get_all_attrs(owner_did), AttributeKind::RustcLintDiagnostics)
|
||||
{
|
||||
// The parent method is marked with `#[rustc_lint_diagnostics]`
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Calls to `#[rustc_lint_diagnostics]`-marked functions should only occur:
|
||||
// - inside an impl of `Diagnostic`, `Subdiagnostic`, or `LintDiagnostic`, or
|
||||
// - inside a parent function that is itself marked with `#[rustc_lint_diagnostics]`.
|
||||
//
|
||||
// Otherwise, emit a `DIAGNOSTIC_OUTSIDE_OF_IMPL` lint.
|
||||
let mut is_inside_appropriate_impl = false;
|
||||
for (_hir_id, parent) in cx.tcx.hir_parent_iter(current_id) {
|
||||
debug!(?parent);
|
||||
if let hir::Node::Item(hir::Item { kind: hir::ItemKind::Impl(impl_), .. }) = parent
|
||||
&& let Some(of_trait) = impl_.of_trait
|
||||
&& let Some(def_id) = of_trait.trait_ref.trait_def_id()
|
||||
&& let Some(name) = cx.tcx.get_diagnostic_name(def_id)
|
||||
&& matches!(name, sym::Diagnostic | sym::Subdiagnostic | sym::LintDiagnostic)
|
||||
{
|
||||
is_inside_appropriate_impl = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
debug!(?is_inside_appropriate_impl);
|
||||
if !is_inside_appropriate_impl {
|
||||
cx.emit_span_lint(DIAGNOSTIC_OUTSIDE_OF_IMPL, span, DiagOutOfImpl);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
declare_tool_lint! {
|
||||
/// The `bad_opt_access` lint detects accessing options by field instead of
|
||||
/// the wrapper function.
|
||||
|
|
|
|||
|
|
@ -655,8 +655,6 @@ fn register_internals(store: &mut LintStore) {
|
|||
store.register_late_mod_pass(|_| Box::new(TyTyKind));
|
||||
store.register_lints(&TypeIr::lint_vec());
|
||||
store.register_late_mod_pass(|_| Box::new(TypeIr));
|
||||
store.register_lints(&Diagnostics::lint_vec());
|
||||
store.register_late_mod_pass(|_| Box::new(Diagnostics));
|
||||
store.register_lints(&BadOptAccess::lint_vec());
|
||||
store.register_late_mod_pass(|_| Box::new(BadOptAccess));
|
||||
store.register_lints(&PassByValue::lint_vec());
|
||||
|
|
|
|||
|
|
@ -943,14 +943,6 @@ pub(crate) struct NonGlobImportTypeIrInherent {
|
|||
#[help]
|
||||
pub(crate) struct LintPassByHand;
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_diag_out_of_impl)]
|
||||
pub(crate) struct DiagOutOfImpl;
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_untranslatable_diag)]
|
||||
pub(crate) struct UntranslatableDiag;
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_bad_opt_access)]
|
||||
pub(crate) struct BadOptAccessDiag<'a> {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue