aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_analysis/src
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_analysis/src')
-rw-r--r--crates/ra_analysis/src/hover.rs85
-rw-r--r--crates/ra_analysis/src/lib.rs2
2 files changed, 76 insertions, 11 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,