@@ -30,8 +30,8 @@ use crate::{
3030 db:: DefDatabase ,
3131 item_scope:: { ImportId , ImportOrExternCrate , ImportType , PerNsGlobImports } ,
3232 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 ,
3535 } ,
3636 macro_call_as_call_id, macro_call_as_call_id_with_eager,
3737 nameres:: {
@@ -93,6 +93,7 @@ pub(super) fn collect_defs(db: &dyn DefDatabase, def_map: DefMap, tree_id: TreeI
9393 proc_macros,
9494 from_glob_import : Default :: default ( ) ,
9595 skip_attrs : Default :: default ( ) ,
96+ unresolved_extern_crates : Default :: default ( ) ,
9697 is_proc_macro : krate. is_proc_macro ,
9798 } ;
9899 if tree_id. is_block ( ) {
@@ -128,7 +129,6 @@ impl PartialResolvedImport {
128129#[ derive( Clone , Debug , Eq , PartialEq ) ]
129130enum ImportSource {
130131 Use { use_tree : Idx < ast:: UseTree > , id : UseId , is_prelude : bool , kind : ImportKind } ,
131- ExternCrate { id : ExternCrateId } ,
132132}
133133
134134#[ derive( Debug , Eq , PartialEq ) ]
@@ -158,21 +158,6 @@ impl Import {
158158 } ) ;
159159 } ) ;
160160 }
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- }
176161}
177162
178163#[ derive( Debug , Eq , PartialEq ) ]
@@ -218,11 +203,16 @@ enum MacroDirectiveKind {
218203struct DefCollector < ' a > {
219204 db : & ' a dyn DefDatabase ,
220205 def_map : DefMap ,
206+ // The dependencies of the current crate, including optional deps like `test`.
221207 deps : FxHashMap < Name , Dependency > ,
222208 glob_imports : FxHashMap < LocalModuleId , Vec < ( LocalModuleId , Visibility , UseId ) > > ,
223209 unresolved_imports : Vec < ImportDirective > ,
224210 indeterminate_imports : Vec < ( ImportDirective , PerNs ) > ,
225211 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 > ,
226216 mod_dirs : FxHashMap < LocalModuleId , ModDir > ,
227217 cfg_options : & ' a CfgOptions ,
228218 /// List of procedural macros defined by this crate. This is read from the dynamic library
@@ -310,6 +300,7 @@ impl DefCollector<'_> {
310300 }
311301
312302 for ( name, dep) in & self . deps {
303+ // Add all
313304 if dep. is_prelude ( ) {
314305 // This is a bit confusing but the gist is that `no_core` and `no_std` remove the
315306 // sysroot dependence on `core` and `std` respectively. Our `CrateGraph` is eagerly
@@ -329,6 +320,7 @@ impl DefCollector<'_> {
329320 if skip {
330321 continue ;
331322 }
323+
332324 crate_data
333325 . extern_prelude
334326 . insert ( name. clone ( ) , ( CrateRootModuleId { krate : dep. crate_id } , None ) ) ;
@@ -789,23 +781,6 @@ impl DefCollector<'_> {
789781 . entered ( ) ;
790782 tracing:: debug!( "resolving import: {:?} ({:?})" , import, self . def_map. data. edition) ;
791783 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- }
809784 ImportSource :: Use { .. } => {
810785 let res = self . def_map . resolve_path_fp_with_macro (
811786 self . db ,
@@ -837,15 +812,6 @@ impl DefCollector<'_> {
837812 }
838813 }
839814
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-
849815 fn record_resolved_import ( & mut self , directive : & ImportDirective ) {
850816 let _p = tracing:: info_span!( "record_resolved_import" ) . entered ( ) ;
851817
@@ -858,8 +824,7 @@ impl DefCollector<'_> {
858824 . unwrap_or ( Visibility :: Public ) ;
859825
860826 match import. source {
861- ImportSource :: ExternCrate { .. }
862- | ImportSource :: Use { kind : ImportKind :: Plain | ImportKind :: TypeOnly , .. } => {
827+ ImportSource :: Use { kind : ImportKind :: Plain | ImportKind :: TypeOnly , .. } => {
863828 let name = match & import. alias {
864829 Some ( ImportAlias :: Alias ( name) ) => Some ( name) ,
865830 Some ( ImportAlias :: Underscore ) => None ,
@@ -873,22 +838,6 @@ impl DefCollector<'_> {
873838 } ;
874839
875840 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- }
892841 ImportSource :: Use { kind, id, use_tree, .. } => {
893842 if kind == ImportKind :: TypeOnly {
894843 def. values = None ;
@@ -1560,45 +1509,21 @@ impl DefCollector<'_> {
15601509 }
15611510
15621511 // 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-
15851512 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 ;
16011520 }
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+ ) ) ;
16021527 }
16031528
16041529 self . def_map
@@ -1623,7 +1548,8 @@ impl ModCollector<'_, '_> {
16231548
16241549 fn collect ( & mut self , items : & [ ModItem ] , container : ItemContainerId ) {
16251550 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 ( ) ;
16271553
16281554 // Note: don't assert that inserted value is fresh: it's simply not true
16291555 // for macros.
@@ -1632,10 +1558,7 @@ impl ModCollector<'_, '_> {
16321558 // Prelude module is always considered to be `#[macro_use]`.
16331559 if let Some ( ( prelude_module, _use) ) = self . def_collector . def_map . prelude {
16341560 // 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 {
16391562 cov_mark:: hit!( prelude_is_macro_use) ;
16401563 self . def_collector . import_macros_from_extern_crate (
16411564 prelude_module. krate ,
@@ -1709,26 +1632,73 @@ impl ModCollector<'_, '_> {
17091632 id : ItemTreeId :: new ( self . tree_id , item_tree_id) ,
17101633 }
17111634 . 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+ ) ,
17171700 ) ;
17181701 }
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- } )
17321702 }
17331703 ModItem :: ExternBlock ( block) => self . collect (
17341704 & self . item_tree [ block] . children ,
@@ -1939,27 +1909,15 @@ impl ModCollector<'_, '_> {
19391909
19401910 fn process_macro_use_extern_crate < ' a > (
19411911 & mut self ,
1942- extern_crate : FileItemTreeId < ExternCrate > ,
19431912 extern_crate_id : ExternCrateId ,
19441913 macro_use_attrs : impl Iterator < Item = & ' a Attr > ,
1914+ target_crate : CrateId ,
19451915 ) {
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-
19581916 cov_mark:: hit!( macro_rules_from_other_crates_are_visible_with_macro_use) ;
1959-
19601917 let mut single_imports = Vec :: new ( ) ;
19611918 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 {
19631921 // `#[macro_use]` (without any paths) found, forget collected names and just import
19641922 // all visible macros.
19651923 self . def_collector . import_macros_from_extern_crate (
@@ -2523,6 +2481,7 @@ mod tests {
25232481 from_glob_import : Default :: default ( ) ,
25242482 skip_attrs : Default :: default ( ) ,
25252483 is_proc_macro : false ,
2484+ unresolved_extern_crates : Default :: default ( ) ,
25262485 } ;
25272486 collector. seed_with_top_level ( ) ;
25282487 collector. collect ( ) ;
0 commit comments