aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_ide/src/runnables.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_ide/src/runnables.rs')
-rw-r--r--crates/ra_ide/src/runnables.rs113
1 files changed, 108 insertions, 5 deletions
diff --git a/crates/ra_ide/src/runnables.rs b/crates/ra_ide/src/runnables.rs
index 38637c19c..131b8f307 100644
--- a/crates/ra_ide/src/runnables.rs
+++ b/crates/ra_ide/src/runnables.rs
@@ -1,6 +1,6 @@
1//! FIXME: write short doc here 1//! FIXME: write short doc here
2 2
3use hir::Semantics; 3use hir::{AsAssocItem, Semantics};
4use itertools::Itertools; 4use itertools::Itertools;
5use ra_ide_db::RootDatabase; 5use ra_ide_db::RootDatabase;
6use ra_syntax::{ 6use ra_syntax::{
@@ -9,6 +9,7 @@ use ra_syntax::{
9}; 9};
10 10
11use crate::FileId; 11use crate::FileId;
12use ast::DocCommentsOwner;
12use std::fmt::Display; 13use std::fmt::Display;
13 14
14#[derive(Debug)] 15#[derive(Debug)]
@@ -37,6 +38,7 @@ pub enum RunnableKind {
37 Test { test_id: TestId, attr: TestAttr }, 38 Test { test_id: TestId, attr: TestAttr },
38 TestMod { path: String }, 39 TestMod { path: String },
39 Bench { test_id: TestId }, 40 Bench { test_id: TestId },
41 DocTest { test_id: TestId },
40 Bin, 42 Bin,
41} 43}
42 44
@@ -63,14 +65,36 @@ fn runnable_fn(sema: &Semantics<RootDatabase>, fn_def: ast::FnDef) -> Option<Run
63 RunnableKind::Bin 65 RunnableKind::Bin
64 } else { 66 } else {
65 let test_id = if let Some(module) = sema.to_def(&fn_def).map(|def| def.module(sema.db)) { 67 let test_id = if let Some(module) = sema.to_def(&fn_def).map(|def| def.module(sema.db)) {
66 let path = module 68 let def = sema.to_def(&fn_def)?;
69 let impl_trait_name =
70 def.as_assoc_item(sema.db).and_then(|assoc_item| {
71 match assoc_item.container(sema.db) {
72 hir::AssocItemContainer::Trait(trait_item) => {
73 Some(trait_item.name(sema.db).to_string())
74 }
75 hir::AssocItemContainer::ImplDef(impl_def) => impl_def
76 .target_ty(sema.db)
77 .as_adt()
78 .map(|adt| adt.name(sema.db).to_string()),
79 }
80 });
81
82 let path_iter = module
67 .path_to_root(sema.db) 83 .path_to_root(sema.db)
68 .into_iter() 84 .into_iter()
69 .rev() 85 .rev()
70 .filter_map(|it| it.name(sema.db)) 86 .filter_map(|it| it.name(sema.db))
71 .map(|name| name.to_string()) 87 .map(|name| name.to_string());
72 .chain(std::iter::once(name_string)) 88
73 .join("::"); 89 let path = if let Some(impl_trait_name) = impl_trait_name {
90 path_iter
91 .chain(std::iter::once(impl_trait_name))
92 .chain(std::iter::once(name_string))
93 .join("::")
94 } else {
95 path_iter.chain(std::iter::once(name_string)).join("::")
96 };
97
74 TestId::Path(path) 98 TestId::Path(path)
75 } else { 99 } else {
76 TestId::Name(name_string) 100 TestId::Name(name_string)
@@ -81,6 +105,8 @@ fn runnable_fn(sema: &Semantics<RootDatabase>, fn_def: ast::FnDef) -> Option<Run
81 RunnableKind::Test { test_id, attr } 105 RunnableKind::Test { test_id, attr }
82 } else if fn_def.has_atom_attr("bench") { 106 } else if fn_def.has_atom_attr("bench") {
83 RunnableKind::Bench { test_id } 107 RunnableKind::Bench { test_id }
108 } else if has_doc_test(&fn_def) {
109 RunnableKind::DocTest { test_id }
84 } else { 110 } else {
85 return None; 111 return None;
86 } 112 }
@@ -117,6 +143,10 @@ fn has_test_related_attribute(fn_def: &ast::FnDef) -> bool {
117 .any(|attribute_text| attribute_text.contains("test")) 143 .any(|attribute_text| attribute_text.contains("test"))
118} 144}
119 145
146fn has_doc_test(fn_def: &ast::FnDef) -> bool {
147 fn_def.doc_comment_text().map_or(false, |comment| comment.contains("```"))
148}
149
120fn runnable_mod(sema: &Semantics<RootDatabase>, module: ast::Module) -> Option<Runnable> { 150fn runnable_mod(sema: &Semantics<RootDatabase>, module: ast::Module) -> Option<Runnable> {
121 let has_test_function = module 151 let has_test_function = module
122 .item_list()? 152 .item_list()?
@@ -195,6 +225,79 @@ mod tests {
195 } 225 }
196 226
197 #[test] 227 #[test]
228 fn test_runnables_doc_test() {
229 let (analysis, pos) = analysis_and_position(
230 r#"
231 //- /lib.rs
232 <|> //empty
233 fn main() {}
234
235 /// ```
236 /// let x = 5;
237 /// ```
238 fn foo() {}
239 "#,
240 );
241 let runnables = analysis.runnables(pos.file_id).unwrap();
242 assert_debug_snapshot!(&runnables,
243 @r###"
244 [
245 Runnable {
246 range: 1..21,
247 kind: Bin,
248 },
249 Runnable {
250 range: 22..64,
251 kind: DocTest {
252 test_id: Path(
253 "foo",
254 ),
255 },
256 },
257 ]
258 "###
259 );
260 }
261
262 #[test]
263 fn test_runnables_doc_test_in_impl() {
264 let (analysis, pos) = analysis_and_position(
265 r#"
266 //- /lib.rs
267 <|> //empty
268 fn main() {}
269
270 struct Data;
271 impl Data {
272 /// ```
273 /// let x = 5;
274 /// ```
275 fn foo() {}
276 }
277 "#,
278 );
279 let runnables = analysis.runnables(pos.file_id).unwrap();
280 assert_debug_snapshot!(&runnables,
281 @r###"
282 [
283 Runnable {
284 range: 1..21,
285 kind: Bin,
286 },
287 Runnable {
288 range: 51..105,
289 kind: DocTest {
290 test_id: Path(
291 "Data::foo",
292 ),
293 },
294 },
295 ]
296 "###
297 );
298 }
299
300 #[test]
198 fn test_runnables_module() { 301 fn test_runnables_module() {
199 let (analysis, pos) = analysis_and_position( 302 let (analysis, pos) = analysis_and_position(
200 r#" 303 r#"