aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbors[bot] <bors[bot]@users.noreply.github.com>2019-01-05 18:09:48 +0000
committerbors[bot] <bors[bot]@users.noreply.github.com>2019-01-05 18:09:48 +0000
commit3e42a158787955ff9f2e81be43479dbe8f2b1bb6 (patch)
treef6e9e68520bb793276a1a1ad8384b53096d1f390
parentcc53e9e7d17871c03fa9d88c709873e20690ca84 (diff)
parent01cf32c46e152058b81a11f3fe429be2d76cff98 (diff)
Merge #438
438: show types in local variable hovers r=matklad a=matklad Co-authored-by: Aleksey Kladov <[email protected]>
-rw-r--r--crates/ra_analysis/src/hover.rs85
-rw-r--r--crates/ra_analysis/src/lib.rs2
-rw-r--r--crates/ra_analysis/tests/test/main.rs1
-rw-r--r--crates/ra_analysis/tests/test/type_of.rs77
4 files changed, 76 insertions, 89 deletions
diff --git a/crates/ra_analysis/src/hover.rs b/crates/ra_analysis/src/hover.rs
index 758de376e..2cf79eebf 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,8 +167,7 @@ impl NavigationTarget {
156#[cfg(test)] 167#[cfg(test)]
157mod tests { 168mod tests {
158 use ra_syntax::TextRange; 169 use ra_syntax::TextRange;
159 170 use crate::mock_analysis::{single_file_with_position, single_file_with_range};
160 use crate::mock_analysis::single_file_with_position;
161 171
162 #[test] 172 #[test]
163 fn hover_shows_type_of_an_expression() { 173 fn hover_shows_type_of_an_expression() {
@@ -168,10 +178,65 @@ 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 }
194
195 #[test]
196 fn test_type_of_for_function() {
197 let (analysis, range) = single_file_with_range(
198 "
199 pub fn foo() -> u32 { 1 };
200
201 fn main() {
202 let foo_test = <|>foo()<|>;
203 }
204 ",
205 );
206
207 let type_name = analysis.type_of(range).unwrap().unwrap();
208 assert_eq!("u32", &type_name);
209 }
210
211 // FIXME: improve type_of to make this work
212 #[test]
213 fn test_type_of_for_expr_1() {
214 let (analysis, range) = single_file_with_range(
215 "
216 fn main() {
217 let foo = <|>1 + foo_test<|>;
218 }
219 ",
220 );
221
222 let type_name = analysis.type_of(range).unwrap().unwrap();
223 assert_eq!("[unknown]", &type_name);
224 }
225
226 // FIXME: improve type_of to make this work
227 #[test]
228 fn test_type_of_for_expr_2() {
229 let (analysis, range) = single_file_with_range(
230 "
231 fn main() {
232 let foo: usize = 1;
233 let bar = <|>1 + foo_test<|>;
234 }
235 ",
236 );
237
238 let type_name = analysis.type_of(range).unwrap().unwrap();
239 assert_eq!("[unknown]", &type_name);
240 }
241
177} 242}
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,
diff --git a/crates/ra_analysis/tests/test/main.rs b/crates/ra_analysis/tests/test/main.rs
index e15035304..26da7c10c 100644
--- a/crates/ra_analysis/tests/test/main.rs
+++ b/crates/ra_analysis/tests/test/main.rs
@@ -1,5 +1,4 @@
1mod runnables; 1mod runnables;
2mod type_of;
3 2
4use ra_syntax::TextRange; 3use ra_syntax::TextRange;
5use test_utils::{assert_eq_dbg, assert_eq_text}; 4use test_utils::{assert_eq_dbg, assert_eq_text};
diff --git a/crates/ra_analysis/tests/test/type_of.rs b/crates/ra_analysis/tests/test/type_of.rs
deleted file mode 100644
index 9d15b52a8..000000000
--- a/crates/ra_analysis/tests/test/type_of.rs
+++ /dev/null
@@ -1,77 +0,0 @@
1use ra_analysis::mock_analysis::single_file_with_range;
2
3#[test]
4fn test_type_of_for_function() {
5 let (analysis, range) = single_file_with_range(
6 "
7 pub fn foo() -> u32 { 1 };
8
9 fn main() {
10 let foo_test = <|>foo()<|>;
11 }
12 ",
13 );
14
15 let type_name = analysis.type_of(range).unwrap().unwrap();
16 assert_eq!("u32", &type_name);
17}
18
19// FIXME: improve type_of to make this work
20#[test]
21fn test_type_of_for_num() {
22 let (analysis, range) = single_file_with_range(
23 r#"
24 fn main() {
25 let foo_test = <|>"foo"<|>;
26 }
27 "#,
28 );
29
30 assert!(analysis.type_of(range).unwrap().is_none());
31}
32// FIXME: improve type_of to make this work
33#[test]
34fn test_type_of_for_binding() {
35 let (analysis, range) = single_file_with_range(
36 "
37 pub fn foo() -> u32 { 1 };
38
39 fn main() {
40 let <|>foo_test<|> = foo();
41 }
42 ",
43 );
44
45 assert!(analysis.type_of(range).unwrap().is_none());
46}
47
48// FIXME: improve type_of to make this work
49#[test]
50fn test_type_of_for_expr_1() {
51 let (analysis, range) = single_file_with_range(
52 "
53 fn main() {
54 let foo = <|>1 + foo_test<|>;
55 }
56 ",
57 );
58
59 let type_name = analysis.type_of(range).unwrap().unwrap();
60 assert_eq!("[unknown]", &type_name);
61}
62
63// FIXME: improve type_of to make this work
64#[test]
65fn test_type_of_for_expr_2() {
66 let (analysis, range) = single_file_with_range(
67 "
68 fn main() {
69 let foo: usize = 1;
70 let bar = <|>1 + foo_test<|>;
71 }
72 ",
73 );
74
75 let type_name = analysis.type_of(range).unwrap().unwrap();
76 assert_eq!("[unknown]", &type_name);
77}