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