| //! Walks the crate looking for items/impl-items/trait-items that have |
| //! either a `rustc_symbol_name` or `rustc_def_path` attribute and |
| //! generates an error giving, respectively, the symbol name or |
| //! def-path. This is used for unit testing the code that generates |
| //! paths etc in all kinds of annoying scenarios. |
| |
| use rustc_hir::def_id::LocalDefId; |
| use rustc_middle::ty::print::with_no_trimmed_paths; |
| use rustc_middle::ty::{GenericArgs, Instance, TyCtxt}; |
| use rustc_span::symbol::{Symbol, sym}; |
| |
| use crate::errors::{Kind, TestOutput}; |
| |
| const SYMBOL_NAME: Symbol = sym::rustc_symbol_name; |
| const DEF_PATH: Symbol = sym::rustc_def_path; |
| |
| pub fn report_symbol_names(tcx: TyCtxt<'_>) { |
| // if the `rustc_attrs` feature is not enabled, then the |
| // attributes we are interested in cannot be present anyway, so |
| // skip the walk. |
| if !tcx.features().rustc_attrs { |
| return; |
| } |
| |
| tcx.dep_graph.with_ignore(|| { |
| let mut symbol_names = SymbolNamesTest { tcx }; |
| let crate_items = tcx.hir_crate_items(()); |
| |
| for id in crate_items.free_items() { |
| symbol_names.process_attrs(id.owner_id.def_id); |
| } |
| |
| for id in crate_items.trait_items() { |
| symbol_names.process_attrs(id.owner_id.def_id); |
| } |
| |
| for id in crate_items.impl_items() { |
| symbol_names.process_attrs(id.owner_id.def_id); |
| } |
| |
| for id in crate_items.foreign_items() { |
| symbol_names.process_attrs(id.owner_id.def_id); |
| } |
| }) |
| } |
| |
| struct SymbolNamesTest<'tcx> { |
| tcx: TyCtxt<'tcx>, |
| } |
| |
| impl SymbolNamesTest<'_> { |
| fn process_attrs(&mut self, def_id: LocalDefId) { |
| let tcx = self.tcx; |
| // The formatting of `tag({})` is chosen so that tests can elect |
| // to test the entirety of the string, if they choose, or else just |
| // some subset. |
| for attr in tcx.get_attrs(def_id, SYMBOL_NAME) { |
| let def_id = def_id.to_def_id(); |
| let instance = Instance::new( |
| def_id, |
| tcx.erase_regions(GenericArgs::identity_for_item(tcx, def_id)), |
| ); |
| let mangled = tcx.symbol_name(instance); |
| tcx.dcx().emit_err(TestOutput { |
| span: attr.span, |
| kind: Kind::SymbolName, |
| content: format!("{mangled}"), |
| }); |
| if let Ok(demangling) = rustc_demangle::try_demangle(mangled.name) { |
| tcx.dcx().emit_err(TestOutput { |
| span: attr.span, |
| kind: Kind::Demangling, |
| content: format!("{demangling}"), |
| }); |
| tcx.dcx().emit_err(TestOutput { |
| span: attr.span, |
| kind: Kind::DemanglingAlt, |
| content: format!("{demangling:#}"), |
| }); |
| } |
| } |
| |
| for attr in tcx.get_attrs(def_id, DEF_PATH) { |
| tcx.dcx().emit_err(TestOutput { |
| span: attr.span, |
| kind: Kind::DefPath, |
| content: with_no_trimmed_paths!(tcx.def_path_str(def_id)), |
| }); |
| } |
| } |
| } |