about summary refs log tree commit diff
diff options
context:
space:
mode:
authorjumbatm <jumbatm@gmail.com>2020-02-02 19:41:14 +1000
committerjumbatm <jumbatm@gmail.com>2020-02-11 19:49:01 +1000
commit2f0430a163bb2f4fe6545064391606bb736e9e51 (patch)
treef31051b5d0d597131a62d983abfa00348ccb14e7
parentb2e78faa15263011dad1e9579fc59610d5b75579 (diff)
downloadrust-2f0430a163bb2f4fe6545064391606bb736e9e51.tar.gz
rust-2f0430a163bb2f4fe6545064391606bb736e9e51.zip
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.
-rw-r--r--src/librustc_lint/builtin.rs50
-rw-r--r--src/librustc_lint/context.rs57
-rw-r--r--src/librustc_lint/early.rs9
-rw-r--r--src/librustc_lint/types.rs22
-rw-r--r--src/librustc_lint/unused.rs53
-rw-r--r--src/librustc_typeck/collect.rs8
6 files changed, 85 insertions, 114 deletions
diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs
index 9fc81a4a1fd..7ebedd29cc4 100644
--- a/src/librustc_lint/builtin.rs
+++ b/src/librustc_lint/builtin.rs
@@ -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(),
                     );
                 }
             }
diff --git a/src/librustc_lint/context.rs b/src/librustc_lint/context.rs
index d9ad97654e0..232b56c88f2 100644
--- a/src/librustc_lint/context.rs
+++ b/src/librustc_lint/context.rs
@@ -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);
     }
 }
 
diff --git a/src/librustc_lint/early.rs b/src/librustc_lint/early.rs
index 27781eb41d2..4f337cd18aa 100644
--- a/src/librustc_lint/early.rs
+++ b/src/librustc_lint/early.rs
@@ -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,
             );
         }
     }
diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs
index d1982e9162e..f6404fb63d4 100644
--- a/src/librustc_lint/types.rs
+++ b/src/librustc_lint/types.rs
@@ -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(),
                 );
             }
         }
diff --git a/src/librustc_lint/unused.rs b/src/librustc_lint/unused.rs
index 2f4a9572a83..faa0b019311 100644
--- a/src/librustc_lint/unused.rs
+++ b/src/librustc_lint/unused.rs
@@ -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()
+                });
             }
         }
     }
diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs
index 1b4f0ffce9c..b661006d1dd 100644
--- a/src/librustc_typeck/collect.rs
+++ b/src/librustc_typeck/collect.rs
@@ -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();
             }
         }
     }