rustc_errors/
decorate_diag.rs

1/// This module provides types and traits for buffering lints until later in compilation.
2use rustc_ast::node_id::NodeId;
3use rustc_data_structures::fx::FxIndexMap;
4use rustc_error_messages::MultiSpan;
5use rustc_lint_defs::{BuiltinLintDiag, Lint, LintId};
6
7use crate::{DynSend, LintDiagnostic, LintDiagnosticBox};
8
9/// We can't implement `LintDiagnostic` for `BuiltinLintDiag`, because decorating some of its
10/// variants requires types we don't have yet. So, handle that case separately.
11pub enum DecorateDiagCompat {
12    Dynamic(Box<dyn for<'a> LintDiagnosticBox<'a, ()> + DynSend + 'static>),
13    Builtin(BuiltinLintDiag),
14}
15
16impl std::fmt::Debug for DecorateDiagCompat {
17    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
18        f.debug_struct("DecorateDiagCompat").finish()
19    }
20}
21
22impl !LintDiagnostic<'_, ()> for BuiltinLintDiag {}
23
24impl<D: for<'a> LintDiagnostic<'a, ()> + DynSend + 'static> From<D> for DecorateDiagCompat {
25    #[inline]
26    fn from(d: D) -> Self {
27        Self::Dynamic(Box::new(d))
28    }
29}
30
31impl From<BuiltinLintDiag> for DecorateDiagCompat {
32    #[inline]
33    fn from(b: BuiltinLintDiag) -> Self {
34        Self::Builtin(b)
35    }
36}
37
38/// Lints that are buffered up early on in the `Session` before the
39/// `LintLevels` is calculated.
40#[derive(Debug)]
41pub struct BufferedEarlyLint {
42    /// The span of code that we are linting on.
43    pub span: Option<MultiSpan>,
44
45    /// The `NodeId` of the AST node that generated the lint.
46    pub node_id: NodeId,
47
48    /// A lint Id that can be passed to
49    /// `rustc_lint::early::EarlyContextAndPass::check_id`.
50    pub lint_id: LintId,
51
52    /// Customization of the `Diag<'_>` for the lint.
53    pub diagnostic: DecorateDiagCompat,
54}
55
56#[derive(Default, Debug)]
57pub struct LintBuffer {
58    pub map: FxIndexMap<NodeId, Vec<BufferedEarlyLint>>,
59}
60
61impl LintBuffer {
62    pub fn add_early_lint(&mut self, early_lint: BufferedEarlyLint) {
63        self.map.entry(early_lint.node_id).or_default().push(early_lint);
64    }
65
66    pub fn take(&mut self, id: NodeId) -> Vec<BufferedEarlyLint> {
67        // FIXME(#120456) - is `swap_remove` correct?
68        self.map.swap_remove(&id).unwrap_or_default()
69    }
70
71    pub fn buffer_lint(
72        &mut self,
73        lint: &'static Lint,
74        node_id: NodeId,
75        span: impl Into<MultiSpan>,
76        decorate: impl Into<DecorateDiagCompat>,
77    ) {
78        self.add_early_lint(BufferedEarlyLint {
79            lint_id: LintId::of(lint),
80            node_id,
81            span: Some(span.into()),
82            diagnostic: decorate.into(),
83        });
84    }
85}