Skip to content

Commit

Permalink
Make cx.span_lint methods lazy
Browse files Browse the repository at this point in the history
- 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.
  • Loading branch information
jumbatm committed Feb 3, 2020
1 parent a1e8d54 commit eaf8fa7
Show file tree
Hide file tree
Showing 5 changed files with 82 additions and 113 deletions.
54 changes: 27 additions & 27 deletions src/librustc_lint/builtin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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());
}
}
}
Expand Down Expand Up @@ -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);
}
}

Expand All @@ -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(),
);
}
}
Expand All @@ -241,19 +241,19 @@ 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());
}
}
}

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,
Expand All @@ -270,12 +270,12 @@ impl EarlyLintPass for UnsafeCode {
) {
match fk {
FnKind::ItemFn(_, ast::FnHeader { unsafety: ast::Unsafety::Unsafe, .. }, ..) => {
self.report_unsafe(cx, span, "declaration of an `unsafe` function")
self.report_unsafe(cx, span, |lint| lint.build("declaration of an `unsafe` function").emit())
}

FnKind::Method(_, sig, ..) => {
if sig.header.unsafety == ast::Unsafety::Unsafe {
self.report_unsafe(cx, span, "implementation of an `unsafe` method")
self.report_unsafe(cx, span, |lint| lint.build("implementation of an `unsafe` method").emit())
}
}

Expand All @@ -286,7 +286,7 @@ impl EarlyLintPass for UnsafeCode {
fn check_trait_item(&mut self, cx: &EarlyContext<'_>, item: &ast::AssocItem) {
if let ast::AssocItemKind::Fn(ref sig, None) = item.kind {
if sig.header.unsafety == ast::Unsafety::Unsafe {
self.report_unsafe(cx, item.span, "declaration of an `unsafe` method")
self.report_unsafe(cx, item.span, |lint| lint.build("declaration of an `unsafe` method").emit())
}
}
}
Expand Down Expand Up @@ -372,10 +372,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(),
);
}
}
Expand Down Expand Up @@ -404,10 +404,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(),
);
}
}
Expand Down Expand Up @@ -555,11 +555,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(),
)
}
}
Expand Down Expand Up @@ -609,11 +609,11 @@ 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,
"type does not implement `fmt::Debug`; consider adding `#[derive(Debug)]` \
or a manual implementation",
|lint| lint.build("type does not implement `fmt::Debug`; consider adding `#[derive(Debug)]` \
or a manual implementation").emit(),
)
}
}
Expand Down Expand Up @@ -912,7 +912,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());
}
}
_ => (),
Expand Down Expand Up @@ -962,7 +962,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());
}
}
}
Expand Down Expand Up @@ -1244,14 +1244,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(),
);
}
}
Expand Down
57 changes: 10 additions & 47 deletions src/librustc_lint/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 => (),
Expand Down Expand Up @@ -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));
});
}

Expand All @@ -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,
Expand All @@ -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);
}
}

Expand Down
9 changes: 5 additions & 4 deletions src/librustc_lint/early.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
);
}
}
Expand Down
22 changes: 11 additions & 11 deletions src/librustc_lint/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(),
);
}
}
Expand Down Expand Up @@ -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(),
);
}
}
Expand Down Expand Up @@ -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(),
);
}
}
Expand All @@ -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(),
);
}
}
Expand Down Expand Up @@ -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(),
);
}
}
Expand Down
Loading

0 comments on commit eaf8fa7

Please sign in to comment.