aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAleksey Kladov <[email protected]>2019-01-05 17:53:30 +0000
committerAleksey Kladov <[email protected]>2019-01-05 17:53:30 +0000
commitbe84a112a75f4e9acac76c497d714aba8d465ed2 (patch)
tree206ca6d0bb186c01a1fa979023afbb76147a5853
parentee461a211195b093269ead477f01fcf63f20cf34 (diff)
show types in local variable hovers
-rw-r--r--crates/ra_analysis/src/hover.rs35
-rw-r--r--crates/ra_analysis/src/lib.rs2
2 files changed, 27 insertions, 10 deletions
diff --git a/crates/ra_analysis/src/hover.rs b/crates/ra_analysis/src/hover.rs
index 758de376e..8217df305 100644
--- a/crates/ra_analysis/src/hover.rs
+++ b/crates/ra_analysis/src/hover.rs
@@ -14,23 +14,28 @@ pub(crate) fn hover(
14) -> Cancelable<Option<RangeInfo<String>>> { 14) -> Cancelable<Option<RangeInfo<String>>> {
15 let file = db.source_file(position.file_id); 15 let file = db.source_file(position.file_id);
16 let mut res = Vec::new(); 16 let mut res = Vec::new();
17 let range = if let Some(name_ref) = 17
18 find_node_at_offset::<ast::NameRef>(file.syntax(), position.offset) 18 let mut range = None;
19 { 19 if let Some(name_ref) = find_node_at_offset::<ast::NameRef>(file.syntax(), position.offset) {
20 let navs = crate::goto_defenition::reference_defenition(db, position.file_id, name_ref)?; 20 let navs = crate::goto_defenition::reference_defenition(db, position.file_id, name_ref)?;
21 for nav in navs { 21 for nav in navs {
22 res.extend(doc_text_for(db, nav)?) 22 res.extend(doc_text_for(db, nav)?)
23 } 23 }
24 name_ref.syntax().range() 24 if !res.is_empty() {
25 } else { 25 range = Some(name_ref.syntax().range())
26 }
27 }
28 if range.is_none() {
26 let expr: ast::Expr = ctry!(find_node_at_offset(file.syntax(), position.offset)); 29 let expr: ast::Expr = ctry!(find_node_at_offset(file.syntax(), position.offset));
27 let frange = FileRange { 30 let frange = FileRange {
28 file_id: position.file_id, 31 file_id: position.file_id,
29 range: expr.syntax().range(), 32 range: expr.syntax().range(),
30 }; 33 };
31 res.extend(type_of(db, frange)?); 34 res.extend(type_of(db, frange)?);
32 expr.syntax().range() 35 range = Some(expr.syntax().range());
33 }; 36 };
37
38 let range = ctry!(range);
34 if res.is_empty() { 39 if res.is_empty() {
35 return Ok(None); 40 return Ok(None);
36 } 41 }
@@ -41,7 +46,13 @@ pub(crate) fn hover(
41pub(crate) fn type_of(db: &RootDatabase, frange: FileRange) -> Cancelable<Option<String>> { 46pub(crate) fn type_of(db: &RootDatabase, frange: FileRange) -> Cancelable<Option<String>> {
42 let file = db.source_file(frange.file_id); 47 let file = db.source_file(frange.file_id);
43 let syntax = file.syntax(); 48 let syntax = file.syntax();
44 let node = find_covering_node(syntax, frange.range); 49 let leaf_node = find_covering_node(syntax, frange.range);
50 // if we picked identifier, expand to pattern/expression
51 let node = leaf_node
52 .ancestors()
53 .take_while(|it| it.range() == leaf_node.range())
54 .find(|&it| ast::Expr::cast(it).is_some() || ast::Pat::cast(it).is_some())
55 .unwrap_or(leaf_node);
45 let parent_fn = ctry!(node.ancestors().find_map(ast::FnDef::cast)); 56 let parent_fn = ctry!(node.ancestors().find_map(ast::FnDef::cast));
46 let function = ctry!(hir::source_binder::function_from_source( 57 let function = ctry!(hir::source_binder::function_from_source(
47 db, 58 db,
@@ -156,7 +167,6 @@ impl NavigationTarget {
156#[cfg(test)] 167#[cfg(test)]
157mod tests { 168mod tests {
158 use ra_syntax::TextRange; 169 use ra_syntax::TextRange;
159
160 use crate::mock_analysis::single_file_with_position; 170 use crate::mock_analysis::single_file_with_position;
161 171
162 #[test] 172 #[test]
@@ -168,10 +178,17 @@ mod tests {
168 fn main() { 178 fn main() {
169 let foo_test = foo()<|>; 179 let foo_test = foo()<|>;
170 } 180 }
171 ", 181 ",
172 ); 182 );
173 let hover = analysis.hover(position).unwrap().unwrap(); 183 let hover = analysis.hover(position).unwrap().unwrap();
174 assert_eq!(hover.range, TextRange::from_to(95.into(), 100.into())); 184 assert_eq!(hover.range, TextRange::from_to(95.into(), 100.into()));
175 assert_eq!(hover.info, "u32"); 185 assert_eq!(hover.info, "u32");
176 } 186 }
187
188 #[test]
189 fn hover_for_local_variable() {
190 let (analysis, position) = single_file_with_position("fn func(foo: i32) { fo<|>o; }");
191 let hover = analysis.hover(position).unwrap().unwrap();
192 assert_eq!(hover.info, "i32");
193 }
177} 194}
diff --git a/crates/ra_analysis/src/lib.rs b/crates/ra_analysis/src/lib.rs
index 4d895b004..390c31c3f 100644
--- a/crates/ra_analysis/src/lib.rs
+++ b/crates/ra_analysis/src/lib.rs
@@ -228,7 +228,7 @@ impl Query {
228/// 228///
229/// Typically, a `NavigationTarget` corresponds to some element in the source 229/// Typically, a `NavigationTarget` corresponds to some element in the source
230/// code, like a function or a struct, but this is not strictly required. 230/// code, like a function or a struct, but this is not strictly required.
231#[derive(Debug)] 231#[derive(Debug, Clone)]
232pub struct NavigationTarget { 232pub struct NavigationTarget {
233 file_id: FileId, 233 file_id: FileId,
234 name: SmolStr, 234 name: SmolStr,