aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/ra_hir/src/semantics.rs65
-rw-r--r--crates/ra_ide/src/hover.rs24
2 files changed, 51 insertions, 38 deletions
diff --git a/crates/ra_hir/src/semantics.rs b/crates/ra_hir/src/semantics.rs
index 154adedb3..178d74be1 100644
--- a/crates/ra_hir/src/semantics.rs
+++ b/crates/ra_hir/src/semantics.rs
@@ -8,8 +8,7 @@ use hir_def::{
8}; 8};
9use ra_db::{FileId, FileRange}; 9use ra_db::{FileId, FileRange};
10use ra_syntax::{ 10use ra_syntax::{
11 algo::{find_covering_element, skip_trivia_token}, 11 algo::skip_trivia_token, ast, match_ast, AstNode, Direction, SyntaxNode, SyntaxToken,
12 ast, match_ast, AstNode, Direction, NodeOrToken, SyntaxElement, SyntaxNode, SyntaxToken,
13 TextRange, TextUnit, 12 TextRange, TextUnit,
14}; 13};
15use rustc_hash::{FxHashMap, FxHashSet}; 14use rustc_hash::{FxHashMap, FxHashSet};
@@ -21,6 +20,7 @@ use crate::{
21 Function, HirFileId, InFile, Local, MacroDef, Module, ModuleDef, Name, Origin, Path, 20 Function, HirFileId, InFile, Local, MacroDef, Module, ModuleDef, Name, Origin, Path,
22 PathResolution, ScopeDef, StructField, Trait, Type, TypeParam, VariantDef, 21 PathResolution, ScopeDef, StructField, Trait, Type, TypeParam, VariantDef,
23}; 22};
23use hir_expand::ExpansionInfo;
24use ra_prof::profile; 24use ra_prof::profile;
25 25
26/// Primary API to get semantic information, like types, from syntax trees. 26/// Primary API to get semantic information, like types, from syntax trees.
@@ -341,22 +341,12 @@ impl<'a, DB: HirDatabase> SemanticsScope<'a, DB> {
341 341
342// FIXME: Change `HasSource` trait to work with `Semantics` and remove this? 342// FIXME: Change `HasSource` trait to work with `Semantics` and remove this?
343pub fn original_range(db: &impl HirDatabase, node: InFile<&SyntaxNode>) -> FileRange { 343pub fn original_range(db: &impl HirDatabase, node: InFile<&SyntaxNode>) -> FileRange {
344 let mut elem: InFile<SyntaxElement> = node.map(|n| n.clone().into()); 344 if let Some(range) = original_range_opt(db, node) {
345
346 while let Some((range, Origin::Call)) = original_range_and_origin(db, elem.as_ref()) {
347 let original_file = range.file_id.original_file(db); 345 let original_file = range.file_id.original_file(db);
348
349 if range.file_id == original_file.into() { 346 if range.file_id == original_file.into() {
350 return FileRange { file_id: original_file, range: range.value }; 347 return FileRange { file_id: original_file, range: range.value };
351 } 348 }
352 349
353 if range.file_id != elem.file_id {
354 if let Some(root) = db.parse_or_expand(range.file_id) {
355 elem = range.with_value(find_covering_element(&root, range.value));
356 continue;
357 }
358 }
359
360 log::error!("Fail to mapping up more for {:?}", range); 350 log::error!("Fail to mapping up more for {:?}", range);
361 return FileRange { file_id: range.file_id.original_file(db), range: range.value }; 351 return FileRange { file_id: range.file_id.original_file(db), range: range.value };
362 } 352 }
@@ -374,19 +364,11 @@ pub fn original_range(db: &impl HirDatabase, node: InFile<&SyntaxNode>) -> FileR
374 FileRange { file_id: node.file_id.original_file(db), range: node.value.text_range() } 364 FileRange { file_id: node.file_id.original_file(db), range: node.value.text_range() }
375} 365}
376 366
377fn original_range_and_origin( 367fn original_range_opt(
378 db: &impl HirDatabase, 368 db: &impl HirDatabase,
379 elem: InFile<&SyntaxElement>, 369 node: InFile<&SyntaxNode>,
380) -> Option<(InFile<TextRange>, Origin)> { 370) -> Option<InFile<TextRange>> {
381 let expansion = elem.file_id.expansion_info(db)?; 371 let expansion = node.file_id.expansion_info(db)?;
382
383 let node = match elem.as_ref().value {
384 NodeOrToken::Node(it) => elem.with_value(it),
385 NodeOrToken::Token(it) => {
386 let (tt, origin) = expansion.map_token_up(elem.with_value(it))?;
387 return Some((tt.map(|it| it.text_range()), origin));
388 }
389 };
390 372
391 // the input node has only one token ? 373 // the input node has only one token ?
392 let single = skip_trivia_token(node.value.first_token()?, Direction::Next)? 374 let single = skip_trivia_token(node.value.first_token()?, Direction::Next)?
@@ -394,23 +376,30 @@ fn original_range_and_origin(
394 376
395 Some(node.value.descendants().find_map(|it| { 377 Some(node.value.descendants().find_map(|it| {
396 let first = skip_trivia_token(it.first_token()?, Direction::Next)?; 378 let first = skip_trivia_token(it.first_token()?, Direction::Next)?;
397 let last = skip_trivia_token(it.last_token()?, Direction::Prev)?; 379 let first = ascend_call_token(db, &expansion, node.with_value(first))?;
398
399 if !single && first == last {
400 return None;
401 }
402 380
403 // Try to map first and last tokens of node, and, if success, return the union range of mapped tokens 381 let last = skip_trivia_token(it.last_token()?, Direction::Prev)?;
404 let (first, first_origin) = expansion.map_token_up(node.with_value(&first))?; 382 let last = ascend_call_token(db, &expansion, node.with_value(last))?;
405 let (last, last_origin) = expansion.map_token_up(node.with_value(&last))?;
406 383
407 if first.file_id != last.file_id || first_origin != last_origin { 384 if (!single && first == last) || (first.file_id != last.file_id) {
408 return None; 385 return None;
409 } 386 }
410 387
411 Some(( 388 Some(first.with_value(first.value.text_range().extend_to(&last.value.text_range())))
412 first.with_value(first.value.text_range().extend_to(&last.value.text_range())),
413 first_origin,
414 ))
415 })?) 389 })?)
416} 390}
391
392fn ascend_call_token(
393 db: &impl HirDatabase,
394 expansion: &ExpansionInfo,
395 token: InFile<SyntaxToken>,
396) -> Option<InFile<SyntaxToken>> {
397 let (mapped, origin) = expansion.map_token_up(token.as_ref())?;
398 if origin != Origin::Call {
399 return None;
400 }
401 if let Some(info) = mapped.file_id.expansion_info(db) {
402 return ascend_call_token(db, &info, mapped);
403 }
404 Some(mapped)
405}
diff --git a/crates/ra_ide/src/hover.rs b/crates/ra_ide/src/hover.rs
index 1e4fcdefb..5073bb1cf 100644
--- a/crates/ra_ide/src/hover.rs
+++ b/crates/ra_ide/src/hover.rs
@@ -739,6 +739,30 @@ fn func(foo: i32) { if true { <|>foo; }; }
739 } 739 }
740 740
741 #[test] 741 #[test]
742 fn test_hover_through_func_in_macro_recursive() {
743 let hover_on = check_hover_result(
744 "
745 //- /lib.rs
746 macro_rules! id_deep {
747 ($($tt:tt)*) => { $($tt)* }
748 }
749 macro_rules! id {
750 ($($tt:tt)*) => { id_deep!($($tt)*) }
751 }
752 fn bar() -> u32 {
753 0
754 }
755 fn foo() {
756 let a = id!([0u32, bar(<|>)] );
757 }
758 ",
759 &["u32"],
760 );
761
762 assert_eq!(hover_on, "bar()")
763 }
764
765 #[test]
742 fn test_hover_through_literal_string_in_macro() { 766 fn test_hover_through_literal_string_in_macro() {
743 let hover_on = check_hover_result( 767 let hover_on = check_hover_result(
744 r#" 768 r#"