@@ -35,8 +35,8 @@ use crate::{
35
35
derive_macro_as_call_id,
36
36
item_scope:: { ImportType , PerNsGlobImports } ,
37
37
item_tree:: {
38
- self , Fields , FileItemTreeId , ImportKind , ItemTree , ItemTreeId , ItemTreeNode , MacroCall ,
39
- MacroDef , MacroRules , Mod , ModItem , ModKind , TreeId ,
38
+ self , ExternCrate , Fields , FileItemTreeId , ImportKind , ItemTree , ItemTreeId , ItemTreeNode ,
39
+ MacroCall , MacroDef , MacroRules , Mod , ModItem , ModKind , TreeId ,
40
40
} ,
41
41
macro_call_as_call_id, macro_id_to_def_id,
42
42
nameres:: {
@@ -712,41 +712,28 @@ impl DefCollector<'_> {
712
712
) ;
713
713
}
714
714
715
- /// Import macros from `#[macro_use] extern crate`.
716
- // FIXME: Support `#[macro_rules(macro_name, ...)]`.
717
- fn import_macros_from_extern_crate (
718
- & mut self ,
719
- current_module_id : LocalModuleId ,
720
- extern_crate : & item_tree:: ExternCrate ,
721
- ) {
722
- tracing:: debug!(
723
- "importing macros from extern crate: {:?} ({:?})" ,
724
- extern_crate,
725
- self . def_map. edition,
726
- ) ;
727
-
728
- if let Some ( m) = self . resolve_extern_crate ( & extern_crate. name ) {
729
- if m == self . def_map . module_id ( current_module_id) {
730
- cov_mark:: hit!( ignore_macro_use_extern_crate_self) ;
731
- return ;
732
- }
733
-
734
- cov_mark:: hit!( macro_rules_from_other_crates_are_visible_with_macro_use) ;
735
- self . import_all_macros_exported ( m. krate ) ;
736
- }
737
- }
738
-
739
- /// Import all exported macros from another crate
715
+ /// Import exported macros from another crate. `names`, if `Some(_)`, specifies the name of
716
+ /// macros to be imported. Otherwise this method imports all exported macros.
740
717
///
741
718
/// Exported macros are just all macros in the root module scope.
742
719
/// Note that it contains not only all `#[macro_export]` macros, but also all aliases
743
720
/// created by `use` in the root module, ignoring the visibility of `use`.
744
- fn import_all_macros_exported ( & mut self , krate : CrateId ) {
721
+ fn import_macros_from_extern_crate ( & mut self , krate : CrateId , names : Option < Vec < Name > > ) {
745
722
let def_map = self . db . crate_def_map ( krate) ;
746
- for ( name, def) in def_map[ def_map. root ] . scope . macros ( ) {
747
- // `#[macro_use]` brings macros into macro_use prelude. Yes, even non-`macro_rules!`
748
- // macros.
749
- self . def_map . macro_use_prelude . insert ( name. clone ( ) , def) ;
723
+ // `#[macro_use]` brings macros into macro_use prelude. Yes, even non-`macro_rules!`
724
+ // macros.
725
+ let root_scope = & def_map[ def_map. root ] . scope ;
726
+ if let Some ( names) = names {
727
+ for name in names {
728
+ // FIXME: Report diagnostic on 404.
729
+ if let Some ( def) = root_scope. get ( & name) . take_macros ( ) {
730
+ self . def_map . macro_use_prelude . insert ( name, def) ;
731
+ }
732
+ }
733
+ } else {
734
+ for ( name, def) in root_scope. macros ( ) {
735
+ self . def_map . macro_use_prelude . insert ( name. clone ( ) , def) ;
736
+ }
750
737
}
751
738
}
752
739
@@ -1537,7 +1524,7 @@ impl ModCollector<'_, '_> {
1537
1524
if let Some ( prelude_module) = self . def_collector . def_map . prelude {
1538
1525
if prelude_module. krate != krate && is_crate_root {
1539
1526
cov_mark:: hit!( prelude_is_macro_use) ;
1540
- self . def_collector . import_all_macros_exported ( prelude_module. krate ) ;
1527
+ self . def_collector . import_macros_from_extern_crate ( prelude_module. krate , None ) ;
1541
1528
}
1542
1529
}
1543
1530
@@ -1547,21 +1534,10 @@ impl ModCollector<'_, '_> {
1547
1534
//
1548
1535
// If we're not at the crate root, `macro_use`d extern crates are an error so let's just
1549
1536
// ignore them.
1550
- // FIXME: Support `#[macro_rules(macro_name, ...)]`.
1551
1537
if is_crate_root {
1552
1538
for & item in items {
1553
- let ModItem :: ExternCrate ( id) = item else { continue ; } ;
1554
- let attrs = self . item_tree . attrs ( self . def_collector . db , krate, item. into ( ) ) ;
1555
- if attrs. cfg ( ) . map_or ( true , |cfg| self . is_cfg_enabled ( & cfg) ) {
1556
- let import = & self . item_tree [ id] ;
1557
- let attrs = self . item_tree . attrs (
1558
- self . def_collector . db ,
1559
- krate,
1560
- ModItem :: from ( id) . into ( ) ,
1561
- ) ;
1562
- if attrs. by_key ( "macro_use" ) . exists ( ) {
1563
- self . def_collector . import_macros_from_extern_crate ( self . module_id , import) ;
1564
- }
1539
+ if let ModItem :: ExternCrate ( id) = item {
1540
+ self . process_macro_use_extern_crate ( id) ;
1565
1541
}
1566
1542
}
1567
1543
}
@@ -1788,6 +1764,52 @@ impl ModCollector<'_, '_> {
1788
1764
}
1789
1765
}
1790
1766
1767
+ fn process_macro_use_extern_crate ( & mut self , extern_crate : FileItemTreeId < ExternCrate > ) {
1768
+ let db = self . def_collector . db ;
1769
+ let attrs = self . item_tree . attrs (
1770
+ db,
1771
+ self . def_collector . def_map . krate ,
1772
+ ModItem :: from ( extern_crate) . into ( ) ,
1773
+ ) ;
1774
+ if let Some ( cfg) = attrs. cfg ( ) {
1775
+ if !self . is_cfg_enabled ( & cfg) {
1776
+ return ;
1777
+ }
1778
+ }
1779
+
1780
+ let target_crate =
1781
+ match self . def_collector . resolve_extern_crate ( & self . item_tree [ extern_crate] . name ) {
1782
+ Some ( m) => {
1783
+ if m == self . def_collector . def_map . module_id ( self . module_id ) {
1784
+ cov_mark:: hit!( ignore_macro_use_extern_crate_self) ;
1785
+ return ;
1786
+ }
1787
+ m. krate
1788
+ }
1789
+ None => return ,
1790
+ } ;
1791
+
1792
+ cov_mark:: hit!( macro_rules_from_other_crates_are_visible_with_macro_use) ;
1793
+
1794
+ let mut single_imports = Vec :: new ( ) ;
1795
+ let hygiene = Hygiene :: new_unhygienic ( ) ;
1796
+ for attr in attrs. by_key ( "macro_use" ) . attrs ( ) {
1797
+ let Some ( paths) = attr. parse_path_comma_token_tree ( db. upcast ( ) , & hygiene) else {
1798
+ // `#[macro_use]` (without any paths) found, forget collected names and just import
1799
+ // all visible macros.
1800
+ self . def_collector . import_macros_from_extern_crate ( target_crate, None ) ;
1801
+ return ;
1802
+ } ;
1803
+ for path in paths {
1804
+ if let Some ( name) = path. as_ident ( ) {
1805
+ single_imports. push ( name. clone ( ) ) ;
1806
+ }
1807
+ }
1808
+ }
1809
+
1810
+ self . def_collector . import_macros_from_extern_crate ( target_crate, Some ( single_imports) ) ;
1811
+ }
1812
+
1791
1813
fn collect_module ( & mut self , module_id : FileItemTreeId < Mod > , attrs : & Attrs ) {
1792
1814
let path_attr = attrs. by_key ( "path" ) . string_value ( ) ;
1793
1815
let is_macro_use = attrs. by_key ( "macro_use" ) . exists ( ) ;
0 commit comments