Skip to content

Commit 58660de

Browse files
committed
fix: Do reference search on all downmapped tokens with the same kind only
1 parent 7ce3ca5 commit 58660de

File tree

3 files changed

+100
-59
lines changed

3 files changed

+100
-59
lines changed

crates/hir/src/semantics.rs

Lines changed: 50 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,16 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> {
208208
self.imp.descend_into_macros(token)
209209
}
210210

211+
/// Descend the token into macrocalls to all its mapped counterparts.
212+
///
213+
/// Returns the original non descended token if none of the mapped counterparts have the same syntax kind.
214+
pub fn descend_into_macros_with_same_kind(
215+
&self,
216+
token: SyntaxToken,
217+
) -> SmallVec<[SyntaxToken; 1]> {
218+
self.imp.descend_into_macros_with_same_kind(token)
219+
}
220+
211221
/// Maps a node down by mapping its first and last token down.
212222
pub fn descend_node_into_attributes<N: AstNode>(&self, node: N) -> SmallVec<[N; 1]> {
213223
self.imp.descend_node_into_attributes(node)
@@ -599,25 +609,19 @@ impl<'db> SemanticsImpl<'db> {
599609
};
600610

601611
if first == last {
602-
self.descend_into_macros_impl(
603-
first,
604-
&mut |InFile { value, .. }| {
605-
if let Some(node) = value.ancestors().find_map(N::cast) {
606-
res.push(node)
607-
}
608-
},
609-
false,
610-
);
612+
self.descend_into_macros_impl(first, &mut |InFile { value, .. }| {
613+
if let Some(node) = value.ancestors().find_map(N::cast) {
614+
res.push(node)
615+
}
616+
false
617+
});
611618
} else {
612619
// Descend first and last token, then zip them to look for the node they belong to
613620
let mut scratch: SmallVec<[_; 1]> = smallvec![];
614-
self.descend_into_macros_impl(
615-
first,
616-
&mut |token| {
617-
scratch.push(token);
618-
},
619-
false,
620-
);
621+
self.descend_into_macros_impl(first, &mut |token| {
622+
scratch.push(token);
623+
false
624+
});
621625

622626
let mut scratch = scratch.into_iter();
623627
self.descend_into_macros_impl(
@@ -638,30 +642,50 @@ impl<'db> SemanticsImpl<'db> {
638642
}
639643
}
640644
}
645+
false
641646
},
642-
false,
643647
);
644648
}
645649
res
646650
}
647651

648652
fn descend_into_macros(&self, token: SyntaxToken) -> SmallVec<[SyntaxToken; 1]> {
649653
let mut res = smallvec![];
650-
self.descend_into_macros_impl(token, &mut |InFile { value, .. }| res.push(value), false);
654+
self.descend_into_macros_impl(token, &mut |InFile { value, .. }| {
655+
res.push(value);
656+
false
657+
});
658+
res
659+
}
660+
661+
fn descend_into_macros_with_same_kind(&self, token: SyntaxToken) -> SmallVec<[SyntaxToken; 1]> {
662+
let kind = token.kind();
663+
let mut res = smallvec![];
664+
self.descend_into_macros_impl(token.clone(), &mut |InFile { value, .. }| {
665+
if value.kind() == kind {
666+
res.push(value);
667+
}
668+
false
669+
});
670+
if res.is_empty() {
671+
res.push(token);
672+
}
651673
res
652674
}
653675

654676
fn descend_into_macros_single(&self, token: SyntaxToken) -> SyntaxToken {
655677
let mut res = token.clone();
656-
self.descend_into_macros_impl(token, &mut |InFile { value, .. }| res = value, true);
678+
self.descend_into_macros_impl(token, &mut |InFile { value, .. }| {
679+
res = value;
680+
true
681+
});
657682
res
658683
}
659684

660685
fn descend_into_macros_impl(
661686
&self,
662687
token: SyntaxToken,
663-
f: &mut dyn FnMut(InFile<SyntaxToken>),
664-
single: bool,
688+
f: &mut dyn FnMut(InFile<SyntaxToken>) -> bool,
665689
) {
666690
let _p = profile::span("descend_into_macros");
667691
let parent = match token.parent() {
@@ -688,16 +712,11 @@ impl<'db> SemanticsImpl<'db> {
688712
self.cache(value, file_id);
689713
}
690714

691-
let mut mapped_tokens =
692-
expansion_info.map_token_down(self.db.upcast(), item, token)?;
693-
715+
let mapped_tokens = expansion_info.map_token_down(self.db.upcast(), item, token)?;
694716
let len = stack.len();
717+
695718
// requeue the tokens we got from mapping our current token down
696-
if single {
697-
stack.extend(mapped_tokens.next());
698-
} else {
699-
stack.extend(mapped_tokens);
700-
}
719+
stack.extend(mapped_tokens);
701720
// if the length changed we have found a mapping for the token
702721
(stack.len() != len).then(|| ())
703722
};
@@ -787,8 +806,8 @@ impl<'db> SemanticsImpl<'db> {
787806
})()
788807
.is_none();
789808

