aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/ide/src/runnables.rs70
1 files changed, 67 insertions, 3 deletions
diff --git a/crates/ide/src/runnables.rs b/crates/ide/src/runnables.rs
index eb82456ad..2bd0e86e5 100644
--- a/crates/ide/src/runnables.rs
+++ b/crates/ide/src/runnables.rs
@@ -102,6 +102,7 @@ pub(crate) fn runnable(
102) -> Option<Runnable> { 102) -> Option<Runnable> {
103 match_ast! { 103 match_ast! {
104 match item { 104 match item {
105 ast::Struct(it) => runnable_struct(sema, it, file_id),
105 ast::Fn(it) => runnable_fn(sema, it, file_id), 106 ast::Fn(it) => runnable_fn(sema, it, file_id),
106 ast::Module(it) => runnable_mod(sema, it, file_id), 107 ast::Module(it) => runnable_mod(sema, it, file_id),
107 _ => None, 108 _ => None,
@@ -182,6 +183,43 @@ fn runnable_fn(
182 Some(Runnable { nav, kind, cfg }) 183 Some(Runnable { nav, kind, cfg })
183} 184}
184 185
186fn runnable_struct(
187 sema: &Semantics<RootDatabase>,
188 struct_def: ast::Struct,
189 file_id: FileId,
190) -> Option<Runnable> {
191 if !has_runnable_doc_test(&struct_def) {
192 return None;
193 }
194 let name_string = struct_def.name()?.text().to_string();
195
196 let attrs =
197 Attrs::from_attrs_owner(sema.db, InFile::new(HirFileId::from(file_id), &struct_def));
198 let cfg = attrs.cfg();
199
200 let test_id = match sema.to_def(&struct_def).map(|def| def.module(sema.db)) {
201 Some(module) => {
202 let path_iter = module
203 .path_to_root(sema.db)
204 .into_iter()
205 .rev()
206 .filter_map(|it| it.name(sema.db))
207 .map(|name| name.to_string());
208 let path = path_iter.chain(std::iter::once(name_string)).join("::");
209
210 TestId::Path(path)
211 }
212 None => TestId::Name(name_string),
213 };
214
215 let nav = NavigationTarget::from_doc_commented(
216 sema.db,
217 InFile::new(file_id.into(), &struct_def),
218 InFile::new(file_id.into(), &struct_def),
219 );
220 Some(Runnable { nav, kind: RunnableKind::DocTest { test_id }, cfg })
221}
222
185#[derive(Debug, Copy, Clone)] 223#[derive(Debug, Copy, Clone)]
186pub struct TestAttr { 224pub struct TestAttr {
187 pub ignore: bool, 225 pub ignore: bool,
@@ -215,8 +253,8 @@ const RUSTDOC_FENCE: &str = "```";
215const RUSTDOC_CODE_BLOCK_ATTRIBUTES_RUNNABLE: &[&str] = 253const RUSTDOC_CODE_BLOCK_ATTRIBUTES_RUNNABLE: &[&str] =
216 &["", "rust", "should_panic", "edition2015", "edition2018"]; 254 &["", "rust", "should_panic", "edition2015", "edition2018"];
217 255
218fn has_runnable_doc_test(fn_def: &ast::Fn) -> bool { 256fn has_runnable_doc_test(def: &dyn DocCommentsOwner) -> bool {
219 fn_def.doc_comment_text().map_or(false, |comments_text| { 257 def.doc_comment_text().map_or(false, |comments_text| {
220 let mut in_code_block = false; 258 let mut in_code_block = false;
221 259
222 for line in comments_text.lines() { 260 for line in comments_text.lines() {
@@ -487,8 +525,14 @@ fn should_have_no_runnable_5() {}
487/// let z = 55; 525/// let z = 55;
488/// ``` 526/// ```
489fn should_have_no_runnable_6() {} 527fn should_have_no_runnable_6() {}
528
529/// ```
530/// let x = 5;
531/// ```
532struct StructWithRunnable(String);
533
490"#, 534"#,
491 &[&BIN, &DOCTEST, &DOCTEST, &DOCTEST], 535 &[&BIN, &DOCTEST, &DOCTEST, &DOCTEST, &DOCTEST],
492 expect![[r#" 536 expect![[r#"
493 [ 537 [
494 Runnable { 538 Runnable {
@@ -569,6 +613,26 @@ fn should_have_no_runnable_6() {}
569 }, 613 },
570 cfg: None, 614 cfg: None,
571 }, 615 },
616 Runnable {
617 nav: NavigationTarget {
618 file_id: FileId(
619 0,
620 ),
621 full_range: 756..821,
622 focus_range: None,
623 name: "StructWithRunnable",
624 kind: STRUCT,
625 container_name: None,
626 description: None,
627 docs: None,
628 },
629 kind: DocTest {
630 test_id: Path(
631 "StructWithRunnable",
632 ),
633 },
634 cfg: None,
635 },
572 ] 636 ]
573 "#]], 637 "#]],
574 ); 638 );