Skip to main content

rustc_lint/
expect.rs

1use rustc_attr_ir::find_attr;
2use rustc_data_structures::fx::FxHashSet;
3use rustc_lint_defs::builtin::UNFULFILLED_LINT_EXPECTATIONS;
4use rustc_lint_defs::{LintExpectationId, StableLintExpectationId};
5use rustc_middle::lint::LintExpectation;
6use rustc_middle::query::Providers;
7use rustc_middle::ty::TyCtxt;
8use rustc_span::Symbol;
9
10use crate::diagnostics::{Expectation, ExpectationNote};
11
12pub(crate) fn provide(providers: &mut Providers) {
13    *providers = Providers { lint_expectations, check_expectations, ..*providers };
14}
15
16fn lint_expectations(tcx: TyCtxt<'_>, (): ()) -> Vec<(StableLintExpectationId, LintExpectation)> {
17    let krate = tcx.hir_crate_items(());
18
19    let mut expectations = Vec::new();
20
21    for owner in krate.owners() {
22        let lints = tcx.shallow_lint_levels_on(owner);
23        expectations.extend_from_slice(&lints.expectations);
24    }
25
26    expectations
27}
28
29fn check_expectations(tcx: TyCtxt<'_>, tool_filter: Option<Symbol>) {
30    let lint_expectations = tcx.lint_expectations(());
31    let fulfilled_expectations = tcx.dcx().steal_fulfilled_expectation_ids();
32
33    // Turn a `LintExpectationId` into a `(AttrId, lint_index)` pair.
34    let canonicalize_id = |expect_id: &LintExpectationId| {
35        let (attr_id, lint_index) = match *expect_id {
36            LintExpectationId::Unstable(id) => (id.attr_id, id.lint_index),
37            LintExpectationId::Stable(id) => {
38                // We are an `eval_always` query, so looking at the attribute's `AttrId` is ok.
39
40                let lint_checks = {
    {
        'done:
            {
            for i in ::rustc_attr_ir::HasAttrs::get_attrs(id.hir_id, &tcx) {
                #[allow(unused_imports)]
                use ::rustc_attr_ir::AttributeKind::*;
                let i: &::rustc_attr_ir::Attribute = i;
                match i {
                    ::rustc_attr_ir::Attribute::Parsed(LintCheck(lints)) => {
                        break 'done Some(lints);
                    }
                    ::rustc_attr_ir::Attribute::Unparsed(..) =>
                        {}
                        #[deny(unreachable_patterns)]
                        _ => {}
                }
            }
            None
        }
    }
}find_attr!(tcx, id.hir_id, LintCheck(lints) => lints).unwrap();
41                let attr_id = lint_checks[id.lint_index as usize].attr_id.attr_id;
42
43                (attr_id, id.lint_index)
44            }
45        };
46        (attr_id, lint_index)
47    };
48
49    let fulfilled_expectations: FxHashSet<_> =
50        fulfilled_expectations.iter().map(canonicalize_id).collect();
51
52    for (expect_id, expectation) in lint_expectations {
53        let hir_id = expect_id.hir_id;
54        let expect_id = canonicalize_id(&LintExpectationId::Stable(*expect_id));
55
56        if !fulfilled_expectations.contains(&expect_id)
57            && tool_filter.is_none_or(|filter| expectation.lint_tool == Some(filter))
58        {
59            let rationale = expectation.reason.map(|rationale| ExpectationNote { rationale });
60            let note = expectation.is_unfulfilled_lint_expectations;
61            tcx.emit_node_span_lint(
62                UNFULFILLED_LINT_EXPECTATIONS,
63                hir_id,
64                expectation.emission_span,
65                Expectation { rationale, note },
66            );
67        }
68    }
69}