]> git.lizzy.rs Git - rust.git/blob - src/modules/visitor.rs
Rename `ast::Lit` as `ast::MetaItemLit`.
[rust.git] / src / modules / visitor.rs
1 use rustc_ast::ast;
2 use rustc_ast::visit::Visitor;
3 use rustc_span::Symbol;
4
5 use crate::attr::MetaVisitor;
6 use crate::parse::macros::cfg_if::parse_cfg_if;
7 use crate::parse::session::ParseSess;
8
9 pub(crate) struct ModItem {
10     pub(crate) item: ast::Item,
11 }
12
13 /// Traverse `cfg_if!` macro and fetch modules.
14 pub(crate) struct CfgIfVisitor<'a> {
15     parse_sess: &'a ParseSess,
16     mods: Vec<ModItem>,
17 }
18
19 impl<'a> CfgIfVisitor<'a> {
20     pub(crate) fn new(parse_sess: &'a ParseSess) -> CfgIfVisitor<'a> {
21         CfgIfVisitor {
22             mods: vec![],
23             parse_sess,
24         }
25     }
26
27     pub(crate) fn mods(self) -> Vec<ModItem> {
28         self.mods
29     }
30 }
31
32 impl<'a, 'ast: 'a> Visitor<'ast> for CfgIfVisitor<'a> {
33     fn visit_mac_call(&mut self, mac: &'ast ast::MacCall) {
34         match self.visit_mac_inner(mac) {
35             Ok(()) => (),
36             Err(e) => debug!("{}", e),
37         }
38     }
39 }
40
41 impl<'a, 'ast: 'a> CfgIfVisitor<'a> {
42     fn visit_mac_inner(&mut self, mac: &'ast ast::MacCall) -> Result<(), &'static str> {
43         // Support both:
44         // ```
45         // extern crate cfg_if;
46         // cfg_if::cfg_if! {..}
47         // ```
48         // And:
49         // ```
50         // #[macro_use]
51         // extern crate cfg_if;
52         // cfg_if! {..}
53         // ```
54         match mac.path.segments.first() {
55             Some(first_segment) => {
56                 if first_segment.ident.name != Symbol::intern("cfg_if") {
57                     return Err("Expected cfg_if");
58                 }
59             }
60             None => {
61                 return Err("Expected cfg_if");
62             }
63         };
64
65         let items = parse_cfg_if(self.parse_sess, mac)?;
66         self.mods
67             .append(&mut items.into_iter().map(|item| ModItem { item }).collect());
68
69         Ok(())
70     }
71 }
72
73 /// Extracts `path = "foo.rs"` from attributes.
74 #[derive(Default)]
75 pub(crate) struct PathVisitor {
76     /// A list of path defined in attributes.
77     paths: Vec<String>,
78 }
79
80 impl PathVisitor {
81     pub(crate) fn paths(self) -> Vec<String> {
82         self.paths
83     }
84 }
85
86 impl<'ast> MetaVisitor<'ast> for PathVisitor {
87     fn visit_meta_name_value(
88         &mut self,
89         meta_item: &'ast ast::MetaItem,
90         lit: &'ast ast::MetaItemLit,
91     ) {
92         if meta_item.has_name(Symbol::intern("path")) && lit.kind.is_str() {
93             self.paths.push(meta_item_lit_to_str(lit));
94         }
95     }
96 }
97
98 #[cfg(not(windows))]
99 fn meta_item_lit_to_str(lit: &ast::MetaItemLit) -> String {
100     match lit.kind {
101         ast::LitKind::Str(symbol, ..) => symbol.to_string(),
102         _ => unreachable!(),
103     }
104 }
105
106 #[cfg(windows)]
107 fn meta_item_lit_to_str(lit: &ast::MetaItemLit) -> String {
108     match lit.kind {
109         ast::LitKind::Str(symbol, ..) => symbol.as_str().replace("/", "\\"),
110         _ => unreachable!(),
111     }
112 }