aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBenjamin Coenen <[email protected]>2020-05-05 16:43:28 +0100
committerBenjamin Coenen <[email protected]>2020-05-05 16:44:27 +0100
commitfe52f8f0281c0f56955871863a6e0c14732540f9 (patch)
tree14bed0631da587bfc25a8560037386ce2fdc6887
parent15de338703fd9c789c4cf8041a59d8730f12bc78 (diff)
add doctest support #4317
Signed-off-by: Benjamin Coenen <[email protected]>
-rw-r--r--crates/ra_ide/src/runnables.rs43
-rw-r--r--crates/rust-analyzer/src/cargo_target_spec.rs26
-rw-r--r--crates/rust-analyzer/src/main_loop/handlers.rs2
3 files changed, 65 insertions, 6 deletions
diff --git a/crates/ra_ide/src/runnables.rs b/crates/ra_ide/src/runnables.rs
index 38637c19c..fa8a9d92c 100644
--- a/crates/ra_ide/src/runnables.rs
+++ b/crates/ra_ide/src/runnables.rs
@@ -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
@@ -81,6 +83,8 @@ fn runnable_fn(sema: &Semantics<RootDatabase>, fn_def: ast::FnDef) -> Option<Run
81 RunnableKind::Test { test_id, attr } 83 RunnableKind::Test { test_id, attr }
82 } else if fn_def.has_atom_attr("bench") { 84 } else if fn_def.has_atom_attr("bench") {
83 RunnableKind::Bench { test_id } 85 RunnableKind::Bench { test_id }
86 } else if has_doc_test(&fn_def) {
87 RunnableKind::DocTest { test_id }
84 } else { 88 } else {
85 return None; 89 return None;
86 } 90 }
@@ -117,6 +121,10 @@ fn has_test_related_attribute(fn_def: &ast::FnDef) -> bool {
117 .any(|attribute_text| attribute_text.contains("test")) 121 .any(|attribute_text| attribute_text.contains("test"))
118} 122}
119 123
124fn has_doc_test(fn_def: &ast::FnDef) -> bool {
125 fn_def.doc_comment_text().map_or(false, |comment| comment.contains("```"))
126}
127
120fn runnable_mod(sema: &Semantics<RootDatabase>, module: ast::Module) -> Option<Runnable> { 128fn runnable_mod(sema: &Semantics<RootDatabase>, module: ast::Module) -> Option<Runnable> {
121 let has_test_function = module 129 let has_test_function = module
122 .item_list()? 130 .item_list()?
@@ -195,6 +203,41 @@ mod tests {
195 } 203 }
196 204
197 #[test] 205 #[test]
206 fn test_runnables_doc_test() {
207 let (analysis, pos) = analysis_and_position(
208 r#"
209 //- /lib.rs
210 <|> //empty
211 fn main() {}
212
213 /// ```
214 /// let x = 5;
215 /// ```
216 fn foo() {}
217 "#,
218 );
219 let runnables = analysis.runnables(pos.file_id).unwrap();
220 assert_debug_snapshot!(&runnables,
221 @r###"
222 [
223 Runnable {
224 range: 1..21,
225 kind: Bin,
226 },
227 Runnable {
228 range: 22..64,
229 kind: DocTest {
230 test_id: Path(
231 "foo",
232 ),
233 },
234 },
235 ]
236 "###
237 );
238 }
239
240 #[test]
198 fn test_runnables_module() { 241 fn test_runnables_module() {
199 let (analysis, pos) = analysis_and_position( 242 let (analysis, pos) = analysis_and_position(
200 r#" 243 r#"
diff --git a/crates/rust-analyzer/src/cargo_target_spec.rs b/crates/rust-analyzer/src/cargo_target_spec.rs
index 10c25666a..5e5a17943 100644
--- a/crates/rust-analyzer/src/cargo_target_spec.rs
+++ b/crates/rust-analyzer/src/cargo_target_spec.rs
@@ -27,7 +27,7 @@ impl CargoTargetSpec {
27 RunnableKind::Test { test_id, attr } => { 27 RunnableKind::Test { test_id, attr } => {
28 args.push("test".to_string()); 28 args.push("test".to_string());
29 if let Some(spec) = spec { 29 if let Some(spec) = spec {
30 spec.push_to(&mut args); 30 spec.push_to(&mut args, kind);
31 } 31 }
32 extra_args.push(test_id.to_string()); 32 extra_args.push(test_id.to_string());
33 if let TestId::Path(_) = test_id { 33 if let TestId::Path(_) = test_id {
@@ -35,13 +35,13 @@ impl CargoTargetSpec {
35 } 35 }
36 extra_args.push("--nocapture".to_string()); 36 extra_args.push("--nocapture".to_string());
37 if attr.ignore { 37 if attr.ignore {
38 extra_args.push("--ignored".to_string()) 38 extra_args.push("--ignored".to_string());
39 } 39 }
40 } 40 }
41 RunnableKind::TestMod { path } => { 41 RunnableKind::TestMod { path } => {
42 args.push("test".to_string()); 42 args.push("test".to_string());
43 if let Some(spec) = spec { 43 if let Some(spec) = spec {
44 spec.push_to(&mut args); 44 spec.push_to(&mut args, kind);
45 } 45 }
46 extra_args.push(path.to_string()); 46 extra_args.push(path.to_string());
47 extra_args.push("--nocapture".to_string()); 47 extra_args.push("--nocapture".to_string());
@@ -49,7 +49,7 @@ impl CargoTargetSpec {
49 RunnableKind::Bench { test_id } => { 49 RunnableKind::Bench { test_id } => {
50 args.push("bench".to_string()); 50 args.push("bench".to_string());
51 if let Some(spec) = spec { 51 if let Some(spec) = spec {
52 spec.push_to(&mut args); 52 spec.push_to(&mut args, kind);
53 } 53 }
54 extra_args.push(test_id.to_string()); 54 extra_args.push(test_id.to_string());
55 if let TestId::Path(_) = test_id { 55 if let TestId::Path(_) = test_id {
@@ -57,10 +57,19 @@ impl CargoTargetSpec {
57 } 57 }
58 extra_args.push("--nocapture".to_string()); 58 extra_args.push("--nocapture".to_string());
59 } 59 }
60 RunnableKind::DocTest { test_id } => {
61 args.push("test".to_string());
62 args.push("--doc".to_string());
63 if let Some(spec) = spec {
64 spec.push_to(&mut args, kind);
65 }
66 extra_args.push(test_id.to_string());
67 extra_args.push("--nocapture".to_string());
68 }
60 RunnableKind::Bin => { 69 RunnableKind::Bin => {
61 args.push("run".to_string()); 70 args.push("run".to_string());
62 if let Some(spec) = spec { 71 if let Some(spec) = spec {
63 spec.push_to(&mut args); 72 spec.push_to(&mut args, kind);
64 } 73 }
65 } 74 }
66 } 75 }
@@ -91,9 +100,14 @@ impl CargoTargetSpec {
91 Ok(res) 100 Ok(res)
92 } 101 }
93 102
94 pub(crate) fn push_to(self, buf: &mut Vec<String>) { 103 pub(crate) fn push_to(self, buf: &mut Vec<String>, kind: &RunnableKind) {
95 buf.push("--package".to_string()); 104 buf.push("--package".to_string());
96 buf.push(self.package); 105 buf.push(self.package);
106
107 // Can't mix --doc with other target flags
108 if let RunnableKind::DocTest { .. } = kind {
109 return;
110 }
97 match self.target_kind { 111 match self.target_kind {
98 TargetKind::Bin => { 112 TargetKind::Bin => {
99 buf.push("--bin".to_string()); 113 buf.push("--bin".to_string());
diff --git a/crates/rust-analyzer/src/main_loop/handlers.rs b/crates/rust-analyzer/src/main_loop/handlers.rs
index c7a96ba93..15e8305f8 100644
--- a/crates/rust-analyzer/src/main_loop/handlers.rs
+++ b/crates/rust-analyzer/src/main_loop/handlers.rs
@@ -835,6 +835,7 @@ pub fn handle_code_lens(
835 for runnable in world.analysis().runnables(file_id)? { 835 for runnable in world.analysis().runnables(file_id)? {
836 let title = match &runnable.kind { 836 let title = match &runnable.kind {
837 RunnableKind::Test { .. } | RunnableKind::TestMod { .. } => "▶️\u{fe0e}Run Test", 837 RunnableKind::Test { .. } | RunnableKind::TestMod { .. } => "▶️\u{fe0e}Run Test",
838 RunnableKind::DocTest { .. } => "▶️\u{fe0e}Run Doctest",
838 RunnableKind::Bench { .. } => "Run Bench", 839 RunnableKind::Bench { .. } => "Run Bench",
839 RunnableKind::Bin => "Run", 840 RunnableKind::Bin => "Run",
840 } 841 }
@@ -1018,6 +1019,7 @@ fn to_lsp_runnable(
1018 RunnableKind::Test { test_id, .. } => format!("test {}", test_id), 1019 RunnableKind::Test { test_id, .. } => format!("test {}", test_id),
1019 RunnableKind::TestMod { path } => format!("test-mod {}", path), 1020 RunnableKind::TestMod { path } => format!("test-mod {}", path),
1020 RunnableKind::Bench { test_id } => format!("bench {}", test_id), 1021 RunnableKind::Bench { test_id } => format!("bench {}", test_id),
1022 RunnableKind::DocTest { test_id, .. } => format!("doctest {}", test_id),
1021 RunnableKind::Bin => "run binary".to_string(), 1023 RunnableKind::Bin => "run binary".to_string(),
1022 }; 1024 };
1023 Ok(req::Runnable { 1025 Ok(req::Runnable {