diff options
-rw-r--r-- | crates/ide/src/runnables.rs | 70 |
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 | ||
186 | fn 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)] |
186 | pub struct TestAttr { | 224 | pub struct TestAttr { |
187 | pub ignore: bool, | 225 | pub ignore: bool, |
@@ -215,8 +253,8 @@ const RUSTDOC_FENCE: &str = "```"; | |||
215 | const RUSTDOC_CODE_BLOCK_ATTRIBUTES_RUNNABLE: &[&str] = | 253 | const RUSTDOC_CODE_BLOCK_ATTRIBUTES_RUNNABLE: &[&str] = |
216 | &["", "rust", "should_panic", "edition2015", "edition2018"]; | 254 | &["", "rust", "should_panic", "edition2015", "edition2018"]; |
217 | 255 | ||
218 | fn has_runnable_doc_test(fn_def: &ast::Fn) -> bool { | 256 | fn 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 | /// ``` |
489 | fn should_have_no_runnable_6() {} | 527 | fn should_have_no_runnable_6() {} |
528 | |||
529 | /// ``` | ||
530 | /// let x = 5; | ||
531 | /// ``` | ||
532 | struct 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 | ); |