-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> {
#[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<Symbol>,
+}
+
+// FIXME: refactor with `Option<String>` 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<UnusedDelimSuggestion>,
+}
+
+#[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;
+#![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;
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 {
);
}
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,
+ },
+ );
}
}
}
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);
}
}
}
} 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) {
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 },
);
}
}
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);
+ }
+ };
}
}
}