Skip to content

Commit 2c5e852

Browse files
committed
Move lint expectation checking into a separate query (RFC 2383)
1 parent 7f03681 commit 2c5e852

File tree

8 files changed

+68
-13
lines changed

8 files changed

+68
-13
lines changed

compiler/rustc_interface/src/passes.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1009,6 +1009,10 @@ fn analysis(tcx: TyCtxt<'_>, (): ()) -> Result<()> {
10091009
});
10101010
}
10111011
);
1012+
1013+
// This check has to be run after all lints are done processing. We don't
1014+
// define a lint filter, as all lint checks should have finished at this point.
1015+
sess.time("check_lint_expectations", || tcx.check_expectations(None));
10121016
});
10131017

10141018
Ok(())

compiler/rustc_lint/src/expect.rs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,16 @@
11
use crate::builtin;
22
use rustc_hir::HirId;
3+
use rustc_middle::ty::query::Providers;
34
use rustc_middle::{lint::LintExpectation, ty::TyCtxt};
45
use rustc_session::lint::LintExpectationId;
56
use rustc_span::symbol::sym;
7+
use rustc_span::Symbol;
68

7-
pub fn check_expectations(tcx: TyCtxt<'_>) {
9+
pub(crate) fn provide(providers: &mut Providers) {
10+
*providers = Providers { check_expectations, ..*providers };
11+
}
12+
13+
fn check_expectations(tcx: TyCtxt<'_>, tool_filter: Option<Symbol>) {
814
if !tcx.sess.features_untracked().enabled(sym::lint_reasons) {
915
return;
1016
}
@@ -13,7 +19,9 @@ pub fn check_expectations(tcx: TyCtxt<'_>) {
1319
let lint_expectations = &tcx.lint_levels(()).lint_expectations;
1420

1521
for (id, expectation) in lint_expectations {
16-
if !fulfilled_expectations.contains(id) {
22+
if !fulfilled_expectations.contains(id)
23+
&& tool_filter.map_or(true, |filter| expectation.lint_tool == Some(filter))
24+
{
1725
// This check will always be true, since `lint_expectations` only
1826
// holds stable ids
1927
if let LintExpectationId::Stable { hir_id, .. } = id {

compiler/rustc_lint/src/late.rs

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -503,7 +503,4 @@ pub fn check_crate<'tcx, T: LateLintPass<'tcx>>(
503503
});
504504
},
505505
);
506-
507-
// This check has to be run after all lints are done processing for this crate
508-
tcx.sess.time("check_lint_expectations", || crate::expect::check_expectations(tcx));
509506
}

compiler/rustc_lint/src/levels.rs

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -371,7 +371,12 @@ impl<'s> LintLevelsBuilder<'s> {
371371
};
372372
self.lint_expectations.push((
373373
expect_id,
374-
LintExpectation::new(reason, sp, is_unfulfilled_lint_expectations),
374+
LintExpectation::new(
375+
reason,
376+
sp,
377+
is_unfulfilled_lint_expectations,
378+
tool_name,
379+
),
375380
));
376381
}
377382
let src = LintLevelSource::Node(
@@ -400,8 +405,10 @@ impl<'s> LintLevelsBuilder<'s> {
400405
self.insert_spec(*id, (level, src));
401406
}
402407
if let Level::Expect(expect_id) = level {
403-
self.lint_expectations
404-
.push((expect_id, LintExpectation::new(reason, sp, false)));
408+
self.lint_expectations.push((
409+
expect_id,
410+
LintExpectation::new(reason, sp, false, tool_name),
411+
));
405412
}
406413
}
407414
Err((Some(ids), ref new_lint_name)) => {
@@ -444,8 +451,10 @@ impl<'s> LintLevelsBuilder<'s> {
444451
self.insert_spec(*id, (level, src));
445452
}
446453
if let Level::Expect(expect_id) = level {
447-
self.lint_expectations
448-
.push((expect_id, LintExpectation::new(reason, sp, false)));
454+
self.lint_expectations.push((
455+
expect_id,
456+
LintExpectation::new(reason, sp, false, tool_name),
457+
));
449458
}
450459
}
451460
Err((None, _)) => {
@@ -550,8 +559,10 @@ impl<'s> LintLevelsBuilder<'s> {
550559
}
551560
}
552561
if let Level::Expect(expect_id) = level {
553-
self.lint_expectations
554-
.push((expect_id, LintExpectation::new(reason, sp, false)));
562+
self.lint_expectations.push((
563+
expect_id,
564+
LintExpectation::new(reason, sp, false, tool_name),
565+
));
555566
}
556567
} else {
557568
panic!("renamed lint does not exist: {}", new_name);

compiler/rustc_lint/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,7 @@ pub use rustc_session::lint::{LintArray, LintPass};
109109

110110
pub fn provide(providers: &mut Providers) {
111111
levels::provide(providers);
112+
expect::provide(providers);
112113
*providers = Providers { lint_mod, ..*providers };
113114
}
114115

compiler/rustc_middle/src/lint.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -210,15 +210,20 @@ pub struct LintExpectation {
210210
/// adjusted to include an additional note. Therefore, we have to track if
211211
/// the expectation is for the lint.
212212
pub is_unfulfilled_lint_expectations: bool,
213+
/// This will hold the name of the tool that this lint belongs to. For
214+
/// the lint `clippy::some_lint` the tool would be `clippy`, the same
215+
/// goes for `rustdoc`. This will be `None` for rustc lints
216+
pub lint_tool: Option<Symbol>,
213217
}
214218

215219
impl LintExpectation {
216220
pub fn new(
217221
reason: Option<Symbol>,
218222
emission_span: Span,
219223
is_unfulfilled_lint_expectations: bool,
224+
lint_tool: Option<Symbol>,
220225
) -> Self {
221-
Self { reason, emission_span, is_unfulfilled_lint_expectations }
226+
Self { reason, emission_span, is_unfulfilled_lint_expectations, lint_tool }
222227
}
223228
}
224229

compiler/rustc_middle/src/query/mod.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,25 @@ rustc_queries! {
157157
desc { "running analysis passes on this crate" }
158158
}
159159

160+
/// This query checks the fulfillment of collected lint expectations.
161+
/// All lint emitting queries have to be done before this is executed
162+
/// to ensure that all expectations can be fulfilled.
163+
///
164+
/// This is an extra query to enable other drivers (like rustdoc) to
165+
/// only execute a small subset of the [`analysis`] query, while allowing
166+
/// lints to be expected. In rustc, this query will be executed as part of
167+
/// the [`analysis`] query and doesn't have to be called a second time.
168+
///
169+
/// Tools can additionally pass in a tool filter. That will restrict the
170+
/// expectations to only trigger for lints starting with the listed tool
171+
/// name. This is useful for cases were not all linting code from rustc
172+
/// was called. With the default `none` all registered lints will also
173+
/// be checked for expectation fulfillment.
174+
query check_expectations(key: Option<Symbol>) -> () {
175+
eval_always
176+
desc { "checking lint expectations (RFC 2383)" }
177+
}
178+
160179
/// Maps from the `DefId` of an item (trait/struct/enum/fn) to its
161180
/// associated generics.
162181
query generics_of(key: DefId) -> ty::Generics {

compiler/rustc_query_impl/src/keys.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -435,6 +435,16 @@ impl Key for Symbol {
435435
}
436436
}
437437

438+
impl Key for Option<Symbol> {
439+
#[inline(always)]
440+
fn query_crate_is_local(&self) -> bool {
441+
true
442+
}
443+
fn default_span(&self, _tcx: TyCtxt<'_>) -> Span {
444+
DUMMY_SP
445+
}
446+
}
447+
438448
/// Canonical query goals correspond to abstract trait operations that
439449
/// are not tied to any crate in particular.
440450
impl<'tcx, T> Key for Canonical<'tcx, T> {

0 commit comments

Comments
 (0)