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