From ffdc740446585502bd179cb608a033dd74a41e39 Mon Sep 17 00:00:00 2001 From: Edwin Cheng Date: Wed, 26 Feb 2020 12:27:57 +0800 Subject: Add recursive support in original_range --- crates/ra_hir/src/semantics.rs | 51 ++++++++++++++++++++++++++++++------------ crates/ra_ide/src/hover.rs | 21 +++++++++++++++++ 2 files changed, 58 insertions(+), 14 deletions(-) diff --git a/crates/ra_hir/src/semantics.rs b/crates/ra_hir/src/semantics.rs index 9fedb7657..96bc791eb 100644 --- a/crates/ra_hir/src/semantics.rs +++ b/crates/ra_hir/src/semantics.rs @@ -7,7 +7,10 @@ use hir_def::{ DefWithBodyId, TraitId, }; use ra_db::{FileId, FileRange}; -use ra_syntax::{ast, match_ast, AstNode, SyntaxNode, SyntaxToken, TextRange, TextUnit}; +use ra_syntax::{ + algo::find_covering_element, ast, match_ast, AstNode, NodeOrToken, SyntaxElement, SyntaxNode, + SyntaxToken, TextRange, TextUnit, +}; use rustc_hash::{FxHashMap, FxHashSet}; use crate::{ @@ -333,10 +336,28 @@ impl<'a, DB: HirDatabase> SemanticsScope<'a, DB> { // FIXME: Change `HasSource` trait to work with `Semantics` and remove this? pub fn original_range(db: &impl HirDatabase, node: InFile<&SyntaxNode>) -> FileRange { - if let Some((range, Origin::Call)) = original_range_and_origin(db, node) { - return range; + let mut elem: InFile = node.map(|n| n.clone().into()); + + while let Some((range, Origin::Call)) = original_range_and_origin(db, elem.as_ref()) { + let original_file = range.file_id.original_file(db); + + if range.file_id == original_file.into() { + return FileRange { file_id: original_file, range: range.value }; + } + + // Fail to mapping up more, return the original file range instead + if range.file_id != elem.file_id { + if let Some(root) = db.parse_or_expand(range.file_id) { + elem = range.with_value(find_covering_element(&root, range.value)); + continue; + } + } + + log::error!("Fail to mapping up more for {:?}", range); + return FileRange { file_id: range.file_id.original_file(db), range: range.value }; } + // Fall back to whole macro call if let Some(expansion) = node.file_id.expansion_info(db) { if let Some(call_node) = expansion.call_node() { return FileRange { @@ -351,15 +372,22 @@ pub fn original_range(db: &impl HirDatabase, node: InFile<&SyntaxNode>) -> FileR fn original_range_and_origin( db: &impl HirDatabase, - node: InFile<&SyntaxNode>, -) -> Option<(FileRange, Origin)> { - let expansion = node.file_id.expansion_info(db)?; + elem: InFile<&SyntaxElement>, +) -> Option<(InFile, Origin)> { + let expansion = elem.file_id.expansion_info(db)?; + + let node = match elem.as_ref().value { + NodeOrToken::Node(it) => elem.with_value(it), + NodeOrToken::Token(it) => { + let (tt, origin) = expansion.map_token_up(elem.with_value(it))?; + return Some((tt.map(|it| it.text_range()), origin)); + } + }; // the input node has only one token ? let single = node.value.first_token()? == node.value.last_token()?; - // FIXME: We should handle recurside macro expansions - let (range, origin) = node.value.descendants().find_map(|it| { + return Some(node.value.descendants().find_map(|it| { let first = it.first_token()?; let last = it.last_token()?; @@ -380,12 +408,7 @@ fn original_range_and_origin( first.with_value(union_range(first.value.text_range(), last.value.text_range())), first_origin, )) - })?; - - return Some(( - FileRange { file_id: range.file_id.original_file(db), range: range.value }, - origin, - )); + })?); fn union_range(a: TextRange, b: TextRange) -> TextRange { let start = a.start().min(b.start()); diff --git a/crates/ra_ide/src/hover.rs b/crates/ra_ide/src/hover.rs index ace33c079..29b16e602 100644 --- a/crates/ra_ide/src/hover.rs +++ b/crates/ra_ide/src/hover.rs @@ -753,6 +753,27 @@ fn func(foo: i32) { if true { <|>foo; }; } assert_eq!(hover_on, "bar") } + #[test] + fn test_hover_through_expr_in_macro_recursive() { + let hover_on = check_hover_result( + " + //- /lib.rs + macro_rules! id_deep { + ($($tt:tt)*) => { $($tt)* } + } + macro_rules! id { + ($($tt:tt)*) => { id_deep!($($tt)*) } + } + fn foo(bar:u32) { + let a = id!(ba<|>r); + } + ", + &["u32"], + ); + + assert_eq!(hover_on, "bar") + } + #[test] fn test_hover_non_ascii_space_doc() { check_hover_result( -- cgit v1.2.3