diff options
Diffstat (limited to 'crates/ra_ide/src')
-rw-r--r-- | crates/ra_ide/src/completion.rs | 78 | ||||
-rw-r--r-- | crates/ra_ide/src/display/function_signature.rs | 13 | ||||
-rw-r--r-- | crates/ra_ide/src/hover.rs | 127 |
3 files changed, 203 insertions, 15 deletions
diff --git a/crates/ra_ide/src/completion.rs b/crates/ra_ide/src/completion.rs index d890b69d2..a721e23c6 100644 --- a/crates/ra_ide/src/completion.rs +++ b/crates/ra_ide/src/completion.rs | |||
@@ -125,3 +125,81 @@ pub(crate) fn completions( | |||
125 | 125 | ||
126 | Some(acc) | 126 | Some(acc) |
127 | } | 127 | } |
128 | |||
129 | #[cfg(test)] | ||
130 | mod tests { | ||
131 | use crate::completion::completion_config::CompletionConfig; | ||
132 | use crate::mock_analysis::analysis_and_position; | ||
133 | |||
134 | struct DetailAndDocumentation<'a> { | ||
135 | detail: &'a str, | ||
136 | documentation: &'a str, | ||
137 | } | ||
138 | |||
139 | fn check_detail_and_documentation(fixture: &str, expected: DetailAndDocumentation) { | ||
140 | let (analysis, position) = analysis_and_position(fixture); | ||
141 | let config = CompletionConfig::default(); | ||
142 | let completions = analysis.completions(&config, position).unwrap().unwrap(); | ||
143 | for item in completions { | ||
144 | if item.detail() == Some(expected.detail) { | ||
145 | let opt = item.documentation(); | ||
146 | let doc = opt.as_ref().map(|it| it.as_str()); | ||
147 | assert_eq!(doc, Some(expected.documentation)); | ||
148 | return; | ||
149 | } | ||
150 | } | ||
151 | panic!("completion detail not found: {}", expected.detail) | ||
152 | } | ||
153 | |||
154 | #[test] | ||
155 | fn test_completion_detail_from_macro_generated_struct_fn_doc_attr() { | ||
156 | check_detail_and_documentation( | ||
157 | r#" | ||
158 | //- /lib.rs | ||
159 | macro_rules! bar { | ||
160 | () => { | ||
161 | struct Bar; | ||
162 | impl Bar { | ||
163 | #[doc = "Do the foo"] | ||
164 | fn foo(&self) {} | ||
165 | } | ||
166 | } | ||
167 | } | ||
168 | |||
169 | bar!(); | ||
170 | |||
171 | fn foo() { | ||
172 | let bar = Bar; | ||
173 | bar.fo<|>; | ||
174 | } | ||
175 | "#, | ||
176 | DetailAndDocumentation { detail: "fn foo(&self)", documentation: "Do the foo" }, | ||
177 | ); | ||
178 | } | ||
179 | |||
180 | #[test] | ||
181 | fn test_completion_detail_from_macro_generated_struct_fn_doc_comment() { | ||
182 | check_detail_and_documentation( | ||
183 | r#" | ||
184 | //- /lib.rs | ||
185 | macro_rules! bar { | ||
186 | () => { | ||
187 | struct Bar; | ||
188 | impl Bar { | ||
189 | /// Do the foo | ||
190 | fn foo(&self) {} | ||
191 | } | ||
192 | } | ||
193 | } | ||
194 | |||
195 | bar!(); | ||
196 | |||
197 | fn foo() { | ||
198 | let bar = Bar; | ||
199 | bar.fo<|>; | ||
200 | } | ||
201 | "#, | ||
202 | DetailAndDocumentation { detail: "fn foo(&self)", documentation: " Do the foo" }, | ||
203 | ); | ||
204 | } | ||
205 | } | ||
diff --git a/crates/ra_ide/src/display/function_signature.rs b/crates/ra_ide/src/display/function_signature.rs index 9572debd8..ca8a6a650 100644 --- a/crates/ra_ide/src/display/function_signature.rs +++ b/crates/ra_ide/src/display/function_signature.rs | |||
@@ -10,7 +10,7 @@ use std::{ | |||
10 | use hir::{Docs, Documentation, HasSource, HirDisplay}; | 10 | use hir::{Docs, Documentation, HasSource, HirDisplay}; |
11 | use ra_ide_db::RootDatabase; | 11 | use ra_ide_db::RootDatabase; |
12 | use ra_syntax::ast::{self, AstNode, NameOwner, VisibilityOwner}; | 12 | use ra_syntax::ast::{self, AstNode, NameOwner, VisibilityOwner}; |
13 | use stdx::SepBy; | 13 | use stdx::{split1, SepBy}; |
14 | 14 | ||
15 | use crate::display::{generic_parameters, where_predicates}; | 15 | use crate::display::{generic_parameters, where_predicates}; |
16 | 16 | ||
@@ -207,7 +207,16 @@ impl From<&'_ ast::FnDef> for FunctionSignature { | |||
207 | res.push(raw_param); | 207 | res.push(raw_param); |
208 | } | 208 | } |
209 | 209 | ||
210 | res.extend(param_list.params().map(|param| param.syntax().text().to_string())); | 210 | // macro-generated functions are missing whitespace |
211 | fn fmt_param(param: ast::Param) -> String { | ||
212 | let text = param.syntax().text().to_string(); | ||
213 | match split1(&text, ':') { | ||
214 | Some((left, right)) => format!("{}: {}", left.trim(), right.trim()), | ||
215 | _ => text, | ||
216 | } | ||
217 | } | ||
218 | |||
219 | res.extend(param_list.params().map(fmt_param)); | ||
211 | res_types.extend(param_list.params().map(|param| { | 220 | res_types.extend(param_list.params().map(|param| { |
212 | let param_text = param.syntax().text().to_string(); | 221 | let param_text = param.syntax().text().to_string(); |
213 | match param_text.split(':').nth(1).and_then(|it| it.get(1..)) { | 222 | match param_text.split(':').nth(1).and_then(|it| it.get(1..)) { |
diff --git a/crates/ra_ide/src/hover.rs b/crates/ra_ide/src/hover.rs index d96cb5596..9636cd0d6 100644 --- a/crates/ra_ide/src/hover.rs +++ b/crates/ra_ide/src/hover.rs | |||
@@ -1,8 +1,8 @@ | |||
1 | use std::iter::once; | 1 | use std::iter::once; |
2 | 2 | ||
3 | use hir::{ | 3 | use hir::{ |
4 | Adt, AsAssocItem, AssocItemContainer, FieldSource, HasSource, HirDisplay, ModuleDef, | 4 | Adt, AsAssocItem, AssocItemContainer, Documentation, FieldSource, HasSource, HirDisplay, |
5 | ModuleSource, Semantics, | 5 | ModuleDef, ModuleSource, Semantics, |
6 | }; | 6 | }; |
7 | use itertools::Itertools; | 7 | use itertools::Itertools; |
8 | use ra_db::SourceDatabase; | 8 | use ra_db::SourceDatabase; |
@@ -10,12 +10,7 @@ use ra_ide_db::{ | |||
10 | defs::{classify_name, classify_name_ref, Definition}, | 10 | defs::{classify_name, classify_name_ref, Definition}, |
11 | RootDatabase, | 11 | RootDatabase, |
12 | }; | 12 | }; |
13 | use ra_syntax::{ | 13 | use ra_syntax::{ast, match_ast, AstNode, SyntaxKind::*, SyntaxToken, TokenAtOffset}; |
14 | ast::{self, DocCommentsOwner}, | ||
15 | match_ast, AstNode, | ||
16 | SyntaxKind::*, | ||
17 | SyntaxToken, TokenAtOffset, | ||
18 | }; | ||
19 | 14 | ||
20 | use crate::{ | 15 | use crate::{ |
21 | display::{macro_label, rust_code_markup, rust_code_markup_with_doc, ShortLabel}, | 16 | display::{macro_label, rust_code_markup, rust_code_markup_with_doc, ShortLabel}, |
@@ -169,13 +164,15 @@ fn hover_text_from_name_kind(db: &RootDatabase, def: Definition) -> Option<Strin | |||
169 | return match def { | 164 | return match def { |
170 | Definition::Macro(it) => { | 165 | Definition::Macro(it) => { |
171 | let src = it.source(db); | 166 | let src = it.source(db); |
172 | hover_text(src.value.doc_comment_text(), Some(macro_label(&src.value)), mod_path) | 167 | let docs = Documentation::from_ast(&src.value).map(Into::into); |
168 | hover_text(docs, Some(macro_label(&src.value)), mod_path) | ||
173 | } | 169 | } |
174 | Definition::Field(it) => { | 170 | Definition::Field(it) => { |
175 | let src = it.source(db); | 171 | let src = it.source(db); |
176 | match src.value { | 172 | match src.value { |
177 | FieldSource::Named(it) => { | 173 | FieldSource::Named(it) => { |
178 | hover_text(it.doc_comment_text(), it.short_label(), mod_path) | 174 | let docs = Documentation::from_ast(&it).map(Into::into); |
175 | hover_text(docs, it.short_label(), mod_path) | ||
179 | } | 176 | } |
180 | _ => None, | 177 | _ => None, |
181 | } | 178 | } |
@@ -183,7 +180,8 @@ fn hover_text_from_name_kind(db: &RootDatabase, def: Definition) -> Option<Strin | |||
183 | Definition::ModuleDef(it) => match it { | 180 | Definition::ModuleDef(it) => match it { |
184 | ModuleDef::Module(it) => match it.definition_source(db).value { | 181 | ModuleDef::Module(it) => match it.definition_source(db).value { |
185 | ModuleSource::Module(it) => { | 182 | ModuleSource::Module(it) => { |
186 | hover_text(it.doc_comment_text(), it.short_label(), mod_path) | 183 | let docs = Documentation::from_ast(&it).map(Into::into); |
184 | hover_text(docs, it.short_label(), mod_path) | ||
187 | } | 185 | } |
188 | _ => None, | 186 | _ => None, |
189 | }, | 187 | }, |
@@ -208,10 +206,11 @@ fn hover_text_from_name_kind(db: &RootDatabase, def: Definition) -> Option<Strin | |||
208 | fn from_def_source<A, D>(db: &RootDatabase, def: D, mod_path: Option<String>) -> Option<String> | 206 | fn from_def_source<A, D>(db: &RootDatabase, def: D, mod_path: Option<String>) -> Option<String> |
209 | where | 207 | where |
210 | D: HasSource<Ast = A>, | 208 | D: HasSource<Ast = A>, |
211 | A: ast::DocCommentsOwner + ast::NameOwner + ShortLabel, | 209 | A: ast::DocCommentsOwner + ast::NameOwner + ShortLabel + ast::AttrsOwner, |
212 | { | 210 | { |
213 | let src = def.source(db); | 211 | let src = def.source(db); |
214 | hover_text(src.value.doc_comment_text(), src.value.short_label(), mod_path) | 212 | let docs = Documentation::from_ast(&src.value).map(Into::into); |
213 | hover_text(docs, src.value.short_label(), mod_path) | ||
215 | } | 214 | } |
216 | } | 215 | } |
217 | 216 | ||
@@ -951,4 +950,106 @@ fn func(foo: i32) { if true { <|>foo; }; } | |||
951 | &["mod my"], | 950 | &["mod my"], |
952 | ); | 951 | ); |
953 | } | 952 | } |
953 | |||
954 | #[test] | ||
955 | fn test_hover_struct_doc_comment() { | ||
956 | check_hover_result( | ||
957 | r#" | ||
958 | //- /lib.rs | ||
959 | /// bar docs | ||
960 | struct Bar; | ||
961 | |||
962 | fn foo() { | ||
963 | let bar = Ba<|>r; | ||
964 | } | ||
965 | "#, | ||
966 | &["struct Bar\n```\n___\n\nbar docs"], | ||
967 | ); | ||
968 | } | ||
969 | |||
970 | #[test] | ||
971 | fn test_hover_struct_doc_attr() { | ||
972 | check_hover_result( | ||
973 | r#" | ||
974 | //- /lib.rs | ||
975 | #[doc = "bar docs"] | ||
976 | struct Bar; | ||
977 | |||
978 | fn foo() { | ||
979 | let bar = Ba<|>r; | ||
980 | } | ||
981 | "#, | ||
982 | &["struct Bar\n```\n___\n\nbar docs"], | ||
983 | ); | ||
984 | } | ||
985 | |||
986 | #[test] | ||
987 | fn test_hover_struct_doc_attr_multiple_and_mixed() { | ||
988 | check_hover_result( | ||
989 | r#" | ||
990 | //- /lib.rs | ||
991 | /// bar docs 0 | ||
992 | #[doc = "bar docs 1"] | ||
993 | #[doc = "bar docs 2"] | ||
994 | struct Bar; | ||
995 | |||
996 | fn foo() { | ||
997 | let bar = Ba<|>r; | ||
998 | } | ||
999 | "#, | ||
1000 | &["struct Bar\n```\n___\n\nbar docs 0\n\nbar docs 1\n\nbar docs 2"], | ||
1001 | ); | ||
1002 | } | ||
1003 | |||
1004 | #[test] | ||
1005 | fn test_hover_macro_generated_struct_fn_doc_comment() { | ||
1006 | check_hover_result( | ||
1007 | r#" | ||
1008 | //- /lib.rs | ||
1009 | macro_rules! bar { | ||
1010 | () => { | ||
1011 | struct Bar; | ||
1012 | impl Bar { | ||
1013 | /// Do the foo | ||
1014 | fn foo(&self) {} | ||
1015 | } | ||
1016 | } | ||
1017 | } | ||
1018 | |||
1019 | bar!(); | ||
1020 | |||
1021 | fn foo() { | ||
1022 | let bar = Bar; | ||
1023 | bar.fo<|>o(); | ||
1024 | } | ||
1025 | "#, | ||
1026 | &["Bar\n```\n\n```rust\nfn foo(&self)\n```\n___\n\n Do the foo"], | ||
1027 | ); | ||
1028 | } | ||
1029 | |||
1030 | #[test] | ||
1031 | fn test_hover_macro_generated_struct_fn_doc_attr() { | ||
1032 | check_hover_result( | ||
1033 | r#" | ||
1034 | //- /lib.rs | ||
1035 | macro_rules! bar { | ||
1036 | () => { | ||
1037 | struct Bar; | ||
1038 | impl Bar { | ||
1039 | #[doc = "Do the foo"] | ||
1040 | fn foo(&self) {} | ||
1041 | } | ||
1042 | } | ||
1043 | } | ||
1044 | |||
1045 | bar!(); | ||
1046 | |||
1047 | fn foo() { | ||
1048 | let bar = Bar; | ||
1049 | bar.fo<|>o(); | ||
1050 | } | ||
1051 | "#, | ||
1052 | &["Bar\n```\n\n```rust\nfn foo(&self)\n```\n___\n\nDo the foo"], | ||
1053 | ); | ||
1054 | } | ||
954 | } | 1055 | } |