Skip to content

Commit 94b2330

Browse files
committed
add doctest runnables on struct #6356
Signed-off-by: Benjamin Coenen <[email protected]>
1 parent d01e412 commit 94b2330

File tree

1 file changed

+67
-3
lines changed

1 file changed

+67
-3
lines changed

crates/ide/src/runnables.rs

Lines changed: 67 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@ pub(crate) fn runnable(
102102
) -> Option<Runnable> {
103103
match_ast! {
104104
match item {
105+
ast::Struct(it) => runnable_struct(sema, it, file_id),
105106
ast::Fn(it) => runnable_fn(sema, it, file_id),
106107
ast::Module(it) => runnable_mod(sema, it, file_id),
107108
_ => None,
@@ -182,6 +183,43 @@ fn runnable_fn(
182183
Some(Runnable { nav, kind, cfg })
183184
}
184185

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+
185223
#[derive(Debug, Copy, Clone)]
186224
pub struct TestAttr {
187225
pub ignore: bool,
@@ -215,8 +253,8 @@ const RUSTDOC_FENCE: &str = "```";
215253
const RUSTDOC_CODE_BLOCK_ATTRIBUTES_RUNNABLE: &[&str] =
216254
&["", "rust", "should_panic", "edition2015", "edition2018"];
217255

218-
fn has_runnable_doc_test(fn_def: &ast::Fn) -> bool {
219-
fn_def.doc_comment_text().map_or(false, |comments_text| {
256+
fn has_runnable_doc_test<T: DocCommentsOwner>(def: &T) -> bool {
257+
def.doc_comment_text().map_or(false, |comments_text| {
220258
let mut in_code_block = false;
221259

222260
for line in comments_text.lines() {
@@ -487,8 +525,14 @@ fn should_have_no_runnable_5() {}
487525
/// let z = 55;
488526
/// ```
489527
fn should_have_no_runnable_6() {}
528+
529+
/// ```
530+
/// let x = 5;
531+
/// ```
532+
struct StructWithRunnable(String);
533+
490534
"#,
491-
&[&BIN, &DOCTEST, &DOCTEST, &DOCTEST],
535+
&[&BIN, &DOCTEST, &DOCTEST, &DOCTEST, &DOCTEST],
492536
expect![[r#"
493537
[
494538
Runnable {
@@ -569,6 +613,26 @@ fn should_have_no_runnable_6() {}
569613
},
570614
cfg: None,
571615
},
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+
},
572636
]
573637
"#]],
574638
);

0 commit comments

Comments
 (0)