]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_passes/src/debugger_visualizer.rs
Auto merge of #102106 - djkoloski:sync-from-clippy, r=Manishearth
[rust.git] / compiler / rustc_passes / src / debugger_visualizer.rs
1 //! Detecting usage of the `#[debugger_visualizer]` attribute.
2
3 use hir::CRATE_HIR_ID;
4 use rustc_data_structures::fx::FxHashSet;
5 use rustc_expand::base::resolve_path;
6 use rustc_hir as hir;
7 use rustc_hir::def_id::CrateNum;
8 use rustc_hir::HirId;
9 use rustc_middle::ty::query::Providers;
10 use rustc_middle::ty::TyCtxt;
11 use rustc_span::def_id::LOCAL_CRATE;
12 use rustc_span::{sym, DebuggerVisualizerFile, DebuggerVisualizerType};
13
14 use std::sync::Arc;
15
16 fn check_for_debugger_visualizer<'tcx>(
17     tcx: TyCtxt<'tcx>,
18     hir_id: HirId,
19     debugger_visualizers: &mut FxHashSet<DebuggerVisualizerFile>,
20 ) {
21     let attrs = tcx.hir().attrs(hir_id);
22     for attr in attrs {
23         if attr.has_name(sym::debugger_visualizer) {
24             let Some(list) = attr.meta_item_list() else {
25                 continue
26             };
27
28             let meta_item = match list.len() {
29                 1 => match list[0].meta_item() {
30                     Some(meta_item) => meta_item,
31                     _ => continue,
32                 },
33                 _ => continue,
34             };
35
36             let visualizer_type = match meta_item.name_or_empty() {
37                 sym::natvis_file => DebuggerVisualizerType::Natvis,
38                 sym::gdb_script_file => DebuggerVisualizerType::GdbPrettyPrinter,
39                 _ => continue,
40             };
41
42             let file = match meta_item.value_str() {
43                 Some(value) => {
44                     match resolve_path(&tcx.sess.parse_sess, value.as_str(), attr.span) {
45                         Ok(file) => file,
46                         _ => continue,
47                     }
48                 }
49                 None => continue,
50             };
51
52             match std::fs::read(&file) {
53                 Ok(contents) => {
54                     debugger_visualizers
55                         .insert(DebuggerVisualizerFile::new(Arc::from(contents), visualizer_type));
56                 }
57                 Err(err) => {
58                     tcx.sess
59                         .struct_span_err(
60                             meta_item.span,
61                             &format!("couldn't read {}: {}", file.display(), err),
62                         )
63                         .emit();
64                 }
65             }
66         }
67     }
68 }
69
70 /// Traverses and collects the debugger visualizers for a specific crate.
71 fn debugger_visualizers<'tcx>(tcx: TyCtxt<'tcx>, cnum: CrateNum) -> Vec<DebuggerVisualizerFile> {
72     assert_eq!(cnum, LOCAL_CRATE);
73
74     // Initialize the collector.
75     let mut debugger_visualizers = FxHashSet::default();
76
77     // Collect debugger visualizers in this crate.
78     tcx.hir().for_each_module(|id| {
79         check_for_debugger_visualizer(
80             tcx,
81             tcx.hir().local_def_id_to_hir_id(id),
82             &mut debugger_visualizers,
83         )
84     });
85
86     // Collect debugger visualizers on the crate attributes.
87     check_for_debugger_visualizer(tcx, CRATE_HIR_ID, &mut debugger_visualizers);
88
89     // Extract out the found debugger_visualizer items.
90     let mut visualizers = debugger_visualizers.into_iter().collect::<Vec<_>>();
91
92     // Sort the visualizers so we always get a deterministic query result.
93     visualizers.sort();
94     visualizers
95 }
96
97 pub fn provide(providers: &mut Providers) {
98     providers.debugger_visualizers = debugger_visualizers;
99 }