about summary refs log tree commit diff
path: root/compiler
diff options
context:
space:
mode:
authorxFrednet <xFrednet@gmail.com>2022-03-29 00:10:45 +0200
committerxFrednet <xFrednet@gmail.com>2022-05-08 14:37:14 +0200
commit2c5e85249f8b10b5fb0caf608d8b2537620285c6 (patch)
tree8d3d6e7b8e79d54df8b5eda69dbe45923b666a47 /compiler
parent7f03681cd941c7e18ee99549148b8aa6f468d7c2 (diff)
downloadrust-2c5e85249f8b10b5fb0caf608d8b2537620285c6.tar.gz
rust-2c5e85249f8b10b5fb0caf608d8b2537620285c6.zip
Move lint expectation checking into a separate query (RFC 2383)
Diffstat (limited to 'compiler')
-rw-r--r--compiler/rustc_interface/src/passes.rs4
-rw-r--r--compiler/rustc_lint/src/expect.rs12
-rw-r--r--compiler/rustc_lint/src/late.rs3
-rw-r--r--compiler/rustc_lint/src/levels.rs25
-rw-r--r--compiler/rustc_lint/src/lib.rs1
-rw-r--r--compiler/rustc_middle/src/lint.rs7
-rw-r--r--compiler/rustc_middle/src/query/mod.rs19
-rw-r--r--compiler/rustc_query_impl/src/keys.rs10
8 files changed, 68 insertions, 13 deletions
diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs
index 08987dff660..00119267e85 100644
--- a/compiler/rustc_interface/src/passes.rs
+++ b/compiler/rustc_interface/src/passes.rs
@@ -1009,6 +1009,10 @@ fn analysis(tcx: TyCtxt<'_>, (): ()) -> Result<()> {
                 });
             }
         );
+
+        // This check has to be run after all lints are done processing. We don't
+        // define a lint filter, as all lint checks should have finished at this point.
+        sess.time("check_lint_expectations", || tcx.check_expectations(None));
     });
 
     Ok(())
diff --git a/compiler/rustc_lint/src/expect.rs b/compiler/rustc_lint/src/expect.rs
index 67f5aa0540f..dc48ac0a618 100644
--- a/compiler/rustc_lint/src/expect.rs
+++ b/compiler/rustc_lint/src/expect.rs
@@ -1,10 +1,16 @@
 use crate::builtin;
 use rustc_hir::HirId;
+use rustc_middle::ty::query::Providers;
 use rustc_middle::{lint::LintExpectation, ty::TyCtxt};
 use rustc_session::lint::LintExpectationId;
 use rustc_span::symbol::sym;
+use rustc_span::Symbol;
 
