Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/hir_expand/src/lib.rs')
-rw-r--r--crates/hir_expand/src/lib.rs58
1 files changed, 28 insertions, 30 deletions
diff --git a/crates/hir_expand/src/lib.rs b/crates/hir_expand/src/lib.rs
index 51899ca2f6..580a1225cb 100644
--- a/crates/hir_expand/src/lib.rs
+++ b/crates/hir_expand/src/lib.rs
@@ -705,24 +705,14 @@ fn ascend_node_border_tokens(
) -> Option<InFile<(SyntaxToken, SyntaxToken)>> {
let expansion = file_id.expansion_info(db)?;
- // the input node has only one token ?
- let first = skip_trivia_token(node.first_token()?, Direction::Next)?;
- let last = skip_trivia_token(node.last_token()?, Direction::Prev)?;
- let is_single_token = first == last;
-
- node.descendants().find_map(|it| {
- let first = skip_trivia_token(it.first_token()?, Direction::Next)?;
- let first = ascend_call_token(db, &expansion, InFile::new(file_id, first))?;
-
- let last = skip_trivia_token(it.last_token()?, Direction::Prev)?;
- let last = ascend_call_token(db, &expansion, InFile::new(file_id, last))?;
-
- if (!is_single_token && first == last) || (first.file_id != last.file_id) {
- return None;
- }
-
- Some(InFile::new(first.file_id, (first.value, last.value)))
- })
+ let first_token = |node: &SyntaxNode| skip_trivia_token(node.first_token()?, Direction::Next);
+ let last_token = |node: &SyntaxNode| skip_trivia_token(node.last_token()?, Direction::Prev);
+
+ let first = first_token(node)?;
+ let last = last_token(node)?;
+ let first = ascend_call_token(db, &expansion, InFile::new(file_id, first))?;
+ let last = ascend_call_token(db, &expansion, InFile::new(file_id, last))?;
+ (first.file_id == last.file_id).then(|| InFile::new(first.file_id, (first.value, last.value)))
}
fn ascend_call_token(
@@ -758,20 +748,28 @@ impl<N: AstNode> InFile<N> {
}
pub fn original_ast_node(self, db: &dyn db::AstDatabase) -> Option<InFile<N>> {
- match ascend_node_border_tokens(db, self.syntax()) {
- Some(InFile { file_id, value: (first, last) }) => {
- let original_file = file_id.original_file(db);
- if file_id != original_file.into() {
- let range = first.text_range().cover(last.text_range());
- tracing::error!("Failed mapping up more for {:?}", range);
- return None;
- }
- let anc = algo::least_common_ancestor(&first.parent()?, &last.parent()?)?;
- Some(InFile::new(file_id, anc.ancestors().find_map(N::cast)?))
+ // This kind of upmapping can only be achieved in attribute expanded files,
+ // as we don't have node inputs otherwise and therefor can't find an `N` node in the input
+ if !self.file_id.is_macro() {
+ return Some(self);
+ } else if !self.file_id.is_attr_macro(db) {
+ return None;
+ }
+
+ if let Some(InFile { file_id, value: (first, last) }) =
+ ascend_node_border_tokens(db, self.syntax())
+ {
+ if file_id.is_macro() {
+ let range = first.text_range().cover(last.text_range());
+ tracing::error!("Failed mapping out of macro file for {:?}", range);
+ return None;
}
- _ if !self.file_id.is_macro() => Some(self),
- _ => None,
+ // FIXME: This heuristic is brittle and with the right macro may select completely unrelated nodes
+ let anc = algo::least_common_ancestor(&first.parent()?, &last.parent()?)?;
+ let value = anc.ancestors().find_map(N::cast)?;
+ return Some(InFile::new(file_id, value));
}
+ None
}
pub fn syntax(&self) -> InFile<&SyntaxNode> {