1
1
//! File symbol extraction.
2
2
3
+ use base_db:: FileRange ;
3
4
use hir_def:: {
4
- AdtId , AssocItemId , DefWithBodyId , HasModule , ImplId , MacroId , ModuleDefId , ModuleId , TraitId ,
5
+ src:: HasSource , AdtId , AssocItemId , DefWithBodyId , HasModule , ImplId , Lookup , MacroId ,
6
+ ModuleDefId , ModuleId , TraitId ,
5
7
} ;
8
+ use hir_expand:: { HirFileId , InFile } ;
6
9
use hir_ty:: db:: HirDatabase ;
7
- use syntax:: SmolStr ;
10
+ use syntax:: { ast :: HasName , AstNode , SmolStr , SyntaxNode , SyntaxNodePtr } ;
8
11
9
- use crate :: { Module , ModuleDef } ;
12
+ use crate :: { Module , ModuleDef , Semantics } ;
10
13
11
14
/// The actual data that is stored in the index. It should be as compact as
12
15
/// possible.
@@ -15,6 +18,45 @@ pub struct FileSymbol {
15
18
// even though name can be derived from the def, we store it for efficiency
16
19
pub name : SmolStr ,
17
20
pub def : ModuleDef ,
21
+ pub loc : DeclarationLocation ,
22
+ pub container_name : Option < SmolStr > ,
23
+ }
24
+
25
+ #[ derive( Debug , Clone , PartialEq , Eq , Hash ) ]
26
+ pub struct DeclarationLocation {
27
+ /// The file id for both the `ptr` and `name_ptr`.
28
+ pub hir_file_id : HirFileId ,
29
+ /// This points to the whole syntax node of the declaration.
30
+ pub ptr : SyntaxNodePtr ,
31
+ /// This points to the [`syntax::ast::Name`] identifier of the declaration.
32
+ pub name_ptr : SyntaxNodePtr ,
33
+ }
34
+
35
+ impl DeclarationLocation {
36
+ pub fn syntax < DB : HirDatabase > ( & self , sema : & Semantics < ' _ , DB > ) -> SyntaxNode {
37
+ let root = sema. parse_or_expand ( self . hir_file_id ) ;
38
+ self . ptr . to_node ( & root)
39
+ }
40
+
41
+ pub fn original_range ( & self , db : & dyn HirDatabase ) -> FileRange {
42
+ let node = resolve_node ( db, self . hir_file_id , & self . ptr ) ;
43
+ node. as_ref ( ) . original_file_range ( db. upcast ( ) )
44
+ }
45
+
46
+ pub fn original_name_range ( & self , db : & dyn HirDatabase ) -> Option < FileRange > {
47
+ let node = resolve_node ( db, self . hir_file_id , & self . name_ptr ) ;
48
+ node. as_ref ( ) . original_file_range_opt ( db. upcast ( ) )
49
+ }
50
+ }
51
+
52
+ fn resolve_node (
53
+ db : & dyn HirDatabase ,
54
+ file_id : HirFileId ,
55
+ ptr : & SyntaxNodePtr ,
56
+ ) -> InFile < SyntaxNode > {
57
+ let root = db. parse_or_expand ( file_id) ;
58
+ let node = ptr. to_node ( & root) ;
59
+ InFile :: new ( file_id, node)
18
60
}
19
61
20
62
/// Represents an outstanding module that the symbol collector must collect symbols from.
@@ -193,17 +235,52 @@ impl<'a> SymbolCollector<'a> {
193
235
}
194
236
}
195
237
196
- fn push_decl ( & mut self , id : impl Into < ModuleDefId > ) {
197
- let def = ModuleDef :: from ( id. into ( ) ) ;
198
- if let Some ( name) = def. name ( self . db ) {
199
- self . symbols . push ( FileSymbol { name : name. to_smol_str ( ) , def } ) ;
200
- }
238
+ fn push_decl < L > ( & mut self , id : L )
239
+ where
240
+ L : Lookup + Into < ModuleDefId > ,
241
+ <L as Lookup >:: Data : HasSource ,
242
+ <<L as Lookup >:: Data as HasSource >:: Value : HasName ,
243
+ {
244
+ self . push_file_symbol ( |s| {
245
+ let loc = id. lookup ( s. db . upcast ( ) ) ;
246
+ let source = loc. source ( s. db . upcast ( ) ) ;
247
+ let name_node = source. value . name ( ) ?;
248
+ Some ( FileSymbol {
249
+ name : name_node. text ( ) . into ( ) ,
250
+ def : ModuleDef :: from ( id. into ( ) ) ,
251
+ container_name : s. current_container_name . clone ( ) ,
252
+ loc : DeclarationLocation {
253
+ hir_file_id : source. file_id ,
254
+ ptr : SyntaxNodePtr :: new ( source. value . syntax ( ) ) ,
255
+ name_ptr : SyntaxNodePtr :: new ( name_node. syntax ( ) ) ,
256
+ } ,
257
+ } )
258
+ } )
201
259
}
202
260
203
261
fn push_module ( & mut self , module_id : ModuleId ) {
204
- let def = Module :: from ( module_id) ;
205
- if let Some ( name) = def. name ( self . db ) {
206
- self . symbols . push ( FileSymbol { name : name. to_smol_str ( ) , def : ModuleDef :: Module ( def) } ) ;
262
+ self . push_file_symbol ( |s| {
263
+ let def_map = module_id. def_map ( s. db . upcast ( ) ) ;
264
+ let module_data = & def_map[ module_id. local_id ] ;
265
+ let declaration = module_data. origin . declaration ( ) ?;
266
+ let module = declaration. to_node ( s. db . upcast ( ) ) ;
267
+ let name_node = module. name ( ) ?;
268
+ Some ( FileSymbol {
269
+ name : name_node. text ( ) . into ( ) ,
270
+ def : ModuleDef :: Module ( module_id. into ( ) ) ,
271
+ container_name : s. current_container_name . clone ( ) ,
272
+ loc : DeclarationLocation {
273
+ hir_file_id : declaration. file_id ,
274
+ ptr : SyntaxNodePtr :: new ( module. syntax ( ) ) ,
275
+ name_ptr : SyntaxNodePtr :: new ( name_node. syntax ( ) ) ,
276
+ } ,
277
+ } )
278
+ } )
279
+ }
280
+
281
+ fn push_file_symbol ( & mut self , f : impl FnOnce ( & Self ) -> Option < FileSymbol > ) {
282
+ if let Some ( file_symbol) = f ( self ) {
283
+ self . symbols . push ( file_symbol) ;
207
284
}
208
285
}
209
286
}
0 commit comments