-pub fn check_expectations(tcx: TyCtxt<'_>) {
+pub(crate) fn provide(providers: &mut Providers) {
+    *providers = Providers { check_expectations, ..*providers };
+}
+
+fn check_expectations(tcx: TyCtxt<'_>, tool_filter: Option<Symbol>) {
     if !tcx.sess.features_untracked().enabled(sym::lint_reasons) {
         return;
     }
@@ -13,7 +19,9 @@ pub fn check_expectations(tcx: TyCtxt<'_>) {
     let lint_expectations = &tcx.lint_levels(()).lint_expectations;
 
     for (id, expectation) in lint_expectations {
-        if !fulfilled_expectations.contains(id) {
+        if !fulfilled_expectations.contains(id)
+            && tool_filter.map_or(true, |filter| expectation.lint_tool == Some(filter))
+        {
             // This check will always be true, since `lint_expectations` only
             // holds stable ids
             if let LintExpectationId::Stable { hir_id, .. } = id {
diff --git a/compiler/rustc_lint/src/late.rs b/compiler/rustc_lint/src/late.rs
index 0ac636b878e..0ce760b64d9 100644
--- a/compiler/rustc_lint/src/late.rs
+++ b/compiler/rustc_lint/src/late.rs
@@ -503,7 +503,4 @@ pub fn check_crate<'tcx, T: LateLintPass<'tcx>>(
             });
         },
     );
-
-    // This check has to be run after all lints are done processing for this crate
-    tcx.sess.time("check_lint_expectations", || crate::expect::check_expectations(tcx));
 }
diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs
index 01f1d1e79ac..257549bf1a1 100644
--- a/compiler/rustc_lint/src/levels.rs
+++ b/compiler/rustc_lint/src/levels.rs
@@ -371,7 +371,12 @@ impl<'s> LintLevelsBuilder<'s> {
                             };
                             self.lint_expectations.push((
                                 expect_id,
-                                LintExpectation::new(reason, sp, is_unfulfilled_lint_expectations),
+                                LintExpectation::new(
+                                    reason,
+                                    sp,
+                                    is_unfulfilled_lint_expectations,
+                                    tool_name,
+                                ),
                             ));
                         }
                         let src = LintLevelSource::Node(
@@ -400,8 +405,10 @@ impl<'s> LintLevelsBuilder<'s> {
                                     self.insert_spec(*id, (level, src));
                                 }
                                 if let Level::Expect(expect_id) = level {
-                                    self.lint_expectations
-                                        .push((expect_id, LintExpectation::new(reason, sp, false)));
+                                    self.lint_expectations.push((
+                                        expect_id,
+                                        LintExpectation::new(reason, sp, false, tool_name),
+                                    ));
                                 }
                             }
                             Err((Some(ids), ref new_lint_name)) => {
@@ -444,8 +451,10 @@ impl<'s> LintLevelsBuilder<'s> {
                                     self.insert_spec(*id, (level, src));
                                 }
                                 if let Level::Expect(expect_id) = level {
-                                    self.lint_expectations
-                                        .push((expect_id, LintExpectation::new(reason, sp, false)));
+                                    self.lint_expectations.push((
+                                        expect_id,
+                                        LintExpectation::new(reason, sp, false, tool_name),
+                                    ));
                                 }
                             }
                             Err((None, _)) => {
@@ -550,8 +559,10 @@ impl<'s> LintLevelsBuilder<'s> {
                             }
                         }
                         if let Level::Expect(expect_id) = level {
-                            self.lint_expectations
-                                .push((expect_id, LintExpectation::new(reason, sp, false)));
+                            self.lint_expectations.push((
+                                expect_id,
+                                LintExpectation::new(reason, sp, false, tool_name),
+                            ));
                         }
                     } else {
                         panic!("renamed lint does not exist: {}", new_name);
diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs
index 028c14366c6..a965587afb7 100644
--- a/compiler/rustc_lint/src/lib.rs
+++ b/compiler/rustc_lint/src/lib.rs
@@ -109,6 +109,7 @@ pub use rustc_session::lint::{LintArray, LintPass};
 
 pub fn provide(providers: &mut Providers) {
     levels::provide(providers);
+    expect::provide(providers);
     *providers = Providers { lint_mod, ..*providers };
 }
 
diff --git a/compiler/rustc_middle/src/lint.rs b/compiler/rustc_middle/src/lint.rs
index e55b0454eef..c7c5f56867a 100644
--- a/compiler/rustc_middle/src/lint.rs
+++ b/compiler/rustc_middle/src/lint.rs
@@ -210,6 +210,10 @@ pub struct LintExpectation {
     /// adjusted to include an additional note. Therefore, we have to track if
     /// the expectation is for the lint.
     pub is_unfulfilled_lint_expectations: bool,
+    /// This will hold the name of the tool that this lint belongs to. For
+    /// the lint `clippy::some_lint` the tool would be `clippy`, the same
+    /// goes for `rustdoc`. This will be `None` for rustc lints
+    pub lint_tool: Option<Symbol>,
 }
 
 impl LintExpectation {
@@ -217,8 +221,9 @@ impl LintExpectation {
         reason: Option<Symbol>,
         emission_span: Span,
         is_unfulfilled_lint_expectations: bool,
+        lint_tool: Option<Symbol>,
     ) -> Self {
-        Self { reason, emission_span, is_unfulfilled_lint_expectations }
+        Self { reason, emission_span, is_unfulfilled_lint_expectations, lint_tool }
     }
 }
 
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index e439d128dbc..3936b3f0d68 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -157,6 +157,25 @@ rustc_queries! {
         desc { "running analysis passes on this crate" }
     }
 
+    /// This query checks the fulfillment of collected lint expectations.
+    /// All lint emitting queries have to be done before this is executed
+    /// to ensure that all expectations can be fulfilled.
+    ///
+    /// This is an extra query to enable other drivers (like rustdoc) to
+    /// only execute a small subset of the [`analysis`] query, while allowing
+    /// lints to be expected. In rustc, this query will be executed as part of
+    /// the [`analysis`] query and doesn't have to be called a second time.
+    ///
+    /// Tools can additionally pass in a tool filter. That will restrict the
+    /// expectations to only trigger for lints starting with the listed tool
+    /// name. This is useful for cases were not all linting code from rustc
+    /// was called. With the default `none` all registered lints will also
+    /// be checked for expectation fulfillment.
+    query check_expectations(key: Option<Symbol>) -> () {
+        eval_always
+        desc { "checking lint expectations (RFC 2383)" }
+    }
+
     /// Maps from the `DefId` of an item (trait/struct/enum/fn) to its
     /// associated generics.
     query generics_of(key: DefId) -> ty::Generics {
diff --git a/compiler/rustc_query_impl/src/keys.rs b/compiler/rustc_query_impl/src/keys.rs
index 3f0f856b5dd..6fbafeb1d32 100644
--- a/compiler/rustc_query_impl/src/keys.rs
+++ b/compiler/rustc_query_impl/src/keys.rs
@@ -435,6 +435,16 @@ impl Key for Symbol {
     }
 }
 
+impl Key for Option<Symbol> {
+    #[inline(always)]
+    fn query_crate_is_local(&self) -> bool {
+        true
+    }
+    fn default_span(&self, _tcx: TyCtxt<'_>) -> Span {
+        DUMMY_SP
+    }
+}
+
 /// Canonical query goals correspond to abstract trait operations that
 /// are not tied to any crate in particular.
 impl<'tcx, T> Key for Canonical<'tcx, T> {