diff options
Diffstat (limited to 'crates/ra_analysis')
-rw-r--r-- | crates/ra_analysis/src/hover.rs | 85 | ||||
-rw-r--r-- | crates/ra_analysis/src/lib.rs | 2 | ||||
-rw-r--r-- | crates/ra_analysis/tests/test/main.rs | 1 | ||||
-rw-r--r-- | crates/ra_analysis/tests/test/type_of.rs | 77 |
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( | |||
41 | pub(crate) fn type_of(db: &RootDatabase, frange: FileRange) -> Cancelable<Option<String>> { | 46 | pub(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)] |
157 | mod tests { | 168 | mod 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)] |
232 | pub struct NavigationTarget { | 232 | pub 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 @@ | |||
1 | mod runnables; | 1 | mod runnables; |
2 | mod type_of; | ||
3 | 2 | ||
4 | use ra_syntax::TextRange; | 3 | use ra_syntax::TextRange; |
5 | use test_utils::{assert_eq_dbg, assert_eq_text}; | 4 | use 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 @@ | |||
1 | use ra_analysis::mock_analysis::single_file_with_range; | ||
2 | |||
3 | #[test] | ||
4 | fn 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] | ||
21 | fn 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] | ||
34 | fn 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] | ||
50 | fn 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] | ||
65 | fn 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 | } | ||