Move lint expectation checking into a separate query (RFC 2383)
This commit is contained in:
parent
7f03681cd9
commit
2c5e85249f
@ -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(())
|
||||
|
@ -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 {
|
||||
|
@ -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));
|
||||
}
|
||||
|
@ -371,7 +371,12 @@ pub(crate) fn push(
|
||||
};
|
||||
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 @@ pub(crate) fn push(
|
||||
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 @@ pub(crate) fn push(
|
||||
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 @@ pub(crate) fn push(
|
||||
}
|
||||
}
|
||||
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);
|
||||
|
@ -109,6 +109,7 @@
|
||||
|
||||
pub fn provide(providers: &mut Providers) {
|
||||
levels::provide(providers);
|
||||
expect::provide(providers);
|
||||
*providers = Providers { lint_mod, ..*providers };
|
||||
}
|
||||
|
||||
|
@ -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 @@ pub fn new(
|
||||
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 }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -157,6 +157,25 @@
|
||||
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 {
|
||||
|
@ -435,6 +435,16 @@ fn default_span(&self, _tcx: TyCtxt<'_>) -> Span {
|
||||
}
|
||||
}
|
||||
|
||||
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> {
|
||||
|
Loading…
Reference in New Issue
Block a user