2 use syntax::parse::token::{DelimToken, TokenKind};
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> {
48 // extern crate cfg_if;
49 // cfg_if::cfg_if! {..}
54 // extern crate cfg_if;
57 match mac.path.segments.first() {
58 Some(first_segment) => {
59 if first_segment.ident.name != Symbol::intern("cfg_if") {
60 return Err("Expected cfg_if");
64 return Err("Expected cfg_if");
69 stream_to_parser_with_base_dir(self.parse_sess, mac.tts.clone(), self.base_dir.clone());
70 parser.cfg_mods = false;
71 let mut process_if_cfg = true;
73 while parser.token.kind != TokenKind::Eof {
75 if !parser.eat_keyword(kw::If) {
76 return Err("Expected `if`");
79 .parse_attribute(false)
80 .map_err(|_| "Failed to parse attributes")?;
83 if !parser.eat(&TokenKind::OpenDelim(DelimToken::Brace)) {
84 return Err("Expected an opening brace");
87 while parser.token != TokenKind::CloseDelim(DelimToken::Brace)
88 && parser.token.kind != TokenKind::Eof
90 let item = match parser.parse_item() {
91 Ok(Some(item_ptr)) => item_ptr.into_inner(),
95 parser.sess.span_diagnostic.reset_err_count();
97 "Expected item inside cfg_if block, but failed to parse it as an item",
101 if let ast::ItemKind::Mod(..) = item.node {
102 self.mods.push(ModItem { item });
106 if !parser.eat(&TokenKind::CloseDelim(DelimToken::Brace)) {
107 return Err("Expected a closing brace");
110 if parser.eat(&TokenKind::Eof) {
114 if !parser.eat_keyword(kw::Else) {
115 return Err("Expected `else`");
118 process_if_cfg = parser.token.is_keyword(kw::If);
125 /// Extracts `path = "foo.rs"` from attributes.
127 pub(crate) struct PathVisitor {
128 /// A list of path defined in attributes.
133 pub(crate) fn paths(self) -> Vec<String> {
138 impl<'ast> MetaVisitor<'ast> for PathVisitor {
139 fn visit_meta_name_value(&mut self, meta_item: &'ast ast::MetaItem, lit: &'ast ast::Lit) {
140 if meta_item.check_name(Symbol::intern("path")) && lit.node.is_str() {
141 self.paths.push(lit_to_str(lit));
147 fn lit_to_str(lit: &ast::Lit) -> String {
149 ast::LitKind::Str(symbol, ..) => symbol.to_string(),
155 fn lit_to_str(lit: &ast::Lit) -> String {
157 ast::LitKind::Str(symbol, ..) => symbol.as_str().replace("/", "\\"),