Skip to content

Commit 8b6621a

Browse files
authored
Merge pull request #19515 from jrmuizel/multiple-definitions
fix: don't drop references with more than one definition.
2 parents afcb45e + e9d997e commit 8b6621a

File tree

1 file changed

+102
-7
lines changed

1 file changed

+102
-7
lines changed

crates/ide/src/static_index.rs

Lines changed: 102 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,17 @@
11
//! This module provides `StaticIndex` which is used for powering
22
//! read-only code browsers and emitting LSIF
33
4+
use arrayvec::ArrayVec;
45
use hir::{Crate, HirFileIdExt, Module, Semantics, db::HirDatabase};
56
use 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
};
1313
use span::Edition;
14-
use syntax::{AstNode, SyntaxKind::*, SyntaxNode, T, TextRange};
14+
use syntax::{AstNode, SyntaxKind::*, SyntaxNode, SyntaxToken, T, TextRange};
1515

1616
use crate::navigation_target::UpmappingResult;
1717
use 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+
129145
pub 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)]
309328
mod 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
//^^^
383467
enum 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

Comments
 (0)