about summary refs log tree commit diff
path: root/compiler/rustc_passes/src/debugger_visualizer.rs
diff options
context:
space:
mode:
authorridwanabdillahi <91507758+ridwanabdillahi@users.noreply.github.com>2022-04-25 18:02:43 -0700
committerridwanabdillahi <91507758+ridwanabdillahi@users.noreply.github.com>2022-05-03 10:53:54 -0700
commit175a4eab84379cebfc230ea357ae02dc9be39660 (patch)
tree19f4ae4b9b91cb53e6ee05368127daa4fbc88d33 /compiler/rustc_passes/src/debugger_visualizer.rs
parente1df625306f4136949e02612406f0c60df6008f3 (diff)
downloadrust-175a4eab84379cebfc230ea357ae02dc9be39660.tar.gz
rust-175a4eab84379cebfc230ea357ae02dc9be39660.zip
Add support for a new attribute `#[debugger_visualizer]` to support embedding debugger visualizers into a generated PDB.
Cleanup `DebuggerVisualizerFile` type and other minor cleanup of queries.

Merge the queries for debugger visualizers into a single query.

Revert move of `resolve_path` to `rustc_builtin_macros`. Update dependencies in Cargo.toml for `rustc_passes`.

Respond to PR comments. Load visualizer files into opaque bytes `Vec<u8>`. Debugger visualizers for dynamically linked crates should not be embedded in the current crate.

Update the unstable book with the new feature. Add the tracking issue for the debugger_visualizer feature.

Respond to PR comments and minor cleanups.
Diffstat (limited to 'compiler/rustc_passes/src/debugger_visualizer.rs')
-rw-r--r--compiler/rustc_passes/src/debugger_visualizer.rs137
1 files changed, 137 insertions, 0 deletions
diff --git a/compiler/rustc_passes/src/debugger_visualizer.rs b/compiler/rustc_passes/src/debugger_visualizer.rs
new file mode 100644
index 00000000000..09a73cc282e
--- /dev/null
+++ b/compiler/rustc_passes/src/debugger_visualizer.rs
@@ -0,0 +1,137 @@
+//! Detecting usage of the #[debugger_visualizer] attribute.
+
+use hir::CRATE_HIR_ID;
+use rustc_data_structures::fx::FxHashSet;
+use rustc_expand::base::resolve_path;
+use rustc_hir as hir;
+use rustc_hir::def_id::CrateNum;
+use rustc_hir::itemlikevisit::ItemLikeVisitor;
+use rustc_hir::{HirId, Target};
+use rustc_middle::ty::query::Providers;
+use rustc_middle::ty::TyCtxt;
+use rustc_span::def_id::LOCAL_CRATE;
+use rustc_span::{sym, DebuggerVisualizerFile, DebuggerVisualizerType};
+
+use std::sync::Arc;
+
+struct DebuggerVisualizerCollector<'tcx> {
+    debugger_visualizers: FxHashSet<DebuggerVisualizerFile>,
+    tcx: TyCtxt<'tcx>,
+}
+
+impl<'v, 'tcx> ItemLikeVisitor<'v> for DebuggerVisualizerCollector<'tcx> {
+    fn visit_item(&mut self, item: &hir::Item<'_>) {
+        let target = Target::from_item(item);
+        match target {
+            Target::Mod => {
+                self.check_for_debugger_visualizer(item.hir_id());
+            }
+            _ => {}
+        }
+    }
+
+    fn visit_trait_item(&mut self, _: &hir::TraitItem<'_>) {}
+
+    fn visit_impl_item(&mut self, _: &hir::ImplItem<'_>) {}
+
+    fn visit_foreign_item(&mut self, _: &hir::ForeignItem<'_>) {}
+}
+
+impl<'tcx> DebuggerVisualizerCollector<'tcx> {
+    fn new(tcx: TyCtxt<'tcx>) -> DebuggerVisualizerCollector<'tcx> {
+        DebuggerVisualizerCollector { tcx, debugger_visualizers: FxHashSet::default() }
+    }
+
+    fn check_for_debugger_visualizer(&mut self, hir_id: HirId) {
+        let attrs = self.tcx.hir().attrs(hir_id);
+        for attr in attrs {
+            if attr.has_name(sym::debugger_visualizer) {
+                let list = match attr.meta_item_list() {
+                    Some(list) => list,
+                    _ => continue,
+                };
+
+                let meta_item = match list.len() {
+                    1 => match list[0].meta_item() {
+                        Some(meta_item) => meta_item,
+                        _ => continue,
+                    },
+                    _ => continue,
+                };
+
+                let file = match (meta_item.name_or_empty(), meta_item.value_str()) {
+                    (sym::natvis_file, Some(value)) => {
+                        match resolve_path(&self.tcx.sess.parse_sess, value.as_str(), attr.span) {
+                            Ok(file) => file,
+                            Err(mut err) => {
+                                err.emit();
+                                continue;
+                            }
+                        }
+                    }
+                    (_, _) => continue,
+                };
+
+                if file.is_file() {
+                    let contents = match std::fs::read(&file) {
+                        Ok(contents) => contents,
+                        Err(err) => {
+                            self.tcx
+                                .sess
+                                .struct_span_err(
+                                    attr.span,
+                                    &format!(
+                                        "Unable to read contents of file `{}`. {}",
+                                        file.display(),
+                                        err
+                                    ),
+                                )
+                                .emit();
+                            continue;
+                        }
+                    };
+
+                    self.debugger_visualizers.insert(DebuggerVisualizerFile::new(
+                        Arc::from(contents),
+                        DebuggerVisualizerType::Natvis,
+                    ));
+                } else {
+                    self.tcx
+                        .sess
+                        .struct_span_err(
+                            attr.span,
+                            &format!("{} is not a valid file", file.display()),
+                        )
+                        .emit();
+                }
+            }
+        }
+    }
+}
+
+/// Traverses and collects the debugger visualizers for a specific crate.
+fn debugger_visualizers<'tcx>(tcx: TyCtxt<'tcx>, cnum: CrateNum) -> Vec<DebuggerVisualizerFile> {
+    assert_eq!(cnum, LOCAL_CRATE);
+
+    // Initialize the collector.
+    let mut collector = DebuggerVisualizerCollector::new(tcx);
+
+    // Collect debugger visualizers in this crate.
+    tcx.hir().visit_all_item_likes(&mut collector);
+
+    // Collect debugger visualizers on the crate attributes.
+    collector.check_for_debugger_visualizer(CRATE_HIR_ID);
+
+    // Extract out the found debugger_visualizer items.
+    let DebuggerVisualizerCollector { debugger_visualizers, .. } = collector;
+
+    let mut visualizers = debugger_visualizers.into_iter().collect::<Vec<_>>();
+
+    // Sort the visualizers so we always get a deterministic query result.
+    visualizers.sort();
+    visualizers
+}
+
+pub fn provide(providers: &mut Providers) {
+    providers.debugger_visualizers = debugger_visualizers;
+}