rustfmt_nightly/modules/
visitor.rs

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