Make cx.span_lint methods lazy
- Make report_unsafe take decorate function - Remove span_lint, replacing calls with struct_span_lint, as caller is now responsible for emitting. - Remove lookup_and_emit, replacing with just lookup which takes a decorate function. - Remove span_lint_note, span_lint_help. These methods aren't easily made lazy as standalone methods, private, and unused. If this functionality is needed, to be lazy, they can easily be made into Fn(&mut DiagnosticBuilder) that are meant to be called _within_ the decorate function. - Rename lookup_and_emit_with_diagnostics to lookup_with_diagnostics to better reflect the fact that it doesn't emit for you.
This commit is contained in:
parent
b2e78faa15
commit
2f0430a163
@ -28,6 +28,7 @@ use rustc::ty::{self, layout::VariantIdx, Ty, TyCtxt};
|
||||
use rustc_ast_pretty::pprust::{self, expr_to_string};
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_errors::{Applicability, DiagnosticBuilder};
|
||||
use rustc::lint::LintDiagnosticBuilder;
|
||||
use rustc_feature::Stability;
|
||||
use rustc_feature::{deprecated_attributes, AttributeGate, AttributeTemplate, AttributeType};
|
||||
use rustc_hir as hir;
|
||||
@ -106,8 +107,7 @@ impl BoxPointers {
|
||||
fn check_heap_type(&self, cx: &LateContext<'_, '_>, span: Span, ty: Ty<'_>) {
|
||||
for leaf_ty in ty.walk() {
|
||||
if leaf_ty.is_box() {
|
||||
let m = format!("type uses owned (Box type) pointers: {}", ty);
|
||||
cx.span_lint(BOX_POINTERS, span, &m);
|
||||
cx.struct_span_lint(BOX_POINTERS, span, |lint| lint.build(&format!("type uses owned (Box type) pointers: {}", ty)).emit());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -214,13 +214,13 @@ declare_lint! {
|
||||
declare_lint_pass!(UnsafeCode => [UNSAFE_CODE]);
|
||||
|
||||
impl UnsafeCode {
|
||||
fn report_unsafe(&self, cx: &EarlyContext<'_>, span: Span, desc: &'static str) {
|
||||
fn report_unsafe(&self, cx: &EarlyContext<'_>, span: Span, decorate: impl for<'a> FnOnce(LintDiagnosticBuilder<'a>)) {
|
||||
// This comes from a macro that has `#[allow_internal_unsafe]`.
|
||||
if span.allows_unsafe() {
|
||||
return;
|
||||
}
|
||||
|
||||
cx.span_lint(UNSAFE_CODE, span, desc);
|
||||
cx.struct_span_lint(UNSAFE_CODE, span, decorate);
|
||||
}
|
||||
}
|
||||
|
||||
@ -230,9 +230,9 @@ impl EarlyLintPass for UnsafeCode {
|
||||
self.report_unsafe(
|
||||
cx,
|
||||
attr.span,
|
||||
"`allow_internal_unsafe` allows defining \
|
||||
|lint| lint.build("`allow_internal_unsafe` allows defining \
|
||||
macros using unsafe without triggering \
|
||||
the `unsafe_code` lint at their call site",
|
||||
the `unsafe_code` lint at their call site").emit(),
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -241,7 +241,7 @@ impl EarlyLintPass for UnsafeCode {
|
||||
if let ast::ExprKind::Block(ref blk, _) = e.kind {
|
||||
// Don't warn about generated blocks; that'll just pollute the output.
|
||||
if blk.rules == ast::BlockCheckMode::Unsafe(ast::UserProvided) {
|
||||
self.report_unsafe(cx, blk.span, "usage of an `unsafe` block");
|
||||
self.report_unsafe(cx, blk.span, |lint| lint.build("usage of an `unsafe` block").emit());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -249,11 +249,11 @@ impl EarlyLintPass for UnsafeCode {
|
||||
fn check_item(&mut self, cx: &EarlyContext<'_>, it: &ast::Item) {
|
||||
match it.kind {
|
||||
ast::ItemKind::Trait(_, ast::Unsafety::Unsafe, ..) => {
|
||||
self.report_unsafe(cx, it.span, "declaration of an `unsafe` trait")
|
||||
self.report_unsafe(cx, it.span, |lint| lint.build("declaration of an `unsafe` trait").emit())
|
||||
}
|
||||
|
||||
ast::ItemKind::Impl { unsafety: ast::Unsafety::Unsafe, .. } => {
|
||||
self.report_unsafe(cx, it.span, "implementation of an `unsafe` trait")
|
||||
self.report_unsafe(cx, it.span, |lint| lint.build("implementation of an `unsafe` trait").emit())
|
||||
}
|
||||
|
||||
_ => return,
|
||||
@ -275,7 +275,7 @@ impl EarlyLintPass for UnsafeCode {
|
||||
FnCtxt::Assoc(_) if body.is_none() => "declaration of an `unsafe` method",
|
||||
FnCtxt::Assoc(_) => "implementation of an `unsafe` method",
|
||||
};
|
||||
self.report_unsafe(cx, span, msg);
|
||||
self.report_unsafe(cx, span, |lint| lint.build(msg).emit());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -360,10 +360,10 @@ impl MissingDoc {
|
||||
|
||||
let has_doc = attrs.iter().any(|a| has_doc(a));
|
||||
if !has_doc {
|
||||
cx.span_lint(
|
||||
cx.struct_span_lint(
|
||||
MISSING_DOCS,
|
||||
cx.tcx.sess.source_map().def_span(sp),
|
||||
&format!("missing documentation for {}", desc),
|
||||
|lint| lint.build(&format!("missing documentation for {}", desc)).emit(),
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -392,10 +392,10 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingDoc {
|
||||
for macro_def in krate.exported_macros {
|
||||
let has_doc = macro_def.attrs.iter().any(|a| has_doc(a));
|
||||
if !has_doc {
|
||||
cx.span_lint(
|
||||
cx.struct_span_lint(
|
||||
MISSING_DOCS,
|
||||
cx.tcx.sess.source_map().def_span(macro_def.span),
|
||||
"missing documentation for macro",
|
||||
|lint| lint.build("missing documentation for macro").emit(),
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -543,11 +543,11 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingCopyImplementations {
|
||||
return;
|
||||
}
|
||||
if can_type_implement_copy(cx.tcx, param_env, ty).is_ok() {
|
||||
cx.span_lint(
|
||||
cx.struct_span_lint(
|
||||
MISSING_COPY_IMPLEMENTATIONS,
|
||||
item.span,
|
||||
"type could implement `Copy`; consider adding `impl \
|
||||
Copy`",
|
||||
|lint| lint.build("type could implement `Copy`; consider adding `impl \
|
||||
Copy`").emit(),
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -597,14 +597,14 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingDebugImplementations {
|
||||
}
|
||||
|
||||
if !self.impling_types.as_ref().unwrap().contains(&item.hir_id) {
|
||||
cx.span_lint(
|
||||
cx.struct_span_lint(
|
||||
MISSING_DEBUG_IMPLEMENTATIONS,
|
||||
item.span,
|
||||
&format!(
|
||||
|lint| lint.build(&format!(
|
||||
"type does not implement `{}`; consider adding `#[derive(Debug)]` \
|
||||
or a manual implementation",
|
||||
cx.tcx.def_path_str(debug)
|
||||
),
|
||||
)).emit(),
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -903,7 +903,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MutableTransmutes {
|
||||
match get_transmute_from_to(cx, expr).map(|(ty1, ty2)| (&ty1.kind, &ty2.kind)) {
|
||||
Some((&ty::Ref(_, _, from_mt), &ty::Ref(_, _, to_mt))) => {
|
||||
if to_mt == hir::Mutability::Mut && from_mt == hir::Mutability::Not {
|
||||
cx.span_lint(MUTABLE_TRANSMUTES, expr.span, msg);
|
||||
cx.struct_span_lint(MUTABLE_TRANSMUTES, expr.span, |lint| lint.build(msg).emit());
|
||||
}
|
||||
}
|
||||
_ => (),
|
||||
@ -953,7 +953,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnstableFeatures {
|
||||
if attr.check_name(sym::feature) {
|
||||
if let Some(items) = attr.meta_item_list() {
|
||||
for item in items {
|
||||
ctx.span_lint(UNSTABLE_FEATURES, item.span(), "unstable feature");
|
||||
ctx.struct_span_lint(UNSTABLE_FEATURES, item.span(), |lint| lint.build("unstable feature").emit());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1235,14 +1235,14 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TrivialConstraints {
|
||||
ConstEvaluatable(..) => continue,
|
||||
};
|
||||
if predicate.is_global() {
|
||||
cx.span_lint(
|
||||
cx.struct_span_lint(
|
||||
TRIVIAL_BOUNDS,
|
||||
span,
|
||||
&format!(
|
||||
|lint| lint.build(&format!(
|
||||
"{} bound {} does not depend on any type \
|
||||
or lifetime parameters",
|
||||
predicate_kind_name, predicate
|
||||
),
|
||||
)).emit(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -474,19 +474,18 @@ pub trait LintContext: Sized {
|
||||
fn sess(&self) -> &Session;
|
||||
fn lints(&self) -> &LintStore;
|
||||
|
||||
fn lookup_and_emit<S: Into<MultiSpan>>(&self, lint: &'static Lint, span: Option<S>, msg: &str) {
|
||||
self.lookup(lint, span, |lint| lint.build(msg).emit());
|
||||
}
|
||||
|
||||
fn lookup_and_emit_with_diagnostics<S: Into<MultiSpan>>(
|
||||
fn lookup_with_diagnostics<S: Into<MultiSpan>>(
|
||||
&self,
|
||||
lint: &'static Lint,
|
||||
span: Option<S>,
|
||||
msg: &str,
|
||||
decorate: impl for<'a> FnOnce(LintDiagnosticBuilder<'a>),
|
||||
diagnostic: BuiltinLintDiagnostics,
|
||||
) {
|
||||
self.lookup(lint, span, |lint| {
|
||||
let mut db = lint.build(msg);
|
||||
// We first generate a blank diagnostic.
|
||||
let mut db = lint.build("");
|
||||
|
||||
// Now, set up surrounding context.
|
||||
let sess = self.sess();
|
||||
match diagnostic {
|
||||
BuiltinLintDiagnostics::Normal => (),
|
||||
@ -567,8 +566,8 @@ pub trait LintContext: Sized {
|
||||
stability::deprecation_suggestion(&mut db, suggestion, span)
|
||||
}
|
||||
}
|
||||
|
||||
db.emit();
|
||||
// Rewrap `db`, and pass control to the user.
|
||||
decorate(LintDiagnosticBuilder::new(db));
|
||||
});
|
||||
}
|
||||
|
||||
@ -579,11 +578,6 @@ pub trait LintContext: Sized {
|
||||
decorate: impl for<'a> FnOnce(LintDiagnosticBuilder<'a>),
|
||||
);
|
||||
|
||||
/// Emit a lint at the appropriate level, for a particular span.
|
||||
fn span_lint<S: Into<MultiSpan>>(&self, lint: &'static Lint, span: S, msg: &str) {
|
||||
self.lookup_and_emit(lint, Some(span), msg);
|
||||
}
|
||||
|
||||
fn struct_span_lint<S: Into<MultiSpan>>(
|
||||
&self,
|
||||
lint: &'static Lint,
|
||||
@ -592,40 +586,9 @@ pub trait LintContext: Sized {
|
||||
) {
|
||||
self.lookup(lint, Some(span), decorate);
|
||||
}
|
||||
|
||||
/// Emit a lint and note at the appropriate level, for a particular span.
|
||||
fn span_lint_note(
|
||||
&self,
|
||||
lint: &'static Lint,
|
||||
span: Span,
|
||||
msg: &str,
|
||||
note_span: Span,
|
||||
note: &str,
|
||||
) {
|
||||
self.lookup(lint, Some(span), |lint| {
|
||||
let mut err = lint.build(msg);
|
||||
if note_span == span {
|
||||
err.note(note);
|
||||
} else {
|
||||
err.span_note(note_span, note);
|
||||
}
|
||||
err.emit();
|
||||
});
|
||||
}
|
||||
|
||||
/// Emit a lint and help at the appropriate level, for a particular span.
|
||||
fn span_lint_help(&self, lint: &'static Lint, span: Span, msg: &str, help: &str) {
|
||||
self.lookup(lint, Some(span), |err| {
|
||||
let mut err = err.build(msg);
|
||||
self.span_lint(lint, span, msg);
|
||||
err.span_help(span, help);
|
||||
err.emit();
|
||||
});
|
||||
}
|
||||
|
||||
/// Emit a lint at the appropriate level, with no associated span.
|
||||
fn lint(&self, lint: &'static Lint, msg: &str) {
|
||||
self.lookup_and_emit(lint, None as Option<Span>, msg);
|
||||
fn lint(&self, lint: &'static Lint, decorate: impl for<'a> FnOnce(LintDiagnosticBuilder<'a>)) {
|
||||
self.lookup(lint, None as Option<Span>, decorate);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -37,11 +37,12 @@ struct EarlyContextAndPass<'a, T: EarlyLintPass> {
|
||||
impl<'a, T: EarlyLintPass> EarlyContextAndPass<'a, T> {
|
||||
fn check_id(&mut self, id: ast::NodeId) {
|
||||
for early_lint in self.context.buffered.take(id) {
|
||||
self.context.lookup_and_emit_with_diagnostics(
|
||||
let rustc_session::lint::BufferedEarlyLint { span, msg, node_id: _, lint_id: _, diagnostic } = early_lint;
|
||||
self.context.lookup_with_diagnostics(
|
||||
early_lint.lint_id.lint,
|
||||
Some(early_lint.span.clone()),
|
||||
&early_lint.msg,
|
||||
early_lint.diagnostic,
|
||||
Some(span),
|
||||
|lint| lint.build(&msg).emit(),
|
||||
diagnostic,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -266,10 +266,10 @@ fn lint_int_literal<'a, 'tcx>(
|
||||
}
|
||||
}
|
||||
|
||||
cx.span_lint(
|
||||
cx.struct_span_lint(
|
||||
OVERFLOWING_LITERALS,
|
||||
e.span,
|
||||
&format!("literal out of range for `{}`", t.name_str()),
|
||||
|lint| lint.build(&format!("literal out of range for `{}`", t.name_str())).emit(),
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -321,10 +321,10 @@ fn lint_uint_literal<'a, 'tcx>(
|
||||
report_bin_hex_error(cx, e, attr::IntType::UnsignedInt(t), repr_str, lit_val, false);
|
||||
return;
|
||||
}
|
||||
cx.span_lint(
|
||||
cx.struct_span_lint(
|
||||
OVERFLOWING_LITERALS,
|
||||
e.span,
|
||||
&format!("literal out of range for `{}`", t.name_str()),
|
||||
|lint| lint.build(&format!("literal out of range for `{}`", t.name_str())).emit(),
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -355,10 +355,10 @@ fn lint_literal<'a, 'tcx>(
|
||||
_ => bug!(),
|
||||
};
|
||||
if is_infinite == Ok(true) {
|
||||
cx.span_lint(
|
||||
cx.struct_span_lint(
|
||||
OVERFLOWING_LITERALS,
|
||||
e.span,
|
||||
&format!("literal out of range for `{}`", t.name_str()),
|
||||
|lint| lint.build(&format!("literal out of range for `{}`", t.name_str())).emit(),
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -377,10 +377,10 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TypeLimits {
|
||||
}
|
||||
hir::ExprKind::Binary(binop, ref l, ref r) => {
|
||||
if is_comparison(binop) && !check_limits(cx, binop, &l, &r) {
|
||||
cx.span_lint(
|
||||
cx.struct_span_lint(
|
||||
UNUSED_COMPARISONS,
|
||||
e.span,
|
||||
"comparison is useless due to type limits",
|
||||
|lint| lint.build("comparison is useless due to type limits").emit(),
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -1055,14 +1055,14 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for VariantSizeDifferences {
|
||||
// We only warn if the largest variant is at least thrice as large as
|
||||
// the second-largest.
|
||||
if largest > slargest * 3 && slargest > 0 {
|
||||
cx.span_lint(
|
||||
cx.struct_span_lint(
|
||||
VARIANT_SIZE_DIFFERENCES,
|
||||
enum_definition.variants[largest_index].span,
|
||||
&format!(
|
||||
|lint| lint.build(&format!(
|
||||
"enum variant is more than three times \
|
||||
larger ({} bytes) than the next largest",
|
||||
largest
|
||||
),
|
||||
)).emit(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -104,16 +104,16 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedResults {
|
||||
};
|
||||
|
||||
if let Some(must_use_op) = must_use_op {
|
||||
cx.span_lint(
|
||||
cx.struct_span_lint(
|
||||
UNUSED_MUST_USE,
|
||||
expr.span,
|
||||
&format!("unused {} that must be used", must_use_op),
|
||||
|lint| lint.build(&format!("unused {} that must be used", must_use_op)).emit(),
|
||||
);
|
||||
op_warned = true;
|
||||
}
|
||||
|
||||
if !(type_permits_lack_of_use || fn_warned || op_warned) {
|
||||
cx.span_lint(UNUSED_RESULTS, s.span, "unused result");
|
||||
cx.struct_span_lint(UNUSED_RESULTS, s.span, |lint| lint.build("unused result").emit());
|
||||
}
|
||||
|
||||
// Returns whether an error has been emitted (and thus another does not need to be later).
|
||||
@ -247,7 +247,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for PathStatements {
|
||||
fn check_stmt(&mut self, cx: &LateContext<'_, '_>, s: &hir::Stmt<'_>) {
|
||||
if let hir::StmtKind::Semi(ref expr) = s.kind {
|
||||
if let hir::ExprKind::Path(_) = expr.kind {
|
||||
cx.span_lint(PATH_STATEMENTS, s.span, "path statement with no effect");
|
||||
cx.struct_span_lint(PATH_STATEMENTS, s.span, |lint| lint.build("path statement with no effect").emit());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -288,17 +288,19 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedAttributes {
|
||||
|
||||
if !attr::is_used(attr) {
|
||||
debug!("emitting warning for: {:?}", attr);
|
||||
cx.span_lint(UNUSED_ATTRIBUTES, attr.span, "unused attribute");
|
||||
cx.struct_span_lint(UNUSED_ATTRIBUTES, attr.span, |lint| lint.build("unused attribute").emit());
|
||||
// Is it a builtin attribute that must be used at the crate level?
|
||||
if attr_info.map_or(false, |(_, ty, ..)| ty == &AttributeType::CrateLevel) {
|
||||
let msg = match attr.style {
|
||||
ast::AttrStyle::Outer => {
|
||||
"crate-level attribute should be an inner attribute: add an exclamation \
|
||||
mark: `#![foo]`"
|
||||
}
|
||||
ast::AttrStyle::Inner => "crate-level attribute should be in the root module",
|
||||
};
|
||||
cx.span_lint(UNUSED_ATTRIBUTES, attr.span, msg);
|
||||
cx.struct_span_lint(UNUSED_ATTRIBUTES, attr.span, |lint| {
|
||||
let msg = match attr.style {
|
||||
ast::AttrStyle::Outer => {
|
||||
"crate-level attribute should be an inner attribute: add an exclamation \
|
||||
mark: `#![foo]`"
|
||||
}
|
||||
ast::AttrStyle::Inner => "crate-level attribute should be in the root module",
|
||||
};
|
||||
lint.build(msg).emit()
|
||||
});
|
||||
}
|
||||
} else {
|
||||
debug!("Attr was used: {:?}", attr);
|
||||
@ -635,8 +637,9 @@ impl UnusedImportBraces {
|
||||
ast::UseTreeKind::Nested(_) => return,
|
||||
};
|
||||
|
||||
let msg = format!("braces around {} is unnecessary", node_name);
|
||||
cx.span_lint(UNUSED_IMPORT_BRACES, item.span, &msg);
|
||||
cx.struct_span_lint(UNUSED_IMPORT_BRACES, item.span, |lint|
|
||||
lint.build(&format!("braces around {} is unnecessary", node_name)).emit()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -666,15 +669,17 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedAllocation {
|
||||
|
||||
for adj in cx.tables.expr_adjustments(e) {
|
||||
if let adjustment::Adjust::Borrow(adjustment::AutoBorrow::Ref(_, m)) = adj.kind {
|
||||
let msg = match m {
|
||||
adjustment::AutoBorrowMutability::Not => {
|
||||
"unnecessary allocation, use `&` instead"
|
||||
}
|
||||
adjustment::AutoBorrowMutability::Mut { .. } => {
|
||||
"unnecessary allocation, use `&mut` instead"
|
||||
}
|
||||
};
|
||||
cx.span_lint(UNUSED_ALLOCATION, e.span, msg);
|
||||
cx.struct_span_lint(UNUSED_ALLOCATION, e.span, |lint| {
|
||||
let msg = match m {
|
||||
adjustment::AutoBorrowMutability::Not => {
|
||||
"unnecessary allocation, use `&` instead"
|
||||
}
|
||||
adjustment::AutoBorrowMutability::Mut { .. } => {
|
||||
"unnecessary allocation, use `&mut` instead"
|
||||
}
|
||||
};
|
||||
lint.build(msg).emit()
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2959,10 +2959,12 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs {
|
||||
lint::builtin::INLINE_NO_SANITIZE,
|
||||
hir_id,
|
||||
no_sanitize_span,
|
||||
"`no_sanitize` will have no effect after inlining",
|
||||
|lint| {
|
||||
lint.build("`no_sanitize` will have no effect after inlining")
|
||||
.span_note(inline_span, "inlining requested here")
|
||||
.emit();
|
||||
},
|
||||
)
|
||||
.span_note(inline_span, "inlining requested here")
|
||||
.emit();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user