diff --git a/crates/hir/src/semantics.rs b/crates/hir/src/semantics.rs index e53d126928..e4b9f479e8 100644 --- a/crates/hir/src/semantics.rs +++ b/crates/hir/src/semantics.rs @@ -562,6 +562,8 @@ impl<'db> SemanticsImpl<'db> { // Note this return type is deliberate as [`find_nodes_at_offset_with_descend`] wants to stop // traversing the inner iterator when it finds a node. + // The outer iterator is over the tokens descendants + // The inner iterator is the ancestors of a descendant fn descend_node_at_offset( &self, node: &SyntaxNode, @@ -570,8 +572,16 @@ impl<'db> SemanticsImpl<'db> { // Handle macro token cases node.token_at_offset(offset) .map(move |token| self.descend_into_macros(token)) - .map(|it| it.into_iter().map(move |it| self.token_ancestors_with_macros(it))) - .flatten() + .map(|descendants| { + descendants.into_iter().map(move |it| self.token_ancestors_with_macros(it)) + }) + // re-order the tokens from token_at_offset by returning the ancestors with the smaller first nodes first + // See algo::ancestors_at_offset, which uses the same approach + .kmerge_by(|left, right| { + left.clone() + .map(|node| node.text_range().len()) + .lt(right.clone().map(|node| node.text_range().len())) + }) } fn original_range(&self, node: &SyntaxNode) -> FileRange { @@ -589,11 +599,14 @@ impl<'db> SemanticsImpl<'db> { fn token_ancestors_with_macros( &self, token: SyntaxToken, - ) -> impl Iterator + '_ { + ) -> impl Iterator + Clone + '_ { token.parent().into_iter().flat_map(move |parent| self.ancestors_with_macros(parent)) } - fn ancestors_with_macros(&self, node: SyntaxNode) -> impl Iterator + '_ { + fn ancestors_with_macros( + &self, + node: SyntaxNode, + ) -> impl Iterator + Clone + '_ { let node = self.find_file(node); node.ancestors_with_macros(self.db.upcast()).map(|it| it.value) } diff --git a/crates/hir_expand/src/lib.rs b/crates/hir_expand/src/lib.rs index 871cccb830..b666cf8dda 100644 --- a/crates/hir_expand/src/lib.rs +++ b/crates/hir_expand/src/lib.rs @@ -525,7 +525,7 @@ impl InFile { pub fn ancestors_with_macros( self, db: &dyn db::AstDatabase, - ) -> impl Iterator> + '_ { + ) -> impl Iterator> + Clone + '_ { iter::successors(Some(self), move |node| match node.value.parent() { Some(parent) => Some(node.with_value(parent)), None => {