diff options
Diffstat (limited to 'crates/ra_ide/src/hover.rs')
-rw-r--r-- | crates/ra_ide/src/hover.rs | 63 |
1 files changed, 45 insertions, 18 deletions
diff --git a/crates/ra_ide/src/hover.rs b/crates/ra_ide/src/hover.rs index 3f88bb260..1c6ca36df 100644 --- a/crates/ra_ide/src/hover.rs +++ b/crates/ra_ide/src/hover.rs | |||
@@ -2,7 +2,7 @@ | |||
2 | 2 | ||
3 | use hir::{db::AstDatabase, Adt, HasSource, HirDisplay, SourceBinder}; | 3 | use hir::{db::AstDatabase, Adt, HasSource, HirDisplay, SourceBinder}; |
4 | use ra_db::SourceDatabase; | 4 | use ra_db::SourceDatabase; |
5 | use ra_ide_db::RootDatabase; | 5 | use ra_ide_db::{defs::NameDefinition, RootDatabase}; |
6 | use ra_syntax::{ | 6 | use ra_syntax::{ |
7 | algo::find_covering_element, | 7 | algo::find_covering_element, |
8 | ast::{self, DocCommentsOwner}, | 8 | ast::{self, DocCommentsOwner}, |
@@ -13,8 +13,8 @@ use ra_syntax::{ | |||
13 | 13 | ||
14 | use crate::{ | 14 | use crate::{ |
15 | display::{macro_label, rust_code_markup, rust_code_markup_with_doc, ShortLabel}, | 15 | display::{macro_label, rust_code_markup, rust_code_markup_with_doc, ShortLabel}, |
16 | expand::descend_into_macros, | 16 | expand::{descend_into_macros, original_range}, |
17 | references::{classify_name, classify_name_ref, NameKind, NameKind::*}, | 17 | references::{classify_name, classify_name_ref}, |
18 | FilePosition, FileRange, RangeInfo, | 18 | FilePosition, FileRange, RangeInfo, |
19 | }; | 19 | }; |
20 | 20 | ||
@@ -92,20 +92,20 @@ fn hover_text(docs: Option<String>, desc: Option<String>) -> Option<String> { | |||
92 | } | 92 | } |
93 | } | 93 | } |
94 | 94 | ||
95 | fn hover_text_from_name_kind(db: &RootDatabase, name_kind: NameKind) -> Option<String> { | 95 | fn hover_text_from_name_kind(db: &RootDatabase, def: NameDefinition) -> Option<String> { |
96 | return match name_kind { | 96 | return match def { |
97 | Macro(it) => { | 97 | NameDefinition::Macro(it) => { |
98 | let src = it.source(db); | 98 | let src = it.source(db); |
99 | hover_text(src.value.doc_comment_text(), Some(macro_label(&src.value))) | 99 | hover_text(src.value.doc_comment_text(), Some(macro_label(&src.value))) |
100 | } | 100 | } |
101 | StructField(it) => { | 101 | NameDefinition::StructField(it) => { |
102 | let src = it.source(db); | 102 | let src = it.source(db); |
103 | match src.value { | 103 | match src.value { |
104 | hir::FieldSource::Named(it) => hover_text(it.doc_comment_text(), it.short_label()), | 104 | hir::FieldSource::Named(it) => hover_text(it.doc_comment_text(), it.short_label()), |
105 | _ => None, | 105 | _ => None, |
106 | } | 106 | } |
107 | } | 107 | } |
108 | ModuleDef(it) => match it { | 108 | NameDefinition::ModuleDef(it) => match it { |
109 | hir::ModuleDef::Module(it) => match it.definition_source(db).value { | 109 | hir::ModuleDef::Module(it) => match it.definition_source(db).value { |
110 | hir::ModuleSource::Module(it) => { | 110 | hir::ModuleSource::Module(it) => { |
111 | hover_text(it.doc_comment_text(), it.short_label()) | 111 | hover_text(it.doc_comment_text(), it.short_label()) |
@@ -123,8 +123,10 @@ fn hover_text_from_name_kind(db: &RootDatabase, name_kind: NameKind) -> Option<S | |||
123 | hir::ModuleDef::TypeAlias(it) => from_def_source(db, it), | 123 | hir::ModuleDef::TypeAlias(it) => from_def_source(db, it), |
124 | hir::ModuleDef::BuiltinType(it) => Some(it.to_string()), | 124 | hir::ModuleDef::BuiltinType(it) => Some(it.to_string()), |
125 | }, | 125 | }, |
126 | Local(it) => Some(rust_code_markup(it.ty(db).display_truncated(db, None).to_string())), | 126 | NameDefinition::Local(it) => { |
127 | TypeParam(_) | SelfType(_) => { | 127 | Some(rust_code_markup(it.ty(db).display_truncated(db, None).to_string())) |
128 | } | ||
129 | NameDefinition::TypeParam(_) | NameDefinition::SelfType(_) => { | ||
128 | // FIXME: Hover for generic param | 130 | // FIXME: Hover for generic param |
129 | None | 131 | None |
130 | } | 132 | } |
@@ -148,17 +150,18 @@ pub(crate) fn hover(db: &RootDatabase, position: FilePosition) -> Option<RangeIn | |||
148 | let mut res = HoverResult::new(); | 150 | let mut res = HoverResult::new(); |
149 | 151 | ||
150 | let mut sb = SourceBinder::new(db); | 152 | let mut sb = SourceBinder::new(db); |
151 | if let Some((range, name_kind)) = match_ast! { | 153 | if let Some((node, name_kind)) = match_ast! { |
152 | match (token.value.parent()) { | 154 | match (token.value.parent()) { |
153 | ast::NameRef(name_ref) => { | 155 | ast::NameRef(name_ref) => { |
154 | classify_name_ref(&mut sb, token.with_value(&name_ref)).map(|d| (name_ref.syntax().text_range(), d.kind)) | 156 | classify_name_ref(&mut sb, token.with_value(&name_ref)).map(|d| (name_ref.syntax().clone(), d)) |
155 | }, | 157 | }, |
156 | ast::Name(name) => { | 158 | ast::Name(name) => { |
157 | classify_name(&mut sb, token.with_value(&name)).map(|d| (name.syntax().text_range(), d.kind)) | 159 | classify_name(&mut sb, token.with_value(&name)).map(|d| (name.syntax().clone(), d)) |
158 | }, | 160 | }, |
159 | _ => None, | 161 | _ => None, |
160 | } | 162 | } |
161 | } { | 163 | } { |
164 | let range = original_range(db, token.with_value(&node)).range; | ||
162 | res.extend(hover_text_from_name_kind(db, name_kind)); | 165 | res.extend(hover_text_from_name_kind(db, name_kind)); |
163 | 166 | ||
164 | if !res.is_empty() { | 167 | if !res.is_empty() { |
@@ -171,8 +174,7 @@ pub(crate) fn hover(db: &RootDatabase, position: FilePosition) -> Option<RangeIn | |||
171 | .ancestors() | 174 | .ancestors() |
172 | .find(|n| ast::Expr::cast(n.clone()).is_some() || ast::Pat::cast(n.clone()).is_some())?; | 175 | .find(|n| ast::Expr::cast(n.clone()).is_some() || ast::Pat::cast(n.clone()).is_some())?; |
173 | 176 | ||
174 | // The following logic will not work if token is coming from a macro | 177 | let frange = original_range(db, token.with_value(&node)); |
175 | let frange = FileRange { file_id: position.file_id, range: node.text_range() }; | ||
176 | res.extend(type_of(db, frange).map(rust_code_markup)); | 178 | res.extend(type_of(db, frange).map(rust_code_markup)); |
177 | if res.is_empty() { | 179 | if res.is_empty() { |
178 | return None; | 180 | return None; |
@@ -220,6 +222,7 @@ mod tests { | |||
220 | use crate::mock_analysis::{ | 222 | use crate::mock_analysis::{ |
221 | analysis_and_position, single_file_with_position, single_file_with_range, | 223 | analysis_and_position, single_file_with_position, single_file_with_range, |
222 | }; | 224 | }; |
225 | use ra_db::FileLoader; | ||
223 | use ra_syntax::TextRange; | 226 | use ra_syntax::TextRange; |
224 | 227 | ||
225 | fn trim_markup(s: &str) -> &str { | 228 | fn trim_markup(s: &str) -> &str { |
@@ -230,7 +233,7 @@ mod tests { | |||
230 | s.map(trim_markup) | 233 | s.map(trim_markup) |
231 | } | 234 | } |
232 | 235 | ||
233 | fn check_hover_result(fixture: &str, expected: &[&str]) { | 236 | fn check_hover_result(fixture: &str, expected: &[&str]) -> String { |
234 | let (analysis, position) = analysis_and_position(fixture); | 237 | let (analysis, position) = analysis_and_position(fixture); |
235 | let hover = analysis.hover(position).unwrap().unwrap(); | 238 | let hover = analysis.hover(position).unwrap().unwrap(); |
236 | let mut results = Vec::from(hover.info.results()); | 239 | let mut results = Vec::from(hover.info.results()); |
@@ -243,6 +246,9 @@ mod tests { | |||
243 | } | 246 | } |
244 | 247 | ||
245 | assert_eq!(hover.info.len(), expected.len()); | 248 | assert_eq!(hover.info.len(), expected.len()); |
249 | |||
250 | let content = analysis.db.file_text(position.file_id); | ||
251 | content[hover.range].to_string() | ||
246 | } | 252 | } |
247 | 253 | ||
248 | #[test] | 254 | #[test] |
@@ -711,7 +717,7 @@ fn func(foo: i32) { if true { <|>foo; }; } | |||
711 | 717 | ||
712 | #[test] | 718 | #[test] |
713 | fn test_hover_through_macro() { | 719 | fn test_hover_through_macro() { |
714 | check_hover_result( | 720 | let hover_on = check_hover_result( |
715 | " | 721 | " |
716 | //- /lib.rs | 722 | //- /lib.rs |
717 | macro_rules! id { | 723 | macro_rules! id { |
@@ -726,11 +732,13 @@ fn func(foo: i32) { if true { <|>foo; }; } | |||
726 | ", | 732 | ", |
727 | &["fn foo()"], | 733 | &["fn foo()"], |
728 | ); | 734 | ); |
735 | |||
736 | assert_eq!(hover_on, "foo") | ||
729 | } | 737 | } |
730 | 738 | ||
731 | #[test] | 739 | #[test] |
732 | fn test_hover_through_expr_in_macro() { | 740 | fn test_hover_through_expr_in_macro() { |
733 | check_hover_result( | 741 | let hover_on = check_hover_result( |
734 | " | 742 | " |
735 | //- /lib.rs | 743 | //- /lib.rs |
736 | macro_rules! id { | 744 | macro_rules! id { |
@@ -742,5 +750,24 @@ fn func(foo: i32) { if true { <|>foo; }; } | |||
742 | ", | 750 | ", |
743 | &["u32"], | 751 | &["u32"], |
744 | ); | 752 | ); |
753 | |||
754 | assert_eq!(hover_on, "bar") | ||
755 | } | ||
756 | |||
757 | #[test] | ||
758 | fn test_hover_non_ascii_space_doc() { | ||
759 | check_hover_result( | ||
760 | " | ||
761 | //- /lib.rs | ||
762 | /// <- `\u{3000}` here | ||
763 | fn foo() { | ||
764 | } | ||
765 | |||
766 | fn bar() { | ||
767 | fo<|>o(); | ||
768 | } | ||
769 | ", | ||
770 | &["fn foo()\n```\n\n<- `\u{3000}` here"], | ||
771 | ); | ||
745 | } | 772 | } |
746 | } | 773 | } |