diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index ce93616da13..c68bfc98f93 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -1,7 +1,11 @@ -use rustc_errors::{fluent, AddSubdiagnostic, DecorateLint, EmissionGuarantee}; +use rustc_errors::{fluent, AddSubdiagnostic, Applicability, DecorateLint, EmissionGuarantee}; +use rustc_hir::def_id::DefId; use rustc_macros::{LintDiagnostic, SessionSubdiagnostic}; +use rustc_middle::ty::Ty; use rustc_span::{Span, Symbol}; +use crate::LateContext; + #[derive(LintDiagnostic)] #[diag(lint_range_endpoint_out_of_range)] pub struct RangeEndpointOutOfRange<'a> { @@ -146,3 +150,130 @@ pub struct InvalidAtomicOrderingDiag { #[label] pub fail_order_arg_span: Span, } + +#[derive(LintDiagnostic)] +#[diag(lint_unused_op)] +pub struct UnusedOp<'a> { + pub op: &'a str, + #[label] + pub label: Span, + #[suggestion(style = "verbose", code = "let _ = ", applicability = "machine-applicable")] + pub suggestion: Span, +} + +#[derive(LintDiagnostic)] +#[diag(lint_unused_result)] +pub struct UnusedResult<'a> { + pub ty: Ty<'a>, +} + +// FIXME(davidtwco): this isn't properly translatable becauses of the +// pre/post strings +#[derive(LintDiagnostic)] +#[diag(lint_unused_closure)] +#[note] +pub struct UnusedClosure<'a> { + pub count: usize, + pub pre: &'a str, + pub post: &'a str, +} + +// FIXME(davidtwco): this isn't properly translatable becauses of the +// pre/post strings +#[derive(LintDiagnostic)] +#[diag(lint_unused_generator)] +#[note] +pub struct UnusedGenerator<'a> { + pub count: usize, + pub pre: &'a str, + pub post: &'a str, +} + +// FIXME(davidtwco): this isn't properly translatable becauses of the pre/post +// strings +pub struct UnusedDef<'a, 'b> { + pub pre: &'a str, + pub post: &'a str, + pub cx: &'a LateContext<'b>, + pub def_id: DefId, + pub note: Option, +} + +// FIXME: refactor with `Option` in macro +impl<'a, 'b, G: EmissionGuarantee> DecorateLint<'_, G> for UnusedDef<'a, 'b> { + fn decorate_lint(self, diag: rustc_errors::LintDiagnosticBuilder<'_, G>) { + let mut diag = diag.build(fluent::lint_unused_def); + diag.set_arg("pre", self.pre); + diag.set_arg("post", self.post); + diag.set_arg("def", self.cx.tcx.def_path_str(self.def_id)); + // check for #[must_use = "..."] + if let Some(note) = self.note { + diag.note(note.as_str()); + } + diag.emit(); + } +} + +#[derive(LintDiagnostic)] +#[diag(lint_path_statement_drop)] +pub struct PathStatementDrop { + #[subdiagnostic] + pub sub: PathStatementDropSub, +} + +#[derive(SessionSubdiagnostic)] +pub enum PathStatementDropSub { + #[suggestion( + suggestion, + code = "drop({snippet});", + applicability = "machine-applicable" + )] + Suggestion { + #[primary_span] + span: Span, + snippet: String, + }, + #[help(help)] + Help { + #[primary_span] + span: Span, + }, +} + +#[derive(LintDiagnostic)] +#[diag(lint_path_statement_no_effect)] +pub struct PathStatementNoEffect; + +#[derive(LintDiagnostic)] +#[diag(lint_unused_delim)] +pub struct UnusedDelim<'a> { + pub delim: &'static str, + pub item: &'a str, + #[subdiagnostic] + pub suggestion: Option, +} + +#[derive(Subdiagnostic)] +#[multipart_suggestion(suggestion, applicability = "machine-applicable")] +pub struct UnusedDelimSuggestion { + #[suggestion_part(code = "{start_replace}")] + pub start_span: Span, + pub start_replace: &'static str, + #[suggestion_part(code = "{end_replace}")] + pub end_span: Span, + pub end_replace: &'static str, +} + +#[derive(LintDiagnostic)] +#[diag(lint_unused_import_braces)] +pub struct UnusedImportBracesDiag { + pub node: Symbol, +} + +#[derive(LintDiagnostic)] +#[diag(lint_unused_allocation)] +pub struct UnusedAllocationDiag; + +#[derive(LintDiagnostic)] +#[diag(lint_unused_allocation_mut)] +pub struct UnusedAllocationMutDiag; diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs index 525079681ca..8c5f68d6144 100644 --- a/compiler/rustc_lint/src/unused.rs +++ b/compiler/rustc_lint/src/unused.rs @@ -1,9 +1,16 @@ +#![deny(rustc::untranslatable_diagnostic)] +#![deny(rustc::diagnostic_outside_of_impl)] +use crate::lints::{ + PathStatementDrop, PathStatementDropSub, PathStatementNoEffect, UnusedAllocationDiag, + UnusedAllocationMutDiag, UnusedClosure, UnusedDef, UnusedDelim, UnusedDelimSuggestion, + UnusedGenerator, UnusedImportBracesDiag, UnusedOp, UnusedResult, +}; use crate::Lint; use crate::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext}; use rustc_ast as ast; use rustc_ast::util::{classify, parser}; use rustc_ast::{ExprKind, StmtKind}; -use rustc_errors::{fluent, pluralize, Applicability, MultiSpan}; +use rustc_errors::{pluralize, MultiSpan}; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::DefId; @@ -163,23 +170,20 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults { let mut op_warned = false; if let Some(must_use_op) = must_use_op { - cx.struct_span_lint(UNUSED_MUST_USE, expr.span, fluent::lint_unused_op, |lint| { - lint.set_arg("op", must_use_op) - .span_label(expr.span, fluent::label) - .span_suggestion_verbose( - expr.span.shrink_to_lo(), - fluent::suggestion, - "let _ = ", - Applicability::MachineApplicable, - ) - }); + cx.emit_spanned_lint( + UNUSED_MUST_USE, + expr.span, + UnusedOp { + op: must_use_op, + label: expr.span, + suggestion: expr.span.shrink_to_lo(), + }, + ); op_warned = true; } if !(type_lint_emitted_or_suppressed || fn_warned || op_warned) { - cx.struct_span_lint(UNUSED_RESULTS, s.span, fluent::lint_unused_result, |lint| { - lint.set_arg("ty", ty) - }); + cx.emit_spanned_lint(UNUSED_RESULTS, s.span, UnusedResult { ty }); } fn check_fn_must_use(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> bool { @@ -402,47 +406,31 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults { ); } MustUsePath::Closure(span) => { - cx.struct_span_lint( + cx.emit_spanned_lint( UNUSED_MUST_USE, *span, - fluent::lint_unused_closure, - |lint| { - // FIXME(davidtwco): this isn't properly translatable because of the - // pre/post strings - lint.set_arg("count", plural_len) - .set_arg("pre", descr_pre) - .set_arg("post", descr_post) - .note(fluent::note) - }, + UnusedClosure { count: plural_len, pre: descr_pre, post: descr_post }, ); } MustUsePath::Generator(span) => { - cx.struct_span_lint( + cx.emit_spanned_lint( UNUSED_MUST_USE, *span, - fluent::lint_unused_generator, - |lint| { - // FIXME(davidtwco): this isn't properly translatable because of the - // pre/post strings - lint.set_arg("count", plural_len) - .set_arg("pre", descr_pre) - .set_arg("post", descr_post) - .note(fluent::note) - }, + UnusedGenerator { count: plural_len, pre: descr_pre, post: descr_post }, ); } MustUsePath::Def(span, def_id, reason) => { - cx.struct_span_lint(UNUSED_MUST_USE, *span, fluent::lint_unused_def, |lint| { - // FIXME(davidtwco): this isn't properly translatable because of the pre/post - // strings - lint.set_arg("pre", descr_pre); - lint.set_arg("post", descr_post); - lint.set_arg("def", cx.tcx.def_path_str(*def_id)); - if let Some(note) = reason { - lint.note(note.as_str()); - } - lint - }); + cx.emit_spanned_lint( + UNUSED_MUST_USE, + *span, + UnusedDef { + pre: descr_pre, + post: descr_post, + cx, + def_id: *def_id, + note: *reason, + }, + ); } } } @@ -478,31 +466,15 @@ impl<'tcx> LateLintPass<'tcx> for PathStatements { if let hir::ExprKind::Path(_) = expr.kind { let ty = cx.typeck_results().expr_ty(expr); if ty.needs_drop(cx.tcx, cx.param_env) { - cx.struct_span_lint( - PATH_STATEMENTS, - s.span, - fluent::lint_path_statement_drop, - |lint| { - if let Ok(snippet) = cx.sess().source_map().span_to_snippet(expr.span) { - lint.span_suggestion( - s.span, - fluent::suggestion, - format!("drop({});", snippet), - Applicability::MachineApplicable, - ); - } else { - lint.span_help(s.span, fluent::suggestion); - } - lint - }, - ); + let sub = if let Ok(snippet) = cx.sess().source_map().span_to_snippet(expr.span) + { + PathStatementDropSub::Suggestion { span: s.span, snippet } + } else { + PathStatementDropSub::Help { span: s.span } + }; + cx.emit_spanned_lint(PATH_STATEMENTS, s.span, PathStatementDrop { sub }) } else { - cx.struct_span_lint( - PATH_STATEMENTS, - s.span, - fluent::lint_path_statement_no_effect, - |lint| lint, - ); + cx.emit_spanned_lint(PATH_STATEMENTS, s.span, PathStatementNoEffect); } } } @@ -695,36 +667,35 @@ trait UnusedDelimLint { } else { MultiSpan::from(value_span) }; - cx.struct_span_lint(self.lint(), primary_span, fluent::lint_unused_delim, |lint| { - lint.set_arg("delim", Self::DELIM_STR); - lint.set_arg("item", msg); - if let Some((lo, hi)) = spans { - let sm = cx.sess().source_map(); - let lo_replace = + let suggestion = spans.map(|(lo, hi)| { + let sm = cx.sess().source_map(); + let lo_replace = if keep_space.0 && let Ok(snip) = sm.span_to_prev_source(lo) && !snip.ends_with(' ') { - " ".to_string() + " " } else { - "".to_string() + "" }; - let hi_replace = + let hi_replace = if keep_space.1 && let Ok(snip) = sm.span_to_next_source(hi) && !snip.starts_with(' ') { - " ".to_string() + " " } else { - "".to_string() + "" }; - - let replacement = vec![(lo, lo_replace), (hi, hi_replace)]; - lint.multipart_suggestion( - fluent::suggestion, - replacement, - Applicability::MachineApplicable, - ); + UnusedDelimSuggestion { + start_span: lo, + start_replace: lo_replace, + end_span: hi, + end_replace: hi_replace, } - lint }); + cx.emit_spanned_lint( + self.lint(), + primary_span, + UnusedDelim { delim: Self::DELIM_STR, item: msg, suggestion }, + ); } fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &ast::Expr) { @@ -1297,11 +1268,10 @@ impl UnusedImportBraces { ast::UseTreeKind::Nested(_) => return, }; - cx.struct_span_lint( + cx.emit_spanned_lint( UNUSED_IMPORT_BRACES, item.span, - fluent::lint_unused_import_braces, - |lint| lint.set_arg("node", node_name), + UnusedImportBracesDiag { node: node_name }, ); } } @@ -1351,17 +1321,14 @@ impl<'tcx> LateLintPass<'tcx> for UnusedAllocation { for adj in cx.typeck_results().expr_adjustments(e) { if let adjustment::Adjust::Borrow(adjustment::AutoBorrow::Ref(_, m)) = adj.kind { - cx.struct_span_lint( - UNUSED_ALLOCATION, - e.span, - match m { - adjustment::AutoBorrowMutability::Not => fluent::lint_unused_allocation, - adjustment::AutoBorrowMutability::Mut { .. } => { - fluent::lint_unused_allocation_mut - } - }, - |lint| lint, - ); + match m { + adjustment::AutoBorrowMutability::Not => { + cx.emit_spanned_lint(UNUSED_ALLOCATION, e.span, UnusedAllocationDiag); + } + adjustment::AutoBorrowMutability::Mut { .. } => { + cx.emit_spanned_lint(UNUSED_ALLOCATION, e.span, UnusedAllocationMutDiag); + } + }; } } }