Skip to main content

rustc_errors/
decorate_diag.rs

1use std::any::Any;
2
3/// This module provides types and traits for buffering lints until later in compilation.
4use rustc_ast::node_id::NodeId;
5use rustc_data_structures::fx::FxIndexMap;
6use rustc_data_structures::sync::{DynSend, DynSync};
7use rustc_error_messages::MultiSpan;
8use rustc_lint_defs::{Lint, LintId};
9
10use crate::{Diag, DiagCtxtHandle, Diagnostic, Level};
11
12pub struct DecorateDiagCompat(
13    /// The third argument of the closure is a `Session`. However, due to the dependency tree,
14    /// we don't have access to `rustc_session` here, so we downcast it when needed.
15    pub  Box<
16        dyn for<'a> FnOnce(DiagCtxtHandle<'a>, Level, &dyn Any) -> Diag<'a, ()>
17            + DynSync
18            + DynSend
19            + 'static,
20    >,
21);
22
23impl std::fmt::Debug for DecorateDiagCompat {
24    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
25        f.debug_struct("DecorateDiagCompat").finish()
26    }
27}
28
29impl<D: for<'a> Diagnostic<'a, ()> + DynSync + DynSend + 'static> From<D> for DecorateDiagCompat {
30    #[inline]
31    fn from(d: D) -> Self {
32        Self(Box::new(|dcx, level, _| d.into_diag(dcx, level)))
33    }
34}
35
36/// Lints that are buffered up early on in the `Session` before the
37/// `LintLevels` is calculated.
38#[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)]
39pub struct BufferedEarlyLint {
40    /// The span of code that we are linting on.
41    pub span: Option<MultiSpan>,
42
43    /// The `NodeId` of the AST node that generated the lint.
44    pub node_id: NodeId,
45
46    /// A lint Id that can be passed to
47    /// `rustc_lint::early::EarlyContextAndPass::check_id`.
48    pub lint_id: LintId,
49
50    /// Customization of the `Diag<'_>` for the lint.
51    pub diagnostic: DecorateDiagCompat,
52}
53
54#[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)]
55pub struct LintBuffer {
56    pub map: FxIndexMap<NodeId, Vec<BufferedEarlyLint>>,
57}
58
59impl LintBuffer {
60    pub fn add_early_lint(&mut self, early_lint: BufferedEarlyLint) {
61        self.map.entry(early_lint.node_id).or_default().push(early_lint);
62    }
63
64    pub fn take(&mut self, id: NodeId) -> Vec<BufferedEarlyLint> {
65        // FIXME(#120456) - is `swap_remove` correct?
66        self.map.swap_remove(&id).unwrap_or_default()
67    }
68
69    pub fn buffer_lint(
70        &mut self,
71        lint: &'static Lint,
72        node_id: NodeId,
73        span: impl Into<MultiSpan>,
74        decorate: impl Into<DecorateDiagCompat>,
75    ) {
76        self.add_early_lint(BufferedEarlyLint {
77            lint_id: LintId::of(lint),
78            node_id,
79            span: Some(span.into()),
80            diagnostic: decorate.into(),
81        });
82    }
83
84    pub fn dyn_buffer_lint<
85        F: for<'a> FnOnce(DiagCtxtHandle<'a>, Level) -> Diag<'a, ()> + DynSync + DynSend + 'static,
86    >(
87        &mut self,
88        lint: &'static Lint,
89        node_id: NodeId,
90        span: impl Into<MultiSpan>,
91        callback: F,
92    ) {
93        self.add_early_lint(BufferedEarlyLint {
94            lint_id: LintId::of(lint),
95            node_id,
96            span: Some(span.into()),
97            diagnostic: DecorateDiagCompat(Box::new(|dcx, level, _| callback(dcx, level))),
98        });
99    }
100
101    pub fn dyn_buffer_lint_any<
102        F: for<'a> FnOnce(DiagCtxtHandle<'a>, Level, &dyn Any) -> Diag<'a, ()>
103            + DynSend
104            + DynSync
105            + 'static,
106    >(
107        &mut self,
108        lint: &'static Lint,
109        node_id: NodeId,
110        span: impl Into<MultiSpan>,
111        callback: F,
112    ) {
113        self.add_early_lint(BufferedEarlyLint {
114            lint_id: LintId::of(lint),
115            node_id,
116            span: Some(span.into()),
117            diagnostic: DecorateDiagCompat(Box::new(callback)),
118        });
119    }
120}