aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
Diffstat (limited to 'crates')
-rw-r--r--crates/ra_hir/src/semantics.rs51
-rw-r--r--crates/ra_ide/src/hover.rs21
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::{
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,28 @@ 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 // Fail to mapping up more, return the original file range instead
349 if range.file_id != elem.file_id {
350 if let Some(root) = db.parse_or_expand(range.file_id) {
351 elem = range.with_value(find_covering_element(&root, range.value));
352 continue;
353 }
354 }
355
356 log::error!("Fail to mapping up more for {:?}", range);
357 return FileRange { file_id: range.file_id.original_file(db), range: range.value };
338 } 358 }
339 359
360 // Fall back to whole macro call
340 if let Some(expansion) = node.file_id.expansion_info(db) { 361 if let Some(expansion) = node.file_id.expansion_info(db) {
341 if let Some(call_node) = expansion.call_node() { 362 if let Some(call_node) = expansion.call_node() {
342 return FileRange { 363 return FileRange {
@@ -351,15 +372,22 @@ pub fn original_range(db: &impl HirDatabase, node: InFile<&SyntaxNode>) -> FileR
351 372
352fn original_range_and_origin( 373fn original_range_and_origin(
353 db: &impl HirDatabase, 374 db: &impl HirDatabase,
354 node: InFile<&SyntaxNode>, 375 elem: InFile<&SyntaxElement>,
355) -> Option<(FileRange, Origin)> { 376) -> Option<(InFile<TextRange>, Origin)> {
356 let expansion = node.file_id.expansion_info(db)?; 377 let expansion = elem.file_id.expansion_info(db)?;
378
379 let node = match elem.as_ref().value {
380 NodeOrToken::Node(it) => elem.with_value(it),
381 NodeOrToken::Token(it) => {
382 let (tt, origin) = expansion.map_token_up(elem.with_value(it))?;
383 return Some((tt.map(|it| it.text_range()), origin));
384 }
385 };
357 386
358 // the input node has only one token ? 387 // the input node has only one token ?
359 let single = node.value.first_token()? == node.value.last_token()?; 388 let single = node.value.first_token()? == node.value.last_token()?;
360 389
361 // FIXME: We should handle recurside macro expansions 390 return Some(node.value.descendants().find_map(|it| {
362 let (range, origin) = node.value.descendants().find_map(|it| {
363 let first = it.first_token()?; 391 let first = it.first_token()?;
364 let last = it.last_token()?; 392 let last = it.last_token()?;
365 393
@@ -380,12 +408,7 @@ fn original_range_and_origin(
380 first.with_value(union_range(first.value.text_range(), last.value.text_range())), 408 first.with_value(union_range(first.value.text_range(), last.value.text_range())),
381 first_origin, 409 first_origin,
382 )) 410 ))
383 })?; 411 })?);
384
385 return Some((
386 FileRange { file_id: range.file_id.original_file(db), range: range.value },
387 origin,
388 ));
389 412
390 fn union_range(a: TextRange, b: TextRange) -> TextRange { 413 fn union_range(a: TextRange, b: TextRange) -> TextRange {
391 let start = a.start().min(b.start()); 414 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 "