mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-09-28 21:05:02 +00:00
Add recursive support in original_range
This commit is contained in:
parent
80f8e474a0
commit
ffdc740446
2 changed files with 58 additions and 14 deletions
|
@ -7,7 +7,10 @@ use hir_def::{
|
||||||
DefWithBodyId, TraitId,
|
DefWithBodyId, TraitId,
|
||||||
};
|
};
|
||||||
use ra_db::{FileId, FileRange};
|
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 rustc_hash::{FxHashMap, FxHashSet};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
@ -333,10 +336,28 @@ impl<'a, DB: HirDatabase> SemanticsScope<'a, DB> {
|
||||||
|
|
||||||
// FIXME: Change `HasSource` trait to work with `Semantics` and remove this?
|
// FIXME: Change `HasSource` trait to work with `Semantics` and remove this?
|
||||||
pub fn original_range(db: &impl HirDatabase, node: InFile<&SyntaxNode>) -> FileRange {
|
pub fn original_range(db: &impl HirDatabase, node: InFile<&SyntaxNode>) -> FileRange {
|
||||||
if let Some((range, Origin::Call)) = original_range_and_origin(db, node) {
|
let mut elem: InFile<SyntaxElement> = node.map(|n| n.clone().into());
|
||||||
return range;
|
|
||||||
|
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(expansion) = node.file_id.expansion_info(db) {
|
||||||
if let Some(call_node) = expansion.call_node() {
|
if let Some(call_node) = expansion.call_node() {
|
||||||
return FileRange {
|
return FileRange {
|
||||||
|
@ -351,15 +372,22 @@ pub fn original_range(db: &impl HirDatabase, node: InFile<&SyntaxNode>) -> FileR
|
||||||
|
|
||||||
fn original_range_and_origin(
|
fn original_range_and_origin(
|
||||||
db: &impl HirDatabase,
|
db: &impl HirDatabase,
|
||||||
node: InFile<&SyntaxNode>,
|
elem: InFile<&SyntaxElement>,
|
||||||
) -> Option<(FileRange, Origin)> {
|
) -> Option<(InFile<TextRange>, Origin)> {
|
||||||
let expansion = node.file_id.expansion_info(db)?;
|
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 ?
|
// the input node has only one token ?
|
||||||
let single = node.value.first_token()? == node.value.last_token()?;
|
let single = node.value.first_token()? == node.value.last_token()?;
|
||||||
|
|
||||||
// FIXME: We should handle recurside macro expansions
|
return Some(node.value.descendants().find_map(|it| {
|
||||||
let (range, origin) = node.value.descendants().find_map(|it| {
|
|
||||||
let first = it.first_token()?;
|
let first = it.first_token()?;
|
||||||
let last = it.last_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.with_value(union_range(first.value.text_range(), last.value.text_range())),
|
||||||
first_origin,
|
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 {
|
fn union_range(a: TextRange, b: TextRange) -> TextRange {
|
||||||
let start = a.start().min(b.start());
|
let start = a.start().min(b.start());
|
||||||
|
|
|
@ -753,6 +753,27 @@ fn func(foo: i32) { if true { <|>foo; }; }
|
||||||
assert_eq!(hover_on, "bar")
|
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]
|
#[test]
|
||||||
fn test_hover_non_ascii_space_doc() {
|
fn test_hover_non_ascii_space_doc() {
|
||||||
check_hover_result(
|
check_hover_result(
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue