Skip to content

Commit 9f34417

Browse files
fix
clippy
1 parent ea1d299 commit 9f34417

File tree

2 files changed

+91
-26
lines changed

2 files changed

+91
-26
lines changed

crates/ide/src/runnables.rs

Lines changed: 86 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ pub enum RunnableKind {
5757
TestMod { path: String },
5858
Test { test_id: TestId, attr: TestAttr },
5959
Bench { test_id: TestId },
60-
DocTest { test_id: TestId },
60+
DocTest { test_id: TestId, has_compile_fail: bool },
6161
Bin,
6262
}
6363

@@ -404,9 +404,7 @@ pub(crate) fn runnable_impl(
404404
let display_target = def.module(sema.db).krate(sema.db).to_display_target(sema.db);
405405
let edition = display_target.edition;
406406
let attrs = def.attrs(sema.db);
407-
if !has_runnable_doc_test(sema.db, &attrs) {
408-
return None;
409-
}
407+
let doc_test_info = runnable_doc_test_info(sema.db, &attrs)?;
410408
let cfg = attrs.cfgs(sema.db).cloned();
411409
let nav = def.try_to_nav(sema)?.call_site();
412410
let ty = def.self_ty(sema.db);
@@ -431,7 +429,7 @@ pub(crate) fn runnable_impl(
431429
Some(Runnable {
432430
use_name_in_title: false,
433431
nav,
434-
kind: RunnableKind::DocTest { test_id },
432+
kind: RunnableKind::DocTest { test_id, has_compile_fail: doc_test_info.has_compile_fail },
435433
cfg,
436434
update_test,
437435
})
@@ -510,9 +508,7 @@ fn module_def_doctest(sema: &Semantics<'_, RootDatabase>, def: Definition) -> Op
510508
let display_target = krate
511509
.unwrap_or_else(|| (*db.all_crates().last().expect("no crate graph present")).into())
512510
.to_display_target(db);
513-
if !has_runnable_doc_test(db, &attrs) {
514-
return None;
515-
}
511+
let doc_test_info = runnable_doc_test_info(db, &attrs)?;
516512
let def_name = def.name(db)?;
517513
let path = (|| {
518514
let mut path = String::new();
@@ -555,7 +551,7 @@ fn module_def_doctest(sema: &Semantics<'_, RootDatabase>, def: Definition) -> Op
555551
let res = Runnable {
556552
use_name_in_title: false,
557553
nav,
558-
kind: RunnableKind::DocTest { test_id },
554+
kind: RunnableKind::DocTest { test_id, has_compile_fail: doc_test_info.has_compile_fail },
559555
cfg: attrs.cfgs(db).cloned(),
560556
update_test: UpdateTest::default(),
561557
};
@@ -573,32 +569,64 @@ impl TestAttr {
573569
}
574570
}
575571

576-
fn has_runnable_doc_test(db: &RootDatabase, attrs: &hir::AttrsWithOwner) -> bool {
572+
#[derive(Default, Clone, Copy)]
573+
struct RunnableDocTestInfo {
574+
has_compile_fail: bool,
575+
}
576+
577+
fn runnable_doc_test_info(
578+
db: &RootDatabase,
579+
attrs: &hir::AttrsWithOwner,
580+
) -> Option<RunnableDocTestInfo> {
577581
const RUSTDOC_FENCES: [&str; 2] = ["```", "~~~"];
578582
const RUSTDOC_CODE_BLOCK_ATTRIBUTES_RUNNABLE: &[&str] =
579-
&["", "rust", "should_panic", "edition2015", "edition2018", "edition2021"];
583+
&["", "rust", "should_panic", "edition2015", "edition2018", "edition2021", "edition2024"];
584+
585+
let doc = attrs.hir_docs(db)?;
586+
let mut info = RunnableDocTestInfo::default();
587+
let mut in_code_block = false;
588+
let mut runnable_found = false;
589+
590+
for line in doc.docs().lines() {
591+
let trimmed_line = line.trim_start();
592+
if let Some(header) =
593+
RUSTDOC_FENCES.into_iter().find_map(|fence| trimmed_line.strip_prefix(fence))
594+
{
595+
if in_code_block {
596+
in_code_block = false;
597+
continue;
598+
}
580599

581-
attrs.hir_docs(db).is_some_and(|doc| {
582-
let mut in_code_block = false;
600+
in_code_block = true;
601+
let mut block_has_compile_fail = false;
602+
let mut block_runnable = true;
583603

584-
for line in doc.docs().lines() {
585-
if let Some(header) =
586-
RUSTDOC_FENCES.into_iter().find_map(|fence| line.strip_prefix(fence))
604+
for attr in header
605+
.split(',')
606+
.flat_map(|segment| segment.split_ascii_whitespace())
607+
.map(str::trim)
608+
.filter(|attr| !attr.is_empty())
587609
{
588-
in_code_block = !in_code_block;
610+
if attr.eq_ignore_ascii_case("compile_fail") {
611+
block_has_compile_fail = true;
612+
block_runnable = false;
613+
continue;
614+
}
589615

590-
if in_code_block
591-
&& header
592-
.split(',')
593-
.all(|sub| RUSTDOC_CODE_BLOCK_ATTRIBUTES_RUNNABLE.contains(&sub.trim()))
616+
if !RUSTDOC_CODE_BLOCK_ATTRIBUTES_RUNNABLE
617+
.iter()
618+
.any(|allowed| allowed.eq_ignore_ascii_case(attr))
594619
{
595-
return true;
620+
block_runnable = false;
596621
}
597622
}
623+
624+
info.has_compile_fail |= block_has_compile_fail;
625+
runnable_found |= block_runnable;
598626
}
627+
}
599628

600-
false
601-
})
629+
runnable_found.then_some(info)
602630
}
603631

604632
// We could create runnables for modules with number_of_test_submodules > 0,
@@ -756,6 +784,7 @@ impl UpdateTest {
756784
mod tests {
757785
use expect_test::{Expect, expect};
758786

787+
use super::RunnableKind;
759788
use crate::fixture;
760789

761790
fn check(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect) {
@@ -944,6 +973,39 @@ impl Test for StructWithRunnable {}
944973
);
945974
}
946975

976+
#[test]
977+
fn doc_test_runnable_tracks_compile_fail_blocks() {
978+
let (analysis, position) = fixture::position(
979+
r#"
980+
//- /lib.rs
981+
$0
982+
/// ```compile_fail
983+
/// let x = 5;
984+
/// x += 1;
985+
/// ```
986+
///
987+
/// ```
988+
/// let x = 5;
989+
/// x + 1;
990+
/// ```
991+
fn add(left: u64, right: u64) -> u64 {
992+
left + right
993+
}
994+
"#,
995+
);
996+
997+
let runnables = analysis.runnables(position.file_id).unwrap();
998+
let doc_test = runnables
999+
.into_iter()
1000+
.find(|runnable| matches!(runnable.kind, RunnableKind::DocTest { .. }))
1001+
.expect("expected doctest runnable");
1002+
1003+
match doc_test.kind {
1004+
RunnableKind::DocTest { has_compile_fail, .. } => assert!(has_compile_fail),
1005+
_ => panic!("expected doctest runnable"),
1006+
}
1007+
}
1008+
9471009
#[test]
9481010
fn test_runnables_doc_test_in_impl() {
9491011
check(

crates/rust-analyzer/src/target_spec.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ impl CargoTargetSpec {
116116
cfg: &Option<CfgExpr>,
117117
) -> (Vec<String>, Vec<String>) {
118118
let config = snap.config.runnables(None);
119-
let extra_test_binary_args = config.extra_test_binary_args;
119+
let mut extra_test_binary_args = config.extra_test_binary_args;
120120

121121
let mut cargo_args = Vec::new();
122122
let mut executable_args = Vec::new();
@@ -146,10 +146,13 @@ impl CargoTargetSpec {
146146
}
147147
executable_args.extend(extra_test_binary_args);
148148
}
149-
RunnableKind::DocTest { test_id } => {
149+
RunnableKind::DocTest { test_id, has_compile_fail } => {
150150
cargo_args.push("test".to_owned());
151151
cargo_args.push("--doc".to_owned());
152152
executable_args.push(test_id.to_string());
153+
if *has_compile_fail {
154+
extra_test_binary_args.retain(|arg| arg != "--nocapture");
155+
}
153156
executable_args.extend(extra_test_binary_args);
154157
}
155158
RunnableKind::Bin => {

0 commit comments

Comments
 (0)