]> git.proxmox.com Git - rustc.git/blobdiff - src/tools/rustfmt/src/modules/visitor.rs
Update upstream source from tag 'upstream/1.52.1+dfsg1'
[rustc.git] / src / tools / rustfmt / src / modules / visitor.rs
diff --git a/src/tools/rustfmt/src/modules/visitor.rs b/src/tools/rustfmt/src/modules/visitor.rs
new file mode 100644 (file)
index 0000000..d5acf3f
--- /dev/null
@@ -0,0 +1,108 @@
+use rustc_ast::ast;
+use rustc_ast::visit::Visitor;
+use rustc_span::Symbol;
+
+use crate::attr::MetaVisitor;
+use crate::syntux::parser::Parser;
+use crate::syntux::session::ParseSess;
+
+pub(crate) struct ModItem {
+    pub(crate) item: ast::Item,
+}
+
+/// Traverse `cfg_if!` macro and fetch modules.
+pub(crate) struct CfgIfVisitor<'a> {
+    parse_sess: &'a ParseSess,
+    mods: Vec<ModItem>,
+}
+
+impl<'a> CfgIfVisitor<'a> {
+    pub(crate) fn new(parse_sess: &'a ParseSess) -> CfgIfVisitor<'a> {
+        CfgIfVisitor {
+            mods: vec![],
+            parse_sess,
+        }
+    }
+
+    pub(crate) fn mods(self) -> Vec<ModItem> {
+        self.mods
+    }
+}
+
+impl<'a, 'ast: 'a> Visitor<'ast> for CfgIfVisitor<'a> {
+    fn visit_mac_call(&mut self, mac: &'ast ast::MacCall) {
+        match self.visit_mac_inner(mac) {
+            Ok(()) => (),
+            Err(e) => debug!("{}", e),
+        }
+    }
+}
+
+impl<'a, 'ast: 'a> CfgIfVisitor<'a> {
+    fn visit_mac_inner(&mut self, mac: &'ast ast::MacCall) -> Result<(), &'static str> {
+        // Support both:
+        // ```
+        // extern crate cfg_if;
+        // cfg_if::cfg_if! {..}
+        // ```
+        // And:
+        // ```
+        // #[macro_use]
+        // extern crate cfg_if;
+        // cfg_if! {..}
+        // ```
+        match mac.path.segments.first() {
+            Some(first_segment) => {
+                if first_segment.ident.name != Symbol::intern("cfg_if") {
+                    return Err("Expected cfg_if");
+                }
+            }
+            None => {
+                return Err("Expected cfg_if");
+            }
+        };
+
+        let items = Parser::parse_cfg_if(self.parse_sess, mac)?;
+        self.mods
+            .append(&mut items.into_iter().map(|item| ModItem { item }).collect());
+
+        Ok(())
+    }
+}
+
+/// Extracts `path = "foo.rs"` from attributes.
+#[derive(Default)]
+pub(crate) struct PathVisitor {
+    /// A list of path defined in attributes.
+    paths: Vec<String>,
+}
+
+impl PathVisitor {
+    pub(crate) fn paths(self) -> Vec<String> {
+        self.paths
+    }
+}
+
+impl<'ast> MetaVisitor<'ast> for PathVisitor {
+    fn visit_meta_name_value(&mut self, meta_item: &'ast ast::MetaItem, lit: &'ast ast::Lit) {
+        if meta_item.has_name(Symbol::intern("path")) && lit.kind.is_str() {
+            self.paths.push(lit_to_str(lit));
+        }
+    }
+}
+
+#[cfg(not(windows))]
+fn lit_to_str(lit: &ast::Lit) -> String {
+    match lit.kind {
+        ast::LitKind::Str(symbol, ..) => symbol.to_string(),
+        _ => unreachable!(),
+    }
+}
+
+#[cfg(windows)]
+fn lit_to_str(lit: &ast::Lit) -> String {
+    match lit.kind {
+        ast::LitKind::Str(symbol, ..) => symbol.as_str().replace("/", "\\"),
+        _ => unreachable!(),
+    }
+}