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