@@ -30,8 +30,8 @@ use crate::{
30
30
db:: DefDatabase ,
31
31
item_scope:: { ImportId , ImportOrExternCrate , ImportType , PerNsGlobImports } ,
32
32
item_tree:: {
33
- self , AttrOwner , ExternCrate , FieldsShape , FileItemTreeId , ImportKind , ItemTree ,
34
- ItemTreeId , ItemTreeNode , Macro2 , MacroCall , MacroRules , Mod , ModItem , ModKind , TreeId ,
33
+ self , AttrOwner , FieldsShape , FileItemTreeId , ImportKind , ItemTree , ItemTreeId ,
34
+ ItemTreeNode , Macro2 , MacroCall , MacroRules , Mod , ModItem , ModKind , TreeId ,
35
35
} ,
36
36
macro_call_as_call_id, macro_call_as_call_id_with_eager,
37
37
nameres:: {
@@ -93,6 +93,7 @@ pub(super) fn collect_defs(db: &dyn DefDatabase, def_map: DefMap, tree_id: TreeI
93
93
proc_macros,
94
94
from_glob_import : Default :: default ( ) ,
95
95
skip_attrs : Default :: default ( ) ,
96
+ unresolved_extern_crates : Default :: default ( ) ,
96
97
is_proc_macro : krate. is_proc_macro ,
97
98
} ;
98
99
if tree_id. is_block ( ) {
@@ -128,7 +129,6 @@ impl PartialResolvedImport {
128
129
#[ derive( Clone , Debug , Eq , PartialEq ) ]
129
130
enum ImportSource {
130
131
Use { use_tree : Idx < ast:: UseTree > , id : UseId , is_prelude : bool , kind : ImportKind } ,
131
- ExternCrate { id : ExternCrateId } ,
132
132
}
133
133
134
134
#[ derive( Debug , Eq , PartialEq ) ]
@@ -158,21 +158,6 @@ impl Import {
158
158
} ) ;
159
159
} ) ;
160
160
}
161
-
162
- fn from_extern_crate (
163
- tree : & ItemTree ,
164
- item_tree_id : ItemTreeId < item_tree:: ExternCrate > ,
165
- id : ExternCrateId ,
166
- ) -> Self {
167
- let it = & tree[ item_tree_id. value ] ;
168
- let visibility = & tree[ it. visibility ] ;
169
- Self {
170
- path : ModPath :: from_segments ( PathKind :: Plain , iter:: once ( it. name . clone ( ) ) ) ,
171
- alias : it. alias . clone ( ) ,
172
- visibility : visibility. clone ( ) ,
173
- source : ImportSource :: ExternCrate { id } ,
174
- }
175
- }
176
161
}
177
162
178
163
#[ derive( Debug , Eq , PartialEq ) ]
@@ -218,11 +203,16 @@ enum MacroDirectiveKind {
218
203
struct DefCollector < ' a > {
219
204
db : & ' a dyn DefDatabase ,
220
205
def_map : DefMap ,
206
+ // The dependencies of the current crate, including optional deps like `test`.
221
207
deps : FxHashMap < Name , Dependency > ,
222
208
glob_imports : FxHashMap < LocalModuleId , Vec < ( LocalModuleId , Visibility , UseId ) > > ,
223
209
unresolved_imports : Vec < ImportDirective > ,
224
210
indeterminate_imports : Vec < ( ImportDirective , PerNs ) > ,
225
211
unresolved_macros : Vec < MacroDirective > ,
212
+ // We'd like to avoid emitting a diagnostics avalanche when some `extern crate` doesn't
213
+ // resolve. When we emit diagnostics for unresolved imports, we only do so if the import
214
+ // doesn't start with an unresolved crate's name.
215
+ unresolved_extern_crates : FxHashSet < Name > ,
226
216
mod_dirs : FxHashMap < LocalModuleId , ModDir > ,
227
217
cfg_options : & ' a CfgOptions ,
228
218
/// List of procedural macros defined by this crate. This is read from the dynamic library
@@ -310,6 +300,7 @@ impl DefCollector<'_> {
310
300
}
311
301
312
302
for ( name, dep) in & self . deps {
303
+ // Add all
313
304
if dep. is_prelude ( ) {
314
305
// This is a bit confusing but the gist is that `no_core` and `no_std` remove the
315
306
// sysroot dependence on `core` and `std` respectively. Our `CrateGraph` is eagerly
@@ -329,6 +320,7 @@ impl DefCollector<'_> {
329
320
if skip {
330
321
continue ;
331
322
}
323
+
332
324
crate_data
333
325
. extern_prelude
334
326
. insert ( name. clone ( ) , ( CrateRootModuleId { krate : dep. crate_id } , None ) ) ;
@@ -789,23 +781,6 @@ impl DefCollector<'_> {
789
781
. entered ( ) ;
790
782
tracing:: debug!( "resolving import: {:?} ({:?})" , import, self . def_map. data. edition) ;
791
783
match import. source {
792
- ImportSource :: ExternCrate { .. } => {
793
- let name = import
794
- . path
795
- . as_ident ( )
796
- . expect ( "extern crate should have been desugared to one-element path" ) ;
797
-
798
- let res = self . resolve_extern_crate ( name) ;
799
-
800
- match res {
801
- Some ( res) => PartialResolvedImport :: Resolved ( PerNs :: types (
802
- res. into ( ) ,
803
- Visibility :: Public ,
804
- None ,
805
- ) ) ,
806
- None => PartialResolvedImport :: Unresolved ,
807
- }
808
- }
809
784
ImportSource :: Use { .. } => {
810
785
let res = self . def_map . resolve_path_fp_with_macro (
811
786
self . db ,
@@ -837,15 +812,6 @@ impl DefCollector<'_> {
837
812
}
838
813
}
839
814
840
- fn resolve_extern_crate ( & self , name : & Name ) -> Option < CrateRootModuleId > {
841
- if * name == sym:: self_. clone ( ) {
842
- cov_mark:: hit!( extern_crate_self_as) ;
843
- Some ( self . def_map . crate_root ( ) )
844
- } else {
845
- self . deps . get ( name) . map ( |dep| CrateRootModuleId { krate : dep. crate_id } )
846
- }
847
- }
848
-
849
815
fn record_resolved_import ( & mut self , directive : & ImportDirective ) {
850
816
let _p = tracing:: info_span!( "record_resolved_import" ) . entered ( ) ;
851
817
@@ -858,8 +824,7 @@ impl DefCollector<'_> {
858
824
. unwrap_or ( Visibility :: Public ) ;
859
825
860
826
match import. source {
861
- ImportSource :: ExternCrate { .. }
862
- | ImportSource :: Use { kind : ImportKind :: Plain | ImportKind :: TypeOnly , .. } => {
827
+ ImportSource :: Use { kind : ImportKind :: Plain | ImportKind :: TypeOnly , .. } => {
863
828
let name = match & import. alias {
864
829
Some ( ImportAlias :: Alias ( name) ) => Some ( name) ,
865
830
Some ( ImportAlias :: Underscore ) => None ,
@@ -873,22 +838,6 @@ impl DefCollector<'_> {
873
838
} ;
874
839
875
840
let imp = match import. source {
876
- // extern crates in the crate root are special-cased to insert entries into the extern prelude: rust-lang/rust#54658
877
- ImportSource :: ExternCrate { id, .. } => {
878
- if self . def_map . block . is_none ( ) && module_id == DefMap :: ROOT {
879
- if let ( Some ( ModuleDefId :: ModuleId ( def) ) , Some ( name) ) =
880
- ( def. take_types ( ) , name)
881
- {
882
- if let Ok ( def) = def. try_into ( ) {
883
- Arc :: get_mut ( & mut self . def_map . data )
884
- . unwrap ( )
885
- . extern_prelude
886
- . insert ( name. clone ( ) , ( def, Some ( id) ) ) ;
887
- }
888
- }
889
- }
890
- ImportType :: ExternCrate ( id)
891
- }
892
841
ImportSource :: Use { kind, id, use_tree, .. } => {
893
842
if kind == ImportKind :: TypeOnly {
894
843
def. values = None ;
@@ -1560,45 +1509,21 @@ impl DefCollector<'_> {
1560
1509
}
1561
1510
1562
1511
// Emit diagnostics for all remaining unresolved imports.
1563
-
1564
- // We'd like to avoid emitting a diagnostics avalanche when some `extern crate` doesn't
1565
- // resolve. We first emit diagnostics for unresolved extern crates and collect the missing
1566
- // crate names. Then we emit diagnostics for unresolved imports, but only if the import
1567
- // doesn't start with an unresolved crate's name. Due to renaming and reexports, this is a
1568
- // heuristic, but it works in practice.
1569
- let mut diagnosed_extern_crates = FxHashSet :: default ( ) ;
1570
- for directive in & self . unresolved_imports {
1571
- if let ImportSource :: ExternCrate { id } = directive. import . source {
1572
- let item_tree_id = id. lookup ( self . db ) . id ;
1573
- let item_tree = item_tree_id. item_tree ( self . db ) ;
1574
- let extern_crate = & item_tree[ item_tree_id. value ] ;
1575
-
1576
- diagnosed_extern_crates. insert ( extern_crate. name . clone ( ) ) ;
1577
-
1578
- self . def_map . diagnostics . push ( DefDiagnostic :: unresolved_extern_crate (
1579
- directive. module_id ,
1580
- InFile :: new ( item_tree_id. file_id ( ) , extern_crate. ast_id ) ,
1581
- ) ) ;
1582
- }
1583
- }
1584
-
1585
1512
for directive in & self . unresolved_imports {
1586
- if let ImportSource :: Use { use_tree, id, is_prelude : _, kind : _ } =
1587
- directive. import . source
1588
- {
1589
- if matches ! (
1590
- ( directive. import. path. segments( ) . first( ) , & directive. import. path. kind) ,
1591
- ( Some ( krate) , PathKind :: Plain | PathKind :: Abs ) if diagnosed_extern_crates. contains( krate)
1592
- ) {
1593
- continue ;
1594
- }
1595
- let item_tree_id = id. lookup ( self . db ) . id ;
1596
- self . def_map . diagnostics . push ( DefDiagnostic :: unresolved_import (
1597
- directive. module_id ,
1598
- item_tree_id,
1599
- use_tree,
1600
- ) ) ;
1513
+ let ImportSource :: Use { use_tree, id, is_prelude : _, kind : _ } =
1514
+ directive. import . source ;
1515
+ if matches ! (
1516
+ ( directive. import. path. segments( ) . first( ) , & directive. import. path. kind) ,
1517
+ ( Some ( krate) , PathKind :: Plain | PathKind :: Abs ) if self . unresolved_extern_crates. contains( krate)
1518
+ ) {
1519
+ continue ;
1601
1520
}
1521
+ let item_tree_id = id. lookup ( self . db ) . id ;
1522
+ self . def_map . diagnostics . push ( DefDiagnostic :: unresolved_import (
1523
+ directive. module_id ,
1524
+ item_tree_id,
1525
+ use_tree,
1526
+ ) ) ;
1602
1527
}
1603
1528
1604
1529
self . def_map
@@ -1623,7 +1548,8 @@ impl ModCollector<'_, '_> {
1623
1548
1624
1549
fn collect ( & mut self , items : & [ ModItem ] , container : ItemContainerId ) {
1625
1550
let krate = self . def_collector . def_map . krate ;
1626
- let is_crate_root = self . module_id == DefMap :: ROOT ;
1551
+ let is_crate_root =
1552
+ self . module_id == DefMap :: ROOT && self . def_collector . def_map . block . is_none ( ) ;
1627
1553
1628
1554
// Note: don't assert that inserted value is fresh: it's simply not true
1629
1555
// for macros.
@@ -1632,10 +1558,7 @@ impl ModCollector<'_, '_> {
1632
1558
// Prelude module is always considered to be `#[macro_use]`.
1633
1559
if let Some ( ( prelude_module, _use) ) = self . def_collector . def_map . prelude {
1634
1560
// Don't insert macros from the prelude into blocks, as they can be shadowed by other macros.
1635
- if prelude_module. krate != krate
1636
- && is_crate_root
1637
- && self . def_collector . def_map . block . is_none ( )
1638
- {
1561
+ if prelude_module. krate != krate && is_crate_root {
1639
1562
cov_mark:: hit!( prelude_is_macro_use) ;
1640
1563
self . def_collector . import_macros_from_extern_crate (
1641
1564
prelude_module. krate ,
@@ -1709,26 +1632,73 @@ impl ModCollector<'_, '_> {
1709
1632
id : ItemTreeId :: new ( self . tree_id , item_tree_id) ,
1710
1633
}
1711
1634
. intern ( db) ;
1712
- if is_crate_root {
1713
- self . process_macro_use_extern_crate (
1714
- item_tree_id,
1715
- id,
1716
- attrs. by_key ( & sym:: macro_use) . attrs ( ) ,
1635
+ def_map. modules [ self . module_id ] . scope . define_extern_crate_decl ( id) ;
1636
+
1637
+ let item_tree:: ExternCrate { name, visibility, alias, ast_id } =
1638
+ & self . item_tree [ item_tree_id] ;
1639
+
1640
+ let is_self = * name == sym:: self_;
1641
+ let resolved = if is_self {
1642
+ cov_mark:: hit!( extern_crate_self_as) ;
1643
+ Some ( def_map. crate_root ( ) )
1644
+ } else {
1645
+ self . def_collector
1646
+ . deps
1647
+ . get ( name)
1648
+ . map ( |dep| CrateRootModuleId { krate : dep. crate_id } )
1649
+ } ;
1650
+
1651
+ let name = match alias {
1652
+ Some ( ImportAlias :: Alias ( name) ) => Some ( name) ,
1653
+ Some ( ImportAlias :: Underscore ) => None ,
1654
+ None => Some ( name) ,
1655
+ } ;
1656
+
1657
+ if let Some ( resolved) = resolved {
1658
+ let vis = resolve_vis ( def_map, & self . item_tree [ * visibility] ) ;
1659
+
1660
+ if is_crate_root {
1661
+ // extern crates in the crate root are special-cased to insert entries into the extern prelude: rust-lang/rust#54658
1662
+ if let Some ( name) = name {
1663
+ Arc :: get_mut ( & mut def_map. data )
1664
+ . unwrap ( )
1665
+ . extern_prelude
1666
+ . insert ( name. clone ( ) , ( resolved, Some ( id) ) ) ;
1667
+ }
1668
+ // they also allow `#[macro_use]`
1669
+ if !is_self {
1670
+ self . process_macro_use_extern_crate (
1671
+ id,
1672
+ attrs. by_key ( & sym:: macro_use) . attrs ( ) ,
1673
+ resolved. krate ,
1674
+ ) ;
1675
+ }
1676
+ }
1677
+
1678
+ self . def_collector . update (
1679
+ module_id,
1680
+ & [ (
1681
+ name. cloned ( ) ,
1682
+ PerNs :: types (
1683
+ resolved. into ( ) ,
1684
+ vis,
1685
+ Some ( ImportOrExternCrate :: ExternCrate ( id) ) ,
1686
+ ) ,
1687
+ ) ] ,
1688
+ vis,
1689
+ Some ( ImportType :: ExternCrate ( id) ) ,
1690
+ ) ;
1691
+ } else {
1692
+ if let Some ( name) = name {
1693
+ self . def_collector . unresolved_extern_crates . insert ( name. clone ( ) ) ;
1694
+ }
1695
+ self . def_collector . def_map . diagnostics . push (
1696
+ DefDiagnostic :: unresolved_extern_crate (
1697
+ module_id,
1698
+ InFile :: new ( self . file_id ( ) , * ast_id) ,
1699
+ ) ,
1717
1700
) ;
1718
1701
}
1719
-
1720
- self . def_collector . def_map . modules [ self . module_id ]
1721
- . scope
1722
- . define_extern_crate_decl ( id) ;
1723
- self . def_collector . unresolved_imports . push ( ImportDirective {
1724
- module_id : self . module_id ,
1725
- import : Import :: from_extern_crate (
1726
- self . item_tree ,
1727
- ItemTreeId :: new ( self . tree_id , item_tree_id) ,
1728
- id,
1729
- ) ,
1730
- status : PartialResolvedImport :: Unresolved ,
1731
- } )
1732
1702
}
1733
1703
ModItem :: ExternBlock ( block) => self . collect (
1734
1704
& self . item_tree [ block] . children ,
@@ -1939,27 +1909,15 @@ impl ModCollector<'_, '_> {
1939
1909
1940
1910
fn process_macro_use_extern_crate < ' a > (
1941
1911
& mut self ,
1942
- extern_crate : FileItemTreeId < ExternCrate > ,
1943
1912
extern_crate_id : ExternCrateId ,
1944
1913
macro_use_attrs : impl Iterator < Item = & ' a Attr > ,
1914
+ target_crate : CrateId ,
1945
1915
) {
1946
- let db = self . def_collector . db ;
1947
-
1948
- let target_crate =
1949
- match self . def_collector . resolve_extern_crate ( & self . item_tree [ extern_crate] . name ) {
1950
- Some ( m) if m. krate == self . def_collector . def_map . krate => {
1951
- cov_mark:: hit!( ignore_macro_use_extern_crate_self) ;
1952
- return ;
1953
- }
1954
- Some ( m) => m. krate ,
1955
- None => return ,
1956
- } ;
1957
-
1958
1916
cov_mark:: hit!( macro_rules_from_other_crates_are_visible_with_macro_use) ;
1959
-
1960
1917
let mut single_imports = Vec :: new ( ) ;
1961
1918
for attr in macro_use_attrs {
1962
- let Some ( paths) = attr. parse_path_comma_token_tree ( db. upcast ( ) ) else {
1919
+ let Some ( paths) = attr. parse_path_comma_token_tree ( self . def_collector . db . upcast ( ) )
1920
+ else {
1963
1921
// `#[macro_use]` (without any paths) found, forget collected names and just import
1964
1922
// all visible macros.
1965
1923
self . def_collector . import_macros_from_extern_crate (
@@ -2523,6 +2481,7 @@ mod tests {
2523
2481
from_glob_import : Default :: default ( ) ,
2524
2482
skip_attrs : Default :: default ( ) ,
2525
2483
is_proc_macro : false ,
2484
+ unresolved_extern_crates : Default :: default ( ) ,
2526
2485
} ;
2527
2486
collector. seed_with_top_level ( ) ;
2528
2487
collector. collect ( ) ;
0 commit comments