diff options
Diffstat (limited to '')
-rw-r--r-- | compiler/rustc_passes/src/debugger_visualizer.rs | 99 |
1 files changed, 99 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 000000000..e08683fe2 --- /dev/null +++ b/compiler/rustc_passes/src/debugger_visualizer.rs @@ -0,0 +1,99 @@ +//! 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::HirId; +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; + +fn check_for_debugger_visualizer<'tcx>( + tcx: TyCtxt<'tcx>, + hir_id: HirId, + debugger_visualizers: &mut FxHashSet<DebuggerVisualizerFile>, +) { + let attrs = tcx.hir().attrs(hir_id); + for attr in attrs { + if attr.has_name(sym::debugger_visualizer) { + let Some(list) = attr.meta_item_list() else { + continue + }; + + let meta_item = match list.len() { + 1 => match list[0].meta_item() { + Some(meta_item) => meta_item, + _ => continue, + }, + _ => continue, + }; + + let visualizer_type = match meta_item.name_or_empty() { + sym::natvis_file => DebuggerVisualizerType::Natvis, + sym::gdb_script_file => DebuggerVisualizerType::GdbPrettyPrinter, + _ => continue, + }; + + let file = match meta_item.value_str() { + Some(value) => { + match resolve_path(&tcx.sess.parse_sess, value.as_str(), attr.span) { + Ok(file) => file, + _ => continue, + } + } + None => continue, + }; + + match std::fs::read(&file) { + Ok(contents) => { + debugger_visualizers + .insert(DebuggerVisualizerFile::new(Arc::from(contents), visualizer_type)); + } + Err(err) => { + tcx.sess + .struct_span_err( + meta_item.span, + &format!("couldn't read {}: {}", file.display(), err), + ) + .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 debugger_visualizers = FxHashSet::default(); + + // Collect debugger visualizers in this crate. + tcx.hir().for_each_module(|id| { + check_for_debugger_visualizer( + tcx, + tcx.hir().local_def_id_to_hir_id(id), + &mut debugger_visualizers, + ) + }); + + // Collect debugger visualizers on the crate attributes. + check_for_debugger_visualizer(tcx, CRATE_HIR_ID, &mut debugger_visualizers); + + // Extract out the found debugger_visualizer items. + 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; +} |