]> git.lizzy.rs Git - rust.git/commitdiff
Let `macro_use` bypass module scope
authoruHOOCCOOHu <hooccooh1896@gmail.com>
Thu, 5 Sep 2019 03:35:13 +0000 (11:35 +0800)
committeruHOOCCOOHu <hooccooh1896@gmail.com>
Thu, 5 Sep 2019 03:46:00 +0000 (11:46 +0800)
crates/ra_hir/src/nameres/collector.rs
crates/ra_hir/src/nameres/tests/macros.rs

index dbd68723673f8267f653392cdbf8383db32df16e..5d1c42926568fd663ade182e87b76375cbcf76d8 100644 (file)
@@ -166,6 +166,33 @@ fn define_macro(
         self.global_macro_scope.insert(name, macro_id);
     }
 
+    /// Import macros from `#[macro_use] extern crate`.
+    ///
+    /// They are non-scoped, and will only be inserted into mutable `global_macro_scope`.
+    fn import_macros_from_extern_crate(&mut self, import: &raw::ImportData) {
+        log::debug!(
+            "importing macros from extern crate: {:?} ({:?})",
+            import,
+            self.def_map.edition,
+        );
+
+        let res = self.def_map.resolve_name_in_extern_prelude(
+            &import
+                .path
+                .as_ident()
+                .expect("extern crate should have been desugared to one-element path"),
+        );
+
+        if let Some(ModuleDef::Module(m)) = res.take_types() {
+            tested_by!(macro_rules_from_other_crates_are_visible_with_macro_use);
+
+            let item_map = self.db.crate_def_map(m.krate);
+            for (name, &macro_id) in &item_map.exported_macros {
+                self.global_macro_scope.insert(name.clone(), macro_id);
+            }
+        }
+    }
+
     fn resolve_imports(&mut self) -> ReachedFixedPoint {
         let mut imports = std::mem::replace(&mut self.unresolved_imports, Vec::new());
         let mut resolved = Vec::new();
@@ -299,21 +326,6 @@ fn record_resolved_import(
                         }
                     }
 
-                    // `#[macro_use] extern crate` glob imports all macros exported,
-                    // ignoring their scopes
-                    if import.is_extern_crate && import.is_macro_use {
-                        if let Some(ModuleDef::Module(m)) =
-                            def.a().and_then(|item| item.take_types())
-                        {
-                            tested_by!(macro_rules_from_other_crates_are_visible_with_macro_use);
-
-                            let item_map = self.db.crate_def_map(m.krate);
-                            for (name, &macro_id) in &item_map.exported_macros {
-                                self.define_macro(module_id, name.clone(), macro_id, false);
-                            }
-                        }
-                    }
-
                     let resolution = match def {
                         Either::A(item) => {
                             Either::A(Resolution { def: item, import: Some(import_id) })
@@ -513,11 +525,17 @@ fn collect(&mut self, items: &[raw::RawItem]) {
         for item in items {
             match *item {
                 raw::RawItem::Module(m) => self.collect_module(&self.raw_items[m]),
-                raw::RawItem::Import(import) => self.def_collector.unresolved_imports.push((
-                    self.module_id,
-                    import,
-                    self.raw_items[import].clone(),
-                )),
+                raw::RawItem::Import(import_id) => {
+                    let import = self.raw_items[import_id].clone();
+                    // This should be processed eagerly instead of deferred to resolving.
+                    // Otherwise, since it will only mutate `global_macro_scope`
+                    // without `update` names in `mod`s, unresolved macros cannot be expanded.
+                    if import.is_extern_crate && import.is_macro_use {
+                        self.def_collector.import_macros_from_extern_crate(&import);
+                    }
+
+                    self.def_collector.unresolved_imports.push((self.module_id, import_id, import));
+                }
                 raw::RawItem::Def(def) => self.define_def(&self.raw_items[def]),
                 raw::RawItem::Macro(mac) => self.collect_macro(&self.raw_items[mac]),
             }
index cfddf3029942c38988e2a27e53ff2f9efd4ba503..ff762ee300287371a6e0065956def541c7d74f5c 100644 (file)
@@ -147,25 +147,31 @@ fn macro_rules_from_other_crates_are_visible_with_macro_use() {
         #[macro_use]
         extern crate foo;
 
-        structs!(Foo, Bar)
+        structs!(Foo);
+        structs_priv!(Bar);
+        structs_not_exported!(MacroNotResolved1);
+        crates::structs!(MacroNotResolved2);
 
         mod bar;
 
         //- /bar.rs
-        use crate::*;
+        structs!(Baz);
+        crates::structs!(MacroNotResolved3);
 
         //- /lib.rs
         #[macro_export]
         macro_rules! structs {
-            ($($i:ident),*) => {
-                $(struct $i { field: u32 } )*
-            }
+            ($i:ident) => { struct $i; }
+        }
+
+        macro_rules! structs_not_exported {
+            ($i:ident) => { struct $i; }
         }
 
         mod priv_mod {
             #[macro_export]
-            macro_rules! baz {
-                () => {};
+            macro_rules! structs_priv {
+                ($i:ident) => { struct $i; }
             }
         }
         ",
@@ -179,16 +185,9 @@ macro_rules! baz {
    ⋮Bar: t v
    ⋮Foo: t v
    ⋮bar: t
-   ⋮baz: m
    ⋮foo: t
-   ⋮structs: m
    ⋮
    ⋮crate::bar
-   ⋮Bar: t v
-   ⋮Foo: t v
-   ⋮bar: t
-   ⋮baz: m
-   ⋮foo: t
-   ⋮structs: m
+   ⋮Baz: t v
     "###);
 }