Skip to main content

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