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, DynSync};
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(
14        Box<
15            dyn for<'a> FnOnce(DiagCtxtHandle<'a>, Level) -> Diag<'a, ()>
16                + DynSync
17                + DynSend
18                + 'static,
19        >,
20    ),
21    Builtin(BuiltinLintDiag),
22}
23
24impl std::fmt::Debug for DecorateDiagCompat {
25    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
26        f.debug_struct("DecorateDiagCompat").finish()
27    }
28}
29
30impl<D: for<'a> Diagnostic<'a, ()> + DynSync + DynSend + 'static> From<D> for DecorateDiagCompat {
31    #[inline]
32    fn from(d: D) -> Self {
33        Self::Dynamic(Box::new(|dcx, level| d.into_diag(dcx, level)))
34    }
35}
36
37impl From<BuiltinLintDiag> for DecorateDiagCompat {
38    #[inline]
39    fn from(b: BuiltinLintDiag) -> Self {
40        Self::Builtin(b)
41    }
42}
43
44/// Lints that are buffered up early on in the `Session` before the
45/// `LintLevels` is calculated.
46#[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)]
47pub struct BufferedEarlyLint {
48    /// The span of code that we are linting on.
49    pub span: Option<MultiSpan>,
50
51    /// The `NodeId` of the AST node that generated the lint.
52    pub node_id: NodeId,
53
54    /// A lint Id that can be passed to
55    /// `rustc_lint::early::EarlyContextAndPass::check_id`.
56    pub lint_id: LintId,
57
58    /// Customization of the `Diag<'_>` for the lint.
59    pub diagnostic: DecorateDiagCompat,
60}
61
62#[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)]
63pub struct LintBuffer {
64    pub map: FxIndexMap<NodeId, Vec<BufferedEarlyLint>>,
65}
66
67impl LintBuffer {
68    pub fn add_early_lint(&mut self, early_lint: BufferedEarlyLint) {
69        self.map.entry(early_lint.node_id).or_default().push(early_lint);
70    }
71
72    pub fn take(&mut self, id: NodeId) -> Vec<BufferedEarlyLint> {
73        // FIXME(#120456) - is `swap_remove` correct?
74        self.map.swap_remove(&id).unwrap_or_default()
75    }
76
77    pub fn buffer_lint(
78        &mut self,
79        lint: &'static Lint,
80        node_id: NodeId,
81        span: impl Into<MultiSpan>,
82        decorate: impl Into<DecorateDiagCompat>,
83    ) {
84        self.add_early_lint(BufferedEarlyLint {
85            lint_id: LintId::of(lint),
86            node_id,
87            span: Some(span.into()),
88            diagnostic: decorate.into(),
89        });
90    }
91
92    pub fn dyn_buffer_lint<
93        F: for<'a> FnOnce(DiagCtxtHandle<'a>, Level) -> Diag<'a, ()> + DynSync + DynSend + 'static,
94    >(
95        &mut self,
96        lint: &'static Lint,
97        node_id: NodeId,
98        span: impl Into<MultiSpan>,
99        callback: F,
100    ) {
101        self.add_early_lint(BufferedEarlyLint {
102            lint_id: LintId::of(lint),
103            node_id,
104            span: Some(span.into()),
105            diagnostic: DecorateDiagCompat::Dynamic(Box::new(callback)),
106        });
107    }
108}