aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/ra_hir/src/semantics.rs50
-rw-r--r--crates/ra_ide/src/hover.rs21
2 files changed, 57 insertions, 14 deletions
diff --git a/crates/ra_hir/src/semantics.rs b/crates/ra_hir/src/semantics.rs
index 9fedb7657..0b40bf9af 100644
--- a/crates/ra_hir/src/semantics.rs
+++ b/crates/ra_hir/src/semantics.rs
@@ -7,7 +7,10 @@ use hir_def::{
7 DefWithBodyId, TraitId, 7 DefWithBodyId, TraitId,
8}; 8};
9use ra_db::{FileId, FileRange}; 9use ra_db::{FileId, FileRange};
10use ra_syntax::{ast, match_ast, AstNode, SyntaxNode, SyntaxToken, TextRange, TextUnit}; 10use ra_syntax::{
11 algo::find_covering_element, ast, match_ast, AstNode, NodeOrToken, SyntaxElement, SyntaxNode,
12 SyntaxToken, TextRange, TextUnit,
13};
11use rustc_hash::{FxHashMap, FxHashSet}; 14use rustc_hash::{FxHashMap, FxHashSet};
12 15
13use crate::{ 16use crate::{
@@ -333,10 +336,27 @@ impl<'a, DB: HirDatabase> SemanticsScope<'a, DB> {
333 336
334// FIXME: Change `HasSource` trait to work with `Semantics` and remove this? 337// FIXME: Change `HasSource` trait to work with `Semantics` and remove this?
335pub fn original_range(db: &impl HirDatabase, node: InFile<&SyntaxNode>) -> FileRange { 338pub fn original_range(db: &impl HirDatabase, node: InFile<&SyntaxNode>) -> FileRange {
336 if let Some((range, Origin::Call)) = original_range_and_origin(db, node) { 339 let mut elem: InFile<SyntaxElement> = node.map(|n| n.clone().into());
337 return range; 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 };
338 } 357 }
339 358
359 // Fall back to whole macro call
340 if let Some(expansion) = node.file_id.expansion_info(db) { 360 if let Some(expansion) = node.file_id.expansion_info(db) {
341 if let Some(call_node) = expansion.call_node() { 361 if let Some(call_node) = expansion.call_node() {
342 return FileRange { 362 return FileRange {
@@ -351,15 +371,22 @@ pub fn original_range(db: &impl HirDatabase, node: InFile<&SyntaxNode>) -> FileR
351 371
352fn original_range_and_origin( 372fn original_range_and_origin(
353 db: &impl HirDatabase, 373 db: &impl HirDatabase,
354 node: InFile<&SyntaxNode>, 374 elem: InFile<&SyntaxElement>,
355) -> Option<(FileRange, Origin)> { 375) -> Option<(InFile<TextRange>, Origin)> {
356 let expansion = node.file_id.expansion_info(db)?; 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 };
357 385
358 // the input node has only one token ? 386 // the input node has only one token ?
359 let single = node.value.first_token()? == node.value.last_token()?; 387 let single = node.value.first_token()? == node.value.last_token()?;
360 388
361 // FIXME: We should handle recurside macro expansions 389 return Some(node.value.descendants().find_map(|it| {
362 let (range, origin) = node.value.descendants().find_map(|it| {
363 let first = it.first_token()?; 390 let first = it.first_token()?;
364 let last = it.last_token()?; 391 let last = it.last_token()?;
365 392
@@ -380,12 +407,7 @@ fn original_range_and_origin(
380 first.with_value(union_range(first.value.text_range(), last.value.text_range())), 407 first.with_value(union_range(first.value.text_range(), last.value.text_range())),
381 first_origin, 408 first_origin,
382 )) 409 ))
383 })?; 410 })?);
384
385 return Some((
386 FileRange { file_id: range.file_id.original_file(db), range: range.value },
387 origin,
388 ));
389 411
390 fn union_range(a: TextRange, b: TextRange) -> TextRange { 412 fn union_range(a: TextRange, b: TextRange) -> TextRange {
391 let start = a.start().min(b.start()); 413 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
@@ -754,6 +754,27 @@ fn func(foo: i32) { if true { <|>foo; }; }
754 } 754 }
755 755
756 #[test] 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
777 #[test]
757 fn test_hover_non_ascii_space_doc() { 778 fn test_hover_non_ascii_space_doc() {
758 check_hover_result( 779 check_hover_result(
759 " 780 "