2 use syntax::parse::token::{DelimToken, Token};
3 use syntax::parse::{stream_to_parser_with_base_dir, Directory, ParseSess};
4 use syntax::symbol::kw;
5 use syntax::visit::Visitor;
6 use syntax_pos::Symbol;
8 use crate::attr::MetaVisitor;
10 pub(crate) struct ModItem {
11 pub(crate) item: ast::Item,
14 /// Traverse `cfg_if!` macro and fetch modules.
15 pub(crate) struct CfgIfVisitor<'a> {
16 parse_sess: &'a ParseSess,
18 base_dir: Directory<'a>,
21 impl<'a> CfgIfVisitor<'a> {
22 pub(crate) fn new(parse_sess: &'a ParseSess, base_dir: Directory<'a>) -> CfgIfVisitor<'a> {
30 pub(crate) fn mods(self) -> Vec<ModItem> {
35 impl<'a, 'ast: 'a> Visitor<'ast> for CfgIfVisitor<'a> {
36 fn visit_mac(&mut self, mac: &'ast ast::Mac) {
37 match self.visit_mac_inner(mac) {
39 Err(e) => debug!("{}", e),
44 impl<'a, 'ast: 'a> CfgIfVisitor<'a> {
45 fn visit_mac_inner(&mut self, mac: &'ast ast::Mac) -> Result<(), &'static str> {
46 if mac.node.path != Symbol::intern("cfg_if") {
47 return Err("Expected cfg_if");
50 let mut parser = stream_to_parser_with_base_dir(
53 self.base_dir.clone(),
55 parser.cfg_mods = false;
56 let mut process_if_cfg = true;
58 while parser.token != Token::Eof {
60 if !parser.eat_keyword(kw::If) {
61 return Err("Expected `if`");
64 .parse_attribute(false)
65 .map_err(|_| "Failed to parse attributes")?;
68 if !parser.eat(&Token::OpenDelim(DelimToken::Brace)) {
69 return Err("Expected an opening brace");
72 while parser.token != Token::CloseDelim(DelimToken::Brace) && parser.token != Token::Eof
74 let item = match parser.parse_item() {
75 Ok(Some(item_ptr)) => item_ptr.into_inner(),
79 parser.sess.span_diagnostic.reset_err_count();
81 "Expected item inside cfg_if block, but failed to parse it as an item",
85 if let ast::ItemKind::Mod(..) = item.node {
86 self.mods.push(ModItem { item });
90 if !parser.eat(&Token::CloseDelim(DelimToken::Brace)) {
91 return Err("Expected a closing brace");
94 if parser.eat(&Token::Eof) {
98 if !parser.eat_keyword(kw::Else) {
99 return Err("Expected `else`");
102 process_if_cfg = parser.token.is_keyword(kw::If);
109 /// Extracts `path = "foo.rs"` from attributes.
111 pub(crate) struct PathVisitor {
112 /// A list of path defined in attributes.
117 pub(crate) fn paths(self) -> Vec<String> {
122 impl<'ast> MetaVisitor<'ast> for PathVisitor {
123 fn visit_meta_name_value(&mut self, meta_item: &'ast ast::MetaItem, lit: &'ast ast::Lit) {
124 if meta_item.check_name(Symbol::intern("path")) && lit.node.is_str() {
125 self.paths.push(lit_to_str(lit));
131 fn lit_to_str(lit: &ast::Lit) -> String {
133 ast::LitKind::Str(symbol, ..) => symbol.to_string(),
139 fn lit_to_str(lit: &ast::Lit) -> String {
141 ast::LitKind::Str(symbol, ..) => symbol.as_str().replace("/", "\\"),