summaryrefslogtreecommitdiffstats
path: root/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/tools/rust-analyzer/crates/hir-expand/src/lib.rs25
1 files changed, 25 insertions, 0 deletions
diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs b/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs
index fc128102f..a5b499fe8 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs
@@ -811,6 +811,31 @@ impl<'a> InFile<&'a SyntaxNode> {
_ => None,
}
}
+
+ pub fn original_syntax_node(self, db: &dyn db::AstDatabase) -> Option<InFile<SyntaxNode>> {
+ // 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.map(Clone::clone));
+ } 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)
+ {
+ 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;
+ }
+ // 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 kind = self.value.kind();
+ let value = anc.ancestors().find(|it| it.kind() == kind)?;
+ return Some(InFile::new(file_id, value));
+ }
+ None
+ }
}
impl InFile<SyntaxToken> {