fix: make `goto_type_definition` multi-token mapping aware
use ide_db::{base_db::Upcast, helpers::pick_best_token, RootDatabase};
-use syntax::{ast, match_ast, AstNode, SyntaxKind::*, SyntaxToken, T};
+use syntax::{ast, match_ast, AstNode, SyntaxKind::*, SyntaxToken, TextRange, T};
use crate::{display::TryToNav, FilePosition, NavigationTarget, RangeInfo};
@@ -27,9 +27,22 @@ pub(crate) fn goto_type_definition(
kind if kind.is_trivia() => 0,
_ => 1,
})?;
- let token: SyntaxToken = sema.descend_into_macros_single(token);
- let (ty, node) = sema.token_ancestors_with_macros(token).find_map(|node| {
+ let mut res = Vec::new();
+ let mut push = |def: hir::ModuleDef| {
+ if let Some(nav) = def.try_to_nav(db) {
+ if !res.contains(&nav) {
+ res.push(nav);
+ }
+ }
+ };
+
+ // TODO this became pretty baroque after refactoring for `descend_into_macros(_many)`
+ let range = sema
+ .descend_into_macros(token)
+ .iter()
+ .filter_map(|token| {
+ let ty_range = sema.token_ancestors_with_macros(token.clone()).find_map(|node| {
let ty = match_ast! {
match node {
ast::Expr(it) => sema.type_of_expr(&it)?.original,
@@ -51,18 +64,13 @@ pub(crate) fn goto_type_definition(
}
};
- Some((ty, node))
- })?;
-
- let mut res = Vec::new();
- let mut push = |def: hir::ModuleDef| {
- if let Some(nav) = def.try_to_nav(db) {
- if !res.contains(&nav) {
- res.push(nav);
- }
- }
- };
-
+ let range = node.text_range();
+ Some((ty, range.start(), range.end()))
+ });
+ ty_range
+ })
+ .inspect(|(ty, _range_start, _range_end)| {
+ // collect from each `ty` into the `res` result vec
let ty = ty.strip_references();
ty.walk(db, |t| {
if let Some(adt) = t.as_adt() {
@@ -75,8 +83,14 @@ pub(crate) fn goto_type_definition(
push(trait_.into());
}
});
+ }) // reduce all ranges into a single umbrella span (TODO fishy?)
+ .map(|(_, range_start, range_end)| (range_start, range_end))
+ .reduce(|(start_acc, end_acc), (start_cur, end_cur)| {
+ (start_acc.min(start_cur), end_acc.max(end_cur))
+ })
+ .map(|(range_start, range_end)| TextRange::new(range_start, range_end))?; // TODO easy to miss `?` bail
- Some(RangeInfo::new(node.text_range(), res))
+ Some(RangeInfo::new(range, res))
}
#[cfg(test)]
