Skip to main content

rustc_passes/
debugger_visualizer.rs

1//! Detecting usage of the `#[debugger_visualizer]` attribute.
2
3use rustc_ast::{ItemKind, ast};
4use rustc_attr_ir::{Attribute, AttributeKind, DebugVisualizer};
5use rustc_attr_parsing::AttributeParser;
6use rustc_middle::middle::debugger_visualizer::DebuggerVisualizerFile;
7use rustc_middle::query::{LocalCrate, Providers};
8use rustc_middle::ty::TyCtxt;
9use rustc_session::Session;
10use rustc_span::sym;
11
12use crate::diagnostics::DebugVisualizerUnreadable;
13
14impl DebuggerVisualizerCollector<'_> {
15    fn check_for_debugger_visualizer(&mut self, attrs: &[ast::Attribute]) {
16        if let Some(Attribute::Parsed(AttributeKind::DebuggerVisualizer(visualizers))) =
17            AttributeParser::parse_limited_sym(&self.sess, attrs, &[sym::debugger_visualizer])
18        {
19            for DebugVisualizer { span, visualizer_type, path } in visualizers {
20                let file = match self.sess.resolve_path(path.as_str(), span) {
21                    Ok(file) => file,
22                    Err(err) => {
23                        err.emit();
24                        return;
25                    }
26                };
27
28                match self.sess.source_map().load_binary_file(&file) {
29                    Ok((source, _)) => {
30                        self.visualizers.push(DebuggerVisualizerFile::new(
31                            source,
32                            visualizer_type,
33                            file,
34                        ));
35                    }
36                    Err(error) => {
37                        self.sess.dcx().emit_err(DebugVisualizerUnreadable {
38                            span,
39                            file: &file,
40                            error,
41                        });
42                    }
43                }
44            }
45        }
46    }
47}
48
49struct DebuggerVisualizerCollector<'a> {
50    sess: &'a Session,
51    visualizers: Vec<DebuggerVisualizerFile>,
52}
53
54impl<'ast> rustc_ast::visit::Visitor<'ast> for DebuggerVisualizerCollector<'_> {
55    fn visit_item(&mut self, item: &'ast rustc_ast::Item) -> Self::Result {
56        if let ItemKind::Mod(..) = item.kind {
57            self.check_for_debugger_visualizer(&item.attrs);
58        }
59        rustc_ast::visit::walk_item(self, item);
60    }
61    fn visit_crate(&mut self, krate: &'ast ast::Crate) -> Self::Result {
62        self.check_for_debugger_visualizer(&krate.attrs);
63        rustc_ast::visit::walk_crate(self, krate);
64    }
65}
66
67/// Traverses and collects the debugger visualizers for a specific crate.
68fn debugger_visualizers(tcx: TyCtxt<'_>, _: LocalCrate) -> Vec<DebuggerVisualizerFile> {
69    let krate = &tcx.resolver_for_lowering().1;
70
71    let mut visitor = DebuggerVisualizerCollector { sess: tcx.sess, visualizers: Vec::new() };
72    rustc_ast::visit::Visitor::visit_crate(&mut visitor, &*krate.borrow());
73
74    // We are collecting visualizers in AST-order, which is deterministic,
75    // so we don't need to do any explicit sorting in order to get a
76    // deterministic query result
77    visitor.visualizers
78}
79
80pub(crate) fn provide(providers: &mut Providers) {
81    providers.debugger_visualizers = debugger_visualizers;
82}