aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_ide_api/src/hover.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_ide_api/src/hover.rs')
-rw-r--r--crates/ra_ide_api/src/hover.rs48
1 files changed, 19 insertions, 29 deletions
diff --git a/crates/ra_ide_api/src/hover.rs b/crates/ra_ide_api/src/hover.rs
index 6b5887bda..d91151c15 100644
--- a/crates/ra_ide_api/src/hover.rs
+++ b/crates/ra_ide_api/src/hover.rs
@@ -1,4 +1,4 @@
1use ra_db::{Cancelable, SyntaxDatabase}; 1use ra_db::{SyntaxDatabase};
2use ra_syntax::{ 2use ra_syntax::{
3 AstNode, SyntaxNode, TreeArc, 3 AstNode, SyntaxNode, TreeArc,
4 ast::self, 4 ast::self,
@@ -7,19 +7,16 @@ use ra_syntax::{
7 7
8use crate::{db::RootDatabase, RangeInfo, FilePosition, FileRange, NavigationTarget}; 8use crate::{db::RootDatabase, RangeInfo, FilePosition, FileRange, NavigationTarget};
9 9
10pub(crate) fn hover( 10pub(crate) fn hover(db: &RootDatabase, position: FilePosition) -> Option<RangeInfo<String>> {
11 db: &RootDatabase,
12 position: FilePosition,
13) -> Cancelable<Option<RangeInfo<String>>> {
14 let file = db.source_file(position.file_id); 11 let file = db.source_file(position.file_id);
15 let mut res = Vec::new(); 12 let mut res = Vec::new();
16 13
17 let mut range = None; 14 let mut range = None;
18 if let Some(name_ref) = find_node_at_offset::<ast::NameRef>(file.syntax(), position.offset) { 15 if let Some(name_ref) = find_node_at_offset::<ast::NameRef>(file.syntax(), position.offset) {
19 use crate::goto_definition::{ReferenceResult::*, reference_definition}; 16 use crate::goto_definition::{ReferenceResult::*, reference_definition};
20 let ref_result = reference_definition(db, position.file_id, name_ref)?; 17 let ref_result = reference_definition(db, position.file_id, name_ref);
21 match ref_result { 18 match ref_result {
22 Exact(nav) => res.extend(doc_text_for(db, nav)?), 19 Exact(nav) => res.extend(doc_text_for(db, nav)),
23 Approximate(navs) => { 20 Approximate(navs) => {
24 let mut msg = String::from("Failed to exactly resolve the symbol. This is probably because rust_analyzer does not yet support glob imports or traits."); 21 let mut msg = String::from("Failed to exactly resolve the symbol. This is probably because rust_analyzer does not yet support glob imports or traits.");
25 if !navs.is_empty() { 22 if !navs.is_empty() {
@@ -27,7 +24,7 @@ pub(crate) fn hover(
27 } 24 }
28 res.push(msg); 25 res.push(msg);
29 for nav in navs { 26 for nav in navs {
30 res.extend(doc_text_for(db, nav)?) 27 res.extend(doc_text_for(db, nav))
31 } 28 }
32 } 29 }
33 } 30 }
@@ -39,25 +36,24 @@ pub(crate) fn hover(
39 let node = find_leaf_at_offset(file.syntax(), position.offset).find_map(|leaf| { 36 let node = find_leaf_at_offset(file.syntax(), position.offset).find_map(|leaf| {
40 leaf.ancestors() 37 leaf.ancestors()
41 .find(|n| ast::Expr::cast(*n).is_some() || ast::Pat::cast(*n).is_some()) 38 .find(|n| ast::Expr::cast(*n).is_some() || ast::Pat::cast(*n).is_some())
42 }); 39 })?;
43 let node = ctry!(node);
44 let frange = FileRange { 40 let frange = FileRange {
45 file_id: position.file_id, 41 file_id: position.file_id,
46 range: node.range(), 42 range: node.range(),
47 }; 43 };
48 res.extend(type_of(db, frange)?.map(Into::into)); 44 res.extend(type_of(db, frange).map(Into::into));
49 range = Some(node.range()); 45 range = Some(node.range());
50 }; 46 };
51 47
52 let range = ctry!(range); 48 let range = range?;
53 if res.is_empty() { 49 if res.is_empty() {
54 return Ok(None); 50 return None;
55 } 51 }
56 let res = RangeInfo::new(range, res.join("\n\n---\n")); 52 let res = RangeInfo::new(range, res.join("\n\n---\n"));
57 Ok(Some(res)) 53 Some(res)
58} 54}
59 55
60pub(crate) fn type_of(db: &RootDatabase, frange: FileRange) -> Cancelable<Option<String>> { 56pub(crate) fn type_of(db: &RootDatabase, frange: FileRange) -> Option<String> {
61 let file = db.source_file(frange.file_id); 57 let file = db.source_file(frange.file_id);
62 let syntax = file.syntax(); 58 let syntax = file.syntax();
63 let leaf_node = find_covering_node(syntax, frange.range); 59 let leaf_node = find_covering_node(syntax, frange.range);
@@ -67,34 +63,28 @@ pub(crate) fn type_of(db: &RootDatabase, frange: FileRange) -> Cancelable<Option
67 .take_while(|it| it.range() == leaf_node.range()) 63 .take_while(|it| it.range() == leaf_node.range())
68 .find(|&it| ast::Expr::cast(it).is_some() || ast::Pat::cast(it).is_some()) 64 .find(|&it| ast::Expr::cast(it).is_some() || ast::Pat::cast(it).is_some())
69 .unwrap_or(leaf_node); 65 .unwrap_or(leaf_node);
70 let parent_fn = ctry!(node.ancestors().find_map(ast::FnDef::cast)); 66 let parent_fn = node.ancestors().find_map(ast::FnDef::cast)?;
71 let function = ctry!(hir::source_binder::function_from_source( 67 let function = hir::source_binder::function_from_source(db, frange.file_id, parent_fn)?;
72 db,
73 frange.file_id,
74 parent_fn
75 ));
76 let infer = function.infer(db); 68 let infer = function.infer(db);
77 let syntax_mapping = function.body_syntax_mapping(db); 69 let syntax_mapping = function.body_syntax_mapping(db);
78 if let Some(expr) = ast::Expr::cast(node).and_then(|e| syntax_mapping.node_expr(e)) { 70 if let Some(expr) = ast::Expr::cast(node).and_then(|e| syntax_mapping.node_expr(e)) {
79 Ok(Some(infer[expr].to_string())) 71 Some(infer[expr].to_string())
80 } else if let Some(pat) = ast::Pat::cast(node).and_then(|p| syntax_mapping.node_pat(p)) { 72 } else if let Some(pat) = ast::Pat::cast(node).and_then(|p| syntax_mapping.node_pat(p)) {
81 Ok(Some(infer[pat].to_string())) 73 Some(infer[pat].to_string())
82 } else { 74 } else {
83 Ok(None) 75 None
84 } 76 }
85} 77}
86 78
87// FIXME: this should not really use navigation target. Rather, approximatelly 79// FIXME: this should not really use navigation target. Rather, approximatelly
88// resovled symbol should return a `DefId`. 80// resovled symbol should return a `DefId`.
89fn doc_text_for(db: &RootDatabase, nav: NavigationTarget) -> Cancelable<Option<String>> { 81fn doc_text_for(db: &RootDatabase, nav: NavigationTarget) -> Option<String> {
90 let result = match (nav.description(db), nav.docs(db)) { 82 match (nav.description(db), nav.docs(db)) {
91 (Some(desc), Some(docs)) => Some("```rust\n".to_string() + &*desc + "\n```\n\n" + &*docs), 83 (Some(desc), Some(docs)) => Some("```rust\n".to_string() + &*desc + "\n```\n\n" + &*docs),
92 (Some(desc), None) => Some("```rust\n".to_string() + &*desc + "\n```"), 84 (Some(desc), None) => Some("```rust\n".to_string() + &*desc + "\n```"),
93 (None, Some(docs)) => Some(docs), 85 (None, Some(docs)) => Some(docs),
94 _ => None, 86 _ => None,
95 }; 87 }
96
97 Ok(result)
98} 88}
99 89
100impl NavigationTarget { 90impl NavigationTarget {