1
1
//! This module provides `StaticIndex` which is used for powering
2
2
//! read-only code browsers and emitting LSIF
3
3
4
+ use arrayvec:: ArrayVec ;
4
5
use hir:: { Crate , HirFileIdExt , Module , Semantics , db:: HirDatabase } ;
5
6
use ide_db:: {
6
7
FileId , FileRange , FxHashMap , FxHashSet , RootDatabase ,
7
8
base_db:: { RootQueryDb , SourceDatabase , VfsPath } ,
8
- defs:: Definition ,
9
+ defs:: { Definition , IdentClass } ,
9
10
documentation:: Documentation ,
10
11
famous_defs:: FamousDefs ,
11
- helpers:: get_definition,
12
12
} ;
13
13
use span:: Edition ;
14
- use syntax:: { AstNode , SyntaxKind :: * , SyntaxNode , T , TextRange } ;
14
+ use syntax:: { AstNode , SyntaxKind :: * , SyntaxNode , SyntaxToken , T , TextRange } ;
15
15
16
16
use crate :: navigation_target:: UpmappingResult ;
17
17
use crate :: {
@@ -126,6 +126,22 @@ fn documentation_for_definition(
126
126
)
127
127
}
128
128
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
+
129
145
pub enum VendoredLibrariesConfig < ' a > {
130
146
Included { workspace_root : & ' a VfsPath } ,
131
147
Excluded ,
@@ -257,11 +273,14 @@ impl StaticIndex<'_> {
257
273
for token in tokens {
258
274
let range = token. text_range ( ) ;
259
275
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
+ }
262
282
None => continue ,
263
283
} ;
264
- add_token ( def, range, & node) ;
265
284
}
266
285
self . files . push ( result) ;
267
286
}
@@ -308,7 +327,7 @@ impl StaticIndex<'_> {
308
327
#[ cfg( test) ]
309
328
mod tests {
310
329
use crate :: { StaticIndex , fixture} ;
311
- use ide_db:: { FileRange , FxHashSet , base_db:: VfsPath } ;
330
+ use ide_db:: { FileRange , FxHashMap , FxHashSet , base_db:: VfsPath } ;
312
331
use syntax:: TextSize ;
313
332
314
333
use super :: VendoredLibrariesConfig ;
@@ -363,6 +382,71 @@ mod tests {
363
382
}
364
383
}
365
384
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
+
366
450
#[ test]
367
451
fn struct_and_enum ( ) {
368
452
check_all_ranges (
@@ -382,6 +466,17 @@ struct Foo;
382
466
//^^^
383
467
enum E { X(Foo) }
384
468
//^ ^
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
+ // ^^^
385
480
"# ,
386
481
VendoredLibrariesConfig :: Included {
387
482
workspace_root : & VfsPath :: new_virtual_path ( "/workspace" . to_owned ( ) ) ,
0 commit comments