Skip to content

Commit 2dee077

Browse files
authored
Merge pull request #3314 from edwin0cheng/original-range-recursive
Add recursive macro support in `original_range`
2 parents 9b11c18 + 871dc2b commit 2dee077

File tree

2 files changed

+57
-14
lines changed

2 files changed

+57
-14
lines changed

crates/ra_hir/src/semantics.rs

Lines changed: 36 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,10 @@ use hir_def::{
77
DefWithBodyId, TraitId,
88
};
99
use ra_db::{FileId, FileRange};
10-
use ra_syntax::{ast, match_ast, AstNode, SyntaxNode, SyntaxToken, TextRange, TextUnit};
10+
use ra_syntax::{
11+
algo::find_covering_element, ast, match_ast, AstNode, NodeOrToken, SyntaxElement, SyntaxNode,
12+
SyntaxToken, TextRange, TextUnit,
13+
};
1114
use rustc_hash::{FxHashMap, FxHashSet};
1215

1316
use crate::{
@@ -333,10 +336,27 @@ impl<'a, DB: HirDatabase> SemanticsScope<'a, DB> {
333336

334337
// FIXME: Change `HasSource` trait to work with `Semantics` and remove this?
335338
pub fn original_range(db: &impl HirDatabase, node: InFile<&SyntaxNode>) -> FileRange {
336-
if let Some((range, Origin::Call)) = original_range_and_origin(db, node) {
337-
return range;
339+
let mut elem: InFile<SyntaxElement> = node.map(|n| n.clone().into());
340+
341+
while let Some((range, Origin::Call)) = original_range_and_origin(db, elem.as_ref()) {
342+
let original_file = range.file_id.original_file(db);
343+
344+
if range.file_id == original_file.into() {
345+
return FileRange { file_id: original_file, range: range.value };
346+
}
347+
348+
if range.file_id != elem.file_id {
349+
if let Some(root) = db.parse_or_expand(range.file_id) {
350+
elem = range.with_value(find_covering_element(&root, range.value));
351+
continue;
352+
}
353+
}
354+
355+
log::error!("Fail to mapping up more for {:?}", range);
356+
return FileRange { file_id: range.file_id.original_file(db), range: range.value };
338357
}
339358

359+
// Fall back to whole macro call
340360
if let Some(expansion) = node.file_id.expansion_info(db) {
341361
if let Some(call_node) = expansion.call_node() {
342362
return FileRange {
@@ -351,15 +371,22 @@ pub fn original_range(db: &impl HirDatabase, node: InFile<&SyntaxNode>) -> FileR
351371

352372
fn original_range_and_origin(
353373
db: &impl HirDatabase,
354-
node: InFile<&SyntaxNode>,
355-
) -> Option<(FileRange, Origin)> {
356-
let expansion = node.file_id.expansion_info(db)?;
374+
elem: InFile<&SyntaxElement>,
375+
) -> Option<(InFile<TextRange>, Origin)> {
376+
let expansion = elem.file_id.expansion_info(db)?;
377+
378+
let node = match elem.as_ref().value {
379+
NodeOrToken::Node(it) => elem.with_value(it),
380+
NodeOrToken::Token(it) => {
381+
let (tt, origin) = expansion.map_token_up(elem.with_value(it))?;
382+
return Some((tt.map(|it| it.text_range()), origin));
383+
}
384+
};
357385

358386
// the input node has only one token ?
359387
let single = node.value.first_token()? == node.value.last_token()?;
360388

361-
// FIXME: We should handle recurside macro expansions
362-
let (range, origin) = node.value.descendants().find_map(|it| {
389+
return Some(node.value.descendants().find_map(|it| {
363390
let first = it.first_token()?;
364391
let last = it.last_token()?;
365392

@@ -380,12 +407,7 @@ fn original_range_and_origin(
380407
first.with_value(union_range(first.value.text_range(), last.value.text_range())),
381408
first_origin,
382409
))
383-
})?;
384-
385-
return Some((
386-
FileRange { file_id: range.file_id.original_file(db), range: range.value },
387-
origin,
388-
));
410+
})?);
389411

390412
fn union_range(a: TextRange, b: TextRange) -> TextRange {
391413
let start = a.start().min(b.start());

crates/ra_ide/src/hover.rs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -753,6 +753,27 @@ fn func(foo: i32) { if true { <|>foo; }; }
753753
assert_eq!(hover_on, "bar")
754754
}
755755

756+
#[test]
757+
fn test_hover_through_expr_in_macro_recursive() {
758+
let hover_on = check_hover_result(
759+
"
760+
//- /lib.rs
761+
macro_rules! id_deep {
762+
($($tt:tt)*) => { $($tt)* }
763+
}
764+
macro_rules! id {
765+
($($tt:tt)*) => { id_deep!($($tt)*) }
766+
}
767+
fn foo(bar:u32) {
768+
let a = id!(ba<|>r);
769+
}
770+
",
771+
&["u32"],
772+
);
773+
774+
assert_eq!(hover_on, "bar")
775+
}
776+
756777
#[test]
757778
fn test_hover_non_ascii_space_doc() {
758779
check_hover_result(

0 commit comments

Comments
 (0)