| // Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT |
| // file at the top-level directory of this distribution and at |
| // http://rust-lang.org/COPYRIGHT. |
| // |
| // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or |
| // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license |
| // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your |
| // option. This file may not be copied, modified, or distributed |
| // except according to those terms. |
| |
| //! Walks the crate looking for items/impl-items/trait-items that have |
| //! either a `rustc_symbol_name` or `rustc_item_path` attribute and |
| //! generates an error giving, respectively, the symbol name or |
| //! item-path. This is used for unit testing the code that generates |
| //! paths etc in all kinds of annoying scenarios. |
| |
| use rustc::hir; |
| use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap}; |
| use rustc::ty::TyCtxt; |
| use syntax::ast; |
| |
| use rustc_mir::monomorphize::Instance; |
| |
| const SYMBOL_NAME: &'static str = "rustc_symbol_name"; |
| const ITEM_PATH: &'static str = "rustc_item_path"; |
| |
| pub fn report_symbol_names<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { |
| // 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.sess.features.borrow().rustc_attrs { |
| return; |
| } |
| |
| tcx.dep_graph.with_ignore(|| { |
| let mut visitor = SymbolNamesTest { tcx: tcx }; |
| // FIXME(#37712) could use ItemLikeVisitor if trait items were item-like |
| tcx.hir.krate().visit_all_item_likes(&mut visitor.as_deep_visitor()); |
| }) |
| } |
| |
| struct SymbolNamesTest<'a, 'tcx:'a> { |
| tcx: TyCtxt<'a, 'tcx, 'tcx>, |
| } |
| |
| impl<'a, 'tcx> SymbolNamesTest<'a, 'tcx> { |
| fn process_attrs(&mut self, |
| node_id: ast::NodeId) { |
| let tcx = self.tcx; |
| let def_id = tcx.hir.local_def_id(node_id); |
| for attr in tcx.get_attrs(def_id).iter() { |
| if attr.check_name(SYMBOL_NAME) { |
| // for now, can only use on monomorphic names |
| let instance = Instance::mono(tcx, def_id); |
| let name = self.tcx.symbol_name(instance); |
| tcx.sess.span_err(attr.span, &format!("symbol-name({})", name)); |
| } else if attr.check_name(ITEM_PATH) { |
| let path = tcx.item_path_str(def_id); |
| tcx.sess.span_err(attr.span, &format!("item-path({})", path)); |
| } |
| |
| // (*) 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. |
| } |
| } |
| } |
| |
| impl<'a, 'tcx> Visitor<'tcx> for SymbolNamesTest<'a, 'tcx> { |
| fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> { |
| NestedVisitorMap::None |
| } |
| |
| fn visit_item(&mut self, item: &'tcx hir::Item) { |
| self.process_attrs(item.id); |
| intravisit::walk_item(self, item); |
| } |
| |
| fn visit_trait_item(&mut self, ti: &'tcx hir::TraitItem) { |
| self.process_attrs(ti.id); |
| intravisit::walk_trait_item(self, ti) |
| } |
| |
| fn visit_impl_item(&mut self, ii: &'tcx hir::ImplItem) { |
| self.process_attrs(ii.id); |
| intravisit::walk_impl_item(self, ii) |
| } |
| } |