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.rs43
1 files changed, 31 insertions, 12 deletions
diff --git a/crates/ra_ide_api/src/hover.rs b/crates/ra_ide_api/src/hover.rs
index 1a1853df3..8ec60090d 100644
--- a/crates/ra_ide_api/src/hover.rs
+++ b/crates/ra_ide_api/src/hover.rs
@@ -107,7 +107,7 @@ pub(crate) fn hover(db: &RootDatabase, position: FilePosition) -> Option<RangeIn
107 leaf.ancestors().find(|n| ast::Expr::cast(*n).is_some() || ast::Pat::cast(*n).is_some()) 107 leaf.ancestors().find(|n| ast::Expr::cast(*n).is_some() || ast::Pat::cast(*n).is_some())
108 })?; 108 })?;
109 let frange = FileRange { file_id: position.file_id, range: node.range() }; 109 let frange = FileRange { file_id: position.file_id, range: node.range() };
110 res.extend(type_of(db, frange).map(Into::into)); 110 res.extend(type_of(db, frange).map(rust_code_markup));
111 range = Some(node.range()); 111 range = Some(node.range());
112 } 112 }
113 113
@@ -132,22 +132,37 @@ pub(crate) fn type_of(db: &RootDatabase, frange: FileRange) -> Option<String> {
132 let parent_fn = node.ancestors().find_map(ast::FnDef::cast)?; 132 let parent_fn = node.ancestors().find_map(ast::FnDef::cast)?;
133 let function = hir::source_binder::function_from_source(db, frange.file_id, parent_fn)?; 133 let function = hir::source_binder::function_from_source(db, frange.file_id, parent_fn)?;
134 let infer = function.infer(db); 134 let infer = function.infer(db);
135 let syntax_mapping = function.body_syntax_mapping(db); 135 let source_map = function.body_source_map(db);
136 if let Some(expr) = ast::Expr::cast(node).and_then(|e| syntax_mapping.node_expr(e)) { 136 if let Some(expr) = ast::Expr::cast(node).and_then(|e| source_map.node_expr(e)) {
137 Some(infer[expr].to_string()) 137 Some(infer[expr].to_string())
138 } else if let Some(pat) = ast::Pat::cast(node).and_then(|p| syntax_mapping.node_pat(p)) { 138 } else if let Some(pat) = ast::Pat::cast(node).and_then(|p| source_map.node_pat(p)) {
139 Some(infer[pat].to_string()) 139 Some(infer[pat].to_string())
140 } else { 140 } else {
141 None 141 None
142 } 142 }
143} 143}
144 144
145fn rust_code_markup<CODE: AsRef<str>>(val: CODE) -> String {
146 rust_code_markup_with_doc::<_, &str>(val, None)
147}
148
149fn rust_code_markup_with_doc<CODE, DOC>(val: CODE, doc: Option<DOC>) -> String
150where
151 CODE: AsRef<str>,
152 DOC: AsRef<str>,
153{
154 if let Some(doc) = doc {
155 format!("```rust\n{}\n```\n\n{}", val.as_ref(), doc.as_ref())
156 } else {
157 format!("```rust\n{}\n```", val.as_ref())
158 }
159}
160
145// FIXME: this should not really use navigation target. Rather, approximately 161// FIXME: this should not really use navigation target. Rather, approximately
146// resolved symbol should return a `DefId`. 162// resolved symbol should return a `DefId`.
147fn doc_text_for(db: &RootDatabase, nav: NavigationTarget) -> Option<String> { 163fn doc_text_for(db: &RootDatabase, nav: NavigationTarget) -> Option<String> {
148 match (nav.description(db), nav.docs(db)) { 164 match (nav.description(db), nav.docs(db)) {
149 (Some(desc), Some(docs)) => Some("```rust\n".to_string() + &*desc + "\n```\n\n" + &*docs), 165 (Some(desc), docs) => Some(rust_code_markup_with_doc(desc, docs)),
150 (Some(desc), None) => Some("```rust\n".to_string() + &*desc + "\n```"),
151 (None, Some(docs)) => Some(docs), 166 (None, Some(docs)) => Some(docs),
152 _ => None, 167 _ => None,
153 } 168 }
@@ -238,6 +253,10 @@ mod tests {
238 s.trim_start_matches("```rust\n").trim_end_matches("\n```") 253 s.trim_start_matches("```rust\n").trim_end_matches("\n```")
239 } 254 }
240 255
256 fn trim_markup_opt(s: Option<&str>) -> Option<&str> {
257 s.map(trim_markup)
258 }
259
241 fn check_hover_result(fixture: &str, expected: &[&str]) { 260 fn check_hover_result(fixture: &str, expected: &[&str]) {
242 let (analysis, position) = analysis_and_position(fixture); 261 let (analysis, position) = analysis_and_position(fixture);
243 let hover = analysis.hover(position).unwrap().unwrap(); 262 let hover = analysis.hover(position).unwrap().unwrap();
@@ -264,7 +283,7 @@ mod tests {
264 ); 283 );
265 let hover = analysis.hover(position).unwrap().unwrap(); 284 let hover = analysis.hover(position).unwrap().unwrap();
266 assert_eq!(hover.range, TextRange::from_to(95.into(), 100.into())); 285 assert_eq!(hover.range, TextRange::from_to(95.into(), 100.into()));
267 assert_eq!(hover.info.first(), Some("u32")); 286 assert_eq!(trim_markup_opt(hover.info.first()), Some("u32"));
268 } 287 }
269 288
270 #[test] 289 #[test]
@@ -410,21 +429,21 @@ mod tests {
410 ); 429 );
411 let hover = analysis.hover(position).unwrap().unwrap(); 430 let hover = analysis.hover(position).unwrap().unwrap();
412 // not the nicest way to show it currently 431 // not the nicest way to show it currently
413 assert_eq!(hover.info.first(), Some("Some<i32>(T) -> Option<T>")); 432 assert_eq!(trim_markup_opt(hover.info.first()), Some("Some<i32>(T) -> Option<T>"));
414 } 433 }
415 434
416 #[test] 435 #[test]
417 fn hover_for_local_variable() { 436 fn hover_for_local_variable() {
418 let (analysis, position) = single_file_with_position("fn func(foo: i32) { fo<|>o; }"); 437 let (analysis, position) = single_file_with_position("fn func(foo: i32) { fo<|>o; }");
419 let hover = analysis.hover(position).unwrap().unwrap(); 438 let hover = analysis.hover(position).unwrap().unwrap();
420 assert_eq!(hover.info.first(), Some("i32")); 439 assert_eq!(trim_markup_opt(hover.info.first()), Some("i32"));
421 } 440 }
422 441
423 #[test] 442 #[test]
424 fn hover_for_local_variable_pat() { 443 fn hover_for_local_variable_pat() {
425 let (analysis, position) = single_file_with_position("fn func(fo<|>o: i32) {}"); 444 let (analysis, position) = single_file_with_position("fn func(fo<|>o: i32) {}");
426 let hover = analysis.hover(position).unwrap().unwrap(); 445 let hover = analysis.hover(position).unwrap().unwrap();
427 assert_eq!(hover.info.first(), Some("i32")); 446 assert_eq!(trim_markup_opt(hover.info.first()), Some("i32"));
428 } 447 }
429 448
430 #[test] 449 #[test]
@@ -455,7 +474,7 @@ mod tests {
455 ); 474 );
456 475
457 let type_name = analysis.type_of(range).unwrap().unwrap(); 476 let type_name = analysis.type_of(range).unwrap().unwrap();
458 assert_eq!("[unknown]", &type_name); 477 assert_eq!("{unknown}", &type_name);
459 } 478 }
460 479
461 #[test] 480 #[test]
@@ -491,6 +510,6 @@ mod tests {
491 ", 510 ",
492 ); 511 );
493 let hover = analysis.hover(position).unwrap().unwrap(); 512 let hover = analysis.hover(position).unwrap().unwrap();
494 assert_eq!(hover.info.first(), Some("Thing")); 513 assert_eq!(trim_markup_opt(hover.info.first()), Some("Thing"));
495 } 514 }
496} 515}