790-
if was_not_remapped {
791-
f(token)
809+
if was_not_remapped && f(token) {
810+
break;
792811
}
793812
}
794813
}

crates/ide/src/references.rs

Lines changed: 45 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,9 @@ use rustc_hash::FxHashMap;
2020
use syntax::{
2121
algo::find_node_at_offset,
2222
ast::{self, HasName},
23-
match_ast, AstNode, SyntaxNode, TextRange, TextSize, T,
23+
match_ast, AstNode,
24+
SyntaxKind::*,
25+
SyntaxNode, TextRange, TextSize, T,
2426
};
2527

2628
use crate::{FilePosition, NavigationTarget, TryToNav};
@@ -104,7 +106,7 @@ pub(crate) fn find_all_refs(
104106
}
105107
None => {
106108
let search = make_searcher(false);
107-
Some(find_defs(sema, &syntax, position.offset).into_iter().map(search).collect())
109+
Some(find_defs(sema, &syntax, position.offset)?.into_iter().map(search).collect())
108110
}
109111
}
110112
}
@@ -113,31 +115,47 @@ pub(crate) fn find_defs<'a>(
113115
sema: &'a Semantics<RootDatabase>,
114116
syntax: &SyntaxNode,
115117
offset: TextSize,
116-
) -> impl Iterator<Item = Definition> + 'a {
117-
sema.find_nodes_at_offset_with_descend(syntax, offset).filter_map(move |name_like| {
118-
let def = match name_like {
119-
ast::NameLike::NameRef(name_ref) => match NameRefClass::classify(sema, &name_ref)? {
120-
NameRefClass::Definition(def) => def,
121-
NameRefClass::FieldShorthand { local_ref, field_ref: _ } => {
122-
Definition::Local(local_ref)
123-
}
124-
},
125-
ast::NameLike::Name(name) => match NameClass::classify(sema, &name)? {
126-
NameClass::Definition(it) | NameClass::ConstReference(it) => it,
127-
NameClass::PatFieldShorthand { local_def, field_ref: _ } => {
128-
Definition::Local(local_def)
129-
}
130-
},
131-
ast::NameLike::Lifetime(lifetime) => NameRefClass::classify_lifetime(sema, &lifetime)
132-
.and_then(|class| match class {
133-
NameRefClass::Definition(it) => Some(it),
134-
_ => None,
135-
})
136-
.or_else(|| {
137-
NameClass::classify_lifetime(sema, &lifetime).and_then(NameClass::defined)
138-
})?,
139-
};
140-
Some(def)
118+
) -> Option<impl Iterator<Item = Definition> + 'a> {
119+
let token = syntax.token_at_offset(offset).find(|t| {
120+
matches!(
121+
t.kind(),
122+
IDENT | INT_NUMBER | LIFETIME_IDENT | T![self] | T![super] | T![crate] | T![Self]
123+
)
124+
});
125+
token.map(|token| {
126+
sema.descend_into_macros_with_same_kind(token)
127+
.into_iter()
128+
.filter_map(|it| ast::NameLike::cast(it.parent()?))
129+
.filter_map(move |name_like| {
130+
let def = match name_like {
131+
ast::NameLike::NameRef(name_ref) => {
132+
match NameRefClass::classify(sema, &name_ref)? {
133+
NameRefClass::Definition(def) => def,
134+
NameRefClass::FieldShorthand { local_ref, field_ref: _ } => {
135+
Definition::Local(local_ref)
136+
}
137+
}
138+
}
139+
ast::NameLike::Name(name) => match NameClass::classify(sema, &name)? {
140+
NameClass::Definition(it) | NameClass::ConstReference(it) => it,
141+
NameClass::PatFieldShorthand { local_def, field_ref: _ } => {
142+
Definition::Local(local_def)
143+
}
144+
},
145+
ast::NameLike::Lifetime(lifetime) => {
146+
NameRefClass::classify_lifetime(sema, &lifetime)
147+
.and_then(|class| match class {
148+
NameRefClass::Definition(it) => Some(it),
149+
_ => None,
150+
})
151+
.or_else(|| {
152+
NameClass::classify_lifetime(sema, &lifetime)
153+
.and_then(NameClass::defined)
154+
})?
155+
}
156+
};
157+
Some(def)
158+
})
141159
})
142160
}
143161

crates/ide/src/runnables.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -226,7 +226,11 @@ fn find_related_tests(
226226
search_scope: Option<SearchScope>,
227227
tests: &mut FxHashSet<Runnable>,
228228
) {
229-
let defs = references::find_defs(sema, syntax, position.offset);
229+
// FIXME: why is this using references::find_defs, this should use ide_db::search
230+
let defs = match references::find_defs(sema, syntax, position.offset) {
231+
Some(defs) => defs,
232+
None => return,
233+
};
230234
for def in defs {
231235
let defs = def
232236
.usages(sema)

0 commit comments

Comments
 (0)