aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_ide
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_ide')
-rw-r--r--crates/ra_ide/src/completion.rs78
-rw-r--r--crates/ra_ide/src/hover.rs127
2 files changed, 192 insertions, 13 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)]
130mod 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/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 @@
1use std::iter::once; 1use std::iter::once;
2 2
3use hir::{ 3use 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};
7use itertools::Itertools; 7use itertools::Itertools;
8use ra_db::SourceDatabase; 8use 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};
13use ra_syntax::{ 13use 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
20use crate::{ 15use 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}