@@ -9,6 +9,7 @@ use hir_def::{
99 ModuleDefId , ModuleId , TraitId ,
1010 db:: DefDatabase ,
1111 item_scope:: { ImportId , ImportOrExternCrate , ImportOrGlob } ,
12+ nameres:: crate_def_map,
1213 per_ns:: Item ,
1314 src:: { HasChildSource , HasSource } ,
1415 visibility:: { Visibility , VisibilityExplicitness } ,
@@ -20,9 +21,12 @@ use hir_ty::{
2021} ;
2122use intern:: Symbol ;
2223use rustc_hash:: FxHashMap ;
23- use syntax:: { AstNode , AstPtr , SyntaxNode , SyntaxNodePtr , ToSmolStr , ast:: HasName } ;
24+ use syntax:: {
25+ AstNode , AstPtr , SyntaxNode , SyntaxNodePtr , ToSmolStr ,
26+ ast:: { HasModuleItem , HasName } ,
27+ } ;
2428
25- use crate :: { HasCrate , Module , ModuleDef , Semantics } ;
29+ use crate :: { Crate , HasCrate , Module , ModuleDef , Semantics } ;
2630
2731/// The actual data that is stored in the index. It should be as compact as
2832/// possible.
@@ -57,6 +61,70 @@ impl DeclarationLocation {
5761 }
5862}
5963
64+ impl < ' db > FileSymbol < ' db > {
65+ /// Create a `FileSymbol` representing a crate's root module.
66+ /// This is used for crate search queries like `::` or `::foo`.
67+ pub fn for_crate_root ( db : & ' db dyn HirDatabase , krate : Crate ) -> Option < FileSymbol < ' db > > {
68+ let display_name = krate. display_name ( db) ?;
69+ let crate_name = display_name. crate_name ( ) ;
70+ let root_module = krate. root_module ( db) ;
71+ let def_map = crate_def_map ( db, krate. into ( ) ) ;
72+ let module_data = & def_map[ root_module. into ( ) ] ;
73+
74+ // Get the definition source (the source file for crate roots)
75+ let definition = module_data. origin . definition_source ( db) ;
76+ let hir_file_id = definition. file_id ;
77+
78+ // For a crate root, the "declaration" is the source file itself
79+ // We use the entire file's syntax node as the location
80+ let syntax_node = definition. value . node ( ) ;
81+ let ptr = SyntaxNodePtr :: new ( & syntax_node) ;
82+
83+ // For the name, we need to create a synthetic name pointer.
84+ // We'll use the first token of the file as a placeholder since crate roots
85+ // don't have an explicit name in the source.
86+ // We create a name_ptr pointing to the start of the file.
87+ let name_ptr = match & definition. value {
88+ crate :: ModuleSource :: SourceFile ( sf) => {
89+ // Try to find the first item with a name as a reasonable location for focus
90+ // This is a bit of a hack but works for navigation purposes
91+ let first_item: Option < syntax:: ast:: Item > = sf. items ( ) . next ( ) ;
92+ if let Some ( item) = first_item {
93+ if let Some ( name) = item. syntax ( ) . children ( ) . find_map ( syntax:: ast:: Name :: cast) {
94+ AstPtr :: new ( & name) . wrap_left ( )
95+ } else {
96+ // No name found, try to use a NameRef instead
97+ if let Some ( name_ref) =
98+ item. syntax ( ) . descendants ( ) . find_map ( syntax:: ast:: NameRef :: cast)
99+ {
100+ AstPtr :: new ( & name_ref) . wrap_right ( )
101+ } else {
102+ return None ;
103+ }
104+ }
105+ } else {
106+ return None ;
107+ }
108+ }
109+ _ => return None ,
110+ } ;
111+
112+ let loc = DeclarationLocation { hir_file_id, ptr, name_ptr } ;
113+
114+ Some ( FileSymbol {
115+ name : Symbol :: intern ( crate_name. as_str ( ) ) ,
116+ def : ModuleDef :: Module ( root_module) ,
117+ loc,
118+ container_name : None ,
119+ is_alias : false ,
120+ is_assoc : false ,
121+ is_import : false ,
122+ do_not_complete : Complete :: Yes ,
123+ _marker : PhantomData ,
124+ } )
125+ }
126+ }
127+
60128/// Represents an outstanding module that the symbol collector must collect symbols from.
61129#[ derive( Debug ) ]
62130struct SymbolCollectorWork {
0 commit comments