diff options
author | Benjamin Coenen <[email protected]> | 2020-05-05 16:43:28 +0100 |
---|---|---|
committer | Benjamin Coenen <[email protected]> | 2020-05-05 16:44:27 +0100 |
commit | fe52f8f0281c0f56955871863a6e0c14732540f9 (patch) | |
tree | 14bed0631da587bfc25a8560037386ce2fdc6887 | |
parent | 15de338703fd9c789c4cf8041a59d8730f12bc78 (diff) |
add doctest support #4317
Signed-off-by: Benjamin Coenen <[email protected]>
-rw-r--r-- | crates/ra_ide/src/runnables.rs | 43 | ||||
-rw-r--r-- | crates/rust-analyzer/src/cargo_target_spec.rs | 26 | ||||
-rw-r--r-- | crates/rust-analyzer/src/main_loop/handlers.rs | 2 |
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 | ||
11 | use crate::FileId; | 11 | use crate::FileId; |
12 | use ast::DocCommentsOwner; | ||
12 | use std::fmt::Display; | 13 | use 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 | ||
124 | fn has_doc_test(fn_def: &ast::FnDef) -> bool { | ||
125 | fn_def.doc_comment_text().map_or(false, |comment| comment.contains("```")) | ||
126 | } | ||
127 | |||
120 | fn runnable_mod(sema: &Semantics<RootDatabase>, module: ast::Module) -> Option<Runnable> { | 128 | fn 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 { |