aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/ra_ide_api/src/goto_definition.rs1
-rw-r--r--crates/ra_ide_api/src/hover.rs21
-rw-r--r--crates/ra_syntax/src/algo.rs21
3 files changed, 33 insertions, 10 deletions
diff --git a/crates/ra_ide_api/src/goto_definition.rs b/crates/ra_ide_api/src/goto_definition.rs
index 40a2bd148..163781f88 100644
--- a/crates/ra_ide_api/src/goto_definition.rs
+++ b/crates/ra_ide_api/src/goto_definition.rs
@@ -25,6 +25,7 @@ pub(crate) fn goto_definition(
25 None 25 None
26} 26}
27 27
28#[derive(Debug)]
28pub(crate) enum ReferenceResult { 29pub(crate) enum ReferenceResult {
29 Exact(NavigationTarget), 30 Exact(NavigationTarget),
30 Approximate(Vec<NavigationTarget>), 31 Approximate(Vec<NavigationTarget>),
diff --git a/crates/ra_ide_api/src/hover.rs b/crates/ra_ide_api/src/hover.rs
index 397b56786..6545a2581 100644
--- a/crates/ra_ide_api/src/hover.rs
+++ b/crates/ra_ide_api/src/hover.rs
@@ -1,7 +1,7 @@
1use ra_db::SourceDatabase; 1use ra_db::SourceDatabase;
2use ra_syntax::{ 2use ra_syntax::{
3 AstNode, ast, 3 AstNode, ast,
4 algo::{find_covering_element, find_node_at_offset, find_token_at_offset}, 4 algo::{find_covering_element, find_node_at_offset, ancestors_at_offset},
5}; 5};
6use hir::HirDisplay; 6use hir::HirDisplay;
7 7
@@ -104,12 +104,8 @@ pub(crate) fn hover(db: &RootDatabase, position: FilePosition) -> Option<RangeIn
104 } 104 }
105 105
106 if range.is_none() { 106 if range.is_none() {
107 let node = find_token_at_offset(file.syntax(), position.offset).find_map(|token| { 107 let node = ancestors_at_offset(file.syntax(), position.offset)
108 token 108 .find(|n| ast::Expr::cast(*n).is_some() || ast::Pat::cast(*n).is_some())?;
109 .parent()
110 .ancestors()
111 .find(|n| ast::Expr::cast(*n).is_some() || ast::Pat::cast(*n).is_some())
112 })?;
113 let frange = FileRange { file_id: position.file_id, range: node.range() }; 109 let frange = FileRange { file_id: position.file_id, range: node.range() };
114 res.extend(type_of(db, frange).map(rust_code_markup)); 110 res.extend(type_of(db, frange).map(rust_code_markup));
115 range = Some(node.range()); 111 range = Some(node.range());
@@ -398,6 +394,17 @@ The Some variant
398 } 394 }
399 395
400 #[test] 396 #[test]
397 fn hover_local_var_edge() {
398 let (analysis, position) = single_file_with_position(
399 "
400fn func(foo: i32) { if true { <|>foo; }; }
401",
402 );
403 let hover = analysis.hover(position).unwrap().unwrap();
404 assert_eq!(trim_markup_opt(hover.info.first()), Some("i32"));
405 }
406
407 #[test]
401 fn test_type_of_for_function() { 408 fn test_type_of_for_function() {
402 let (analysis, range) = single_file_with_range( 409 let (analysis, range) = single_file_with_range(
403 " 410 "
diff --git a/crates/ra_syntax/src/algo.rs b/crates/ra_syntax/src/algo.rs
index 1f68fe467..d31d00343 100644
--- a/crates/ra_syntax/src/algo.rs
+++ b/crates/ra_syntax/src/algo.rs
@@ -1,5 +1,7 @@
1pub mod visit; 1pub mod visit;
2 2
3use itertools::Itertools;
4
3use crate::{SyntaxNode, TextRange, TextUnit, AstNode, Direction, SyntaxToken, SyntaxElement}; 5use crate::{SyntaxNode, TextRange, TextUnit, AstNode, Direction, SyntaxToken, SyntaxElement};
4 6
5pub use rowan::TokenAtOffset; 7pub use rowan::TokenAtOffset;
@@ -12,6 +14,20 @@ pub fn find_token_at_offset(node: &SyntaxNode, offset: TextUnit) -> TokenAtOffse
12 } 14 }
13} 15}
14 16
17/// Returns ancestors of the node at the offset, sorted by length. This should
18/// do the right thing at an edge, e.g. when searching for expressions at `{
19/// <|>foo }` we will get the name reference instead of the whole block, which
20/// we would get if we just did `find_token_at_offset(...).flat_map(|t|
21/// t.parent().ancestors())`.
22pub fn ancestors_at_offset(
23 node: &SyntaxNode,
24 offset: TextUnit,
25) -> impl Iterator<Item = &SyntaxNode> {
26 find_token_at_offset(node, offset)
27 .map(|token| token.parent().ancestors())
28 .kmerge_by(|node1, node2| node1.range().len() < node2.range().len())
29}
30
15/// Finds a node of specific Ast type at offset. Note that this is slightly 31/// Finds a node of specific Ast type at offset. Note that this is slightly
16/// imprecise: if the cursor is strictly between two nodes of the desired type, 32/// imprecise: if the cursor is strictly between two nodes of the desired type,
17/// as in 33/// as in
@@ -20,10 +36,9 @@ pub fn find_token_at_offset(node: &SyntaxNode, offset: TextUnit) -> TokenAtOffse
20/// struct Foo {}|struct Bar; 36/// struct Foo {}|struct Bar;
21/// ``` 37/// ```
22/// 38///
23/// then the left node will be silently preferred. 39/// then the shorter node will be silently preferred.
24pub fn find_node_at_offset<N: AstNode>(syntax: &SyntaxNode, offset: TextUnit) -> Option<&N> { 40pub fn find_node_at_offset<N: AstNode>(syntax: &SyntaxNode, offset: TextUnit) -> Option<&N> {
25 find_token_at_offset(syntax, offset) 41 ancestors_at_offset(syntax, offset).find_map(N::cast)
26 .find_map(|leaf| leaf.parent().ancestors().find_map(N::cast))
27} 42}
28 43
29/// Finds the first sibling in the given direction which is not `trivia` 44/// Finds the first sibling in the given direction which is not `trivia`