11//! This module provides `StaticIndex` which is used for powering
22//! read-only code browsers and emitting LSIF
33
4+ use arrayvec:: ArrayVec ;
45use hir:: { Crate , HirFileIdExt , Module , Semantics , db:: HirDatabase } ;
56use ide_db:: {
67 FileId , FileRange , FxHashMap , FxHashSet , RootDatabase ,
78 base_db:: { RootQueryDb , SourceDatabase , VfsPath } ,
8- defs:: Definition ,
9+ defs:: { Definition , IdentClass } ,
910 documentation:: Documentation ,
1011 famous_defs:: FamousDefs ,
11- helpers:: get_definition,
1212} ;
1313use span:: Edition ;
14- use syntax:: { AstNode , SyntaxKind :: * , SyntaxNode , T , TextRange } ;
14+ use syntax:: { AstNode , SyntaxKind :: * , SyntaxNode , SyntaxToken , T , TextRange } ;
1515
1616use crate :: navigation_target:: UpmappingResult ;
1717use crate :: {
@@ -126,6 +126,22 @@ fn documentation_for_definition(
126126 )
127127}
128128
129+ // FIXME: This is a weird function
130+ fn get_definitions (
131+ sema : & Semantics < ' _ , RootDatabase > ,
132+ token : SyntaxToken ,
133+ ) -> Option < ArrayVec < Definition , 2 > > {
134+ for token in sema. descend_into_macros_exact ( token) {
135+ let def = IdentClass :: classify_token ( sema, & token) . map ( IdentClass :: definitions_no_ops) ;
136+ if let Some ( defs) = def {
137+ if !defs. is_empty ( ) {
138+ return Some ( defs) ;
139+ }
140+ }
141+ }
142+ None
143+ }
144+
129145pub enum VendoredLibrariesConfig < ' a > {
130146 Included { workspace_root : & ' a VfsPath } ,
131147 Excluded ,
@@ -257,11 +273,14 @@ impl StaticIndex<'_> {
257273 for token in tokens {
258274 let range = token. text_range ( ) ;
259275 let node = token. parent ( ) . unwrap ( ) ;
260- let def = match get_definition ( & sema, token. clone ( ) ) {
261- Some ( it) => it,
276+ match get_definitions ( & sema, token. clone ( ) ) {
277+ Some ( it) => {
278+ for i in it {
279+ add_token ( i, range, & node) ;
280+ }
281+ }
262282 None => continue ,
263283 } ;
264- add_token ( def, range, & node) ;
265284 }
266285 self . files . push ( result) ;
267286 }
@@ -308,7 +327,7 @@ impl StaticIndex<'_> {
308327#[ cfg( test) ]
309328mod tests {
310329 use crate :: { StaticIndex , fixture} ;
311- use ide_db:: { FileRange , FxHashSet , base_db:: VfsPath } ;
330+ use ide_db:: { FileRange , FxHashMap , FxHashSet , base_db:: VfsPath } ;
312331 use syntax:: TextSize ;
313332
314333 use super :: VendoredLibrariesConfig ;
@@ -363,6 +382,71 @@ mod tests {
363382 }
364383 }
365384
385+ #[ track_caller]
386+ fn check_references (
387+ #[ rust_analyzer:: rust_fixture] ra_fixture : & str ,
388+ vendored_libs_config : VendoredLibrariesConfig < ' _ > ,
389+ ) {
390+ let ( analysis, ranges) = fixture:: annotations_without_marker ( ra_fixture) ;
391+ let s = StaticIndex :: compute ( & analysis, vendored_libs_config) ;
392+ let mut range_set: FxHashMap < _ , i32 > = ranges. iter ( ) . map ( |it| ( it. 0 , 0 ) ) . collect ( ) ;
393+
394+ // Make sure that all references have at least one range. We use a HashMap instead of a
395+ // a HashSet so that we can have more than one reference at the same range.
396+ for ( _, t) in s. tokens . iter ( ) {
397+ for r in & t. references {
398+ if r. is_definition {
399+ continue ;
400+ }
401+ if r. range . range . start ( ) == TextSize :: from ( 0 ) {
402+ // ignore whole file range corresponding to module definition
403+ continue ;
404+ }
405+ match range_set. entry ( r. range ) {
406+ std:: collections:: hash_map:: Entry :: Occupied ( mut entry) => {
407+ let count = entry. get_mut ( ) ;
408+ * count += 1 ;
409+ }
410+ std:: collections:: hash_map:: Entry :: Vacant ( _) => {
411+ panic ! ( "additional reference {r:?}" ) ;
412+ }
413+ }
414+ }
415+ }
416+ for ( range, count) in range_set. iter ( ) {
417+ if * count == 0 {
418+ panic ! ( "unfound reference {range:?}" ) ;
419+ }
420+ }
421+ }
422+
423+ #[ test]
424+ fn field_initialization ( ) {
425+ check_references (
426+ r#"
427+ struct Point {
428+ x: f64,
429+ //^^^
430+ y: f64,
431+ //^^^
432+ }
433+ fn foo() {
434+ let x = 5.;
435+ let y = 10.;
436+ let mut p = Point { x, y };
437+ //^^^^^ ^ ^
438+ p.x = 9.;
439+ //^ ^
440+ p.y = 10.;
441+ //^ ^
442+ }
443+ "# ,
444+ VendoredLibrariesConfig :: Included {
445+ workspace_root : & VfsPath :: new_virtual_path ( "/workspace" . to_owned ( ) ) ,
446+ } ,
447+ ) ;
448+ }
449+
366450 #[ test]
367451 fn struct_and_enum ( ) {
368452 check_all_ranges (
@@ -382,6 +466,17 @@ struct Foo;
382466 //^^^
383467enum E { X(Foo) }
384468 //^ ^
469+ "# ,
470+ VendoredLibrariesConfig :: Included {
471+ workspace_root : & VfsPath :: new_virtual_path ( "/workspace" . to_owned ( ) ) ,
472+ } ,
473+ ) ;
474+
475+ check_references (
476+ r#"
477+ struct Foo;
478+ enum E { X(Foo) }
479+ // ^^^
385480"# ,
386481 VendoredLibrariesConfig :: Included {
387482 workspace_root : & VfsPath :: new_virtual_path ( "/workspace" . to_owned ( ) ) ,
0 commit comments