diff options
Diffstat (limited to 'crates')
-rw-r--r-- | crates/ra_ide/src/lib.rs | 2 | ||||
-rw-r--r-- | crates/ra_ide/src/runnables.rs | 111 | ||||
-rw-r--r-- | crates/ra_lsp_server/src/cargo_target_spec.rs | 16 | ||||
-rw-r--r-- | crates/ra_lsp_server/src/main_loop/handlers.rs | 4 |
4 files changed, 101 insertions, 32 deletions
diff --git a/crates/ra_ide/src/lib.rs b/crates/ra_ide/src/lib.rs index 689921f3f..9d66c365b 100644 --- a/crates/ra_ide/src/lib.rs +++ b/crates/ra_ide/src/lib.rs | |||
@@ -71,7 +71,7 @@ pub use crate::{ | |||
71 | references::{ | 71 | references::{ |
72 | Declaration, Reference, ReferenceAccess, ReferenceKind, ReferenceSearchResult, SearchScope, | 72 | Declaration, Reference, ReferenceAccess, ReferenceKind, ReferenceSearchResult, SearchScope, |
73 | }, | 73 | }, |
74 | runnables::{Runnable, RunnableKind}, | 74 | runnables::{Runnable, RunnableKind, TestId}, |
75 | source_change::{FileSystemEdit, SourceChange, SourceFileEdit}, | 75 | source_change::{FileSystemEdit, SourceChange, SourceFileEdit}, |
76 | syntax_highlighting::HighlightedRange, | 76 | syntax_highlighting::HighlightedRange, |
77 | }; | 77 | }; |
diff --git a/crates/ra_ide/src/runnables.rs b/crates/ra_ide/src/runnables.rs index b6b0c70f9..863b85591 100644 --- a/crates/ra_ide/src/runnables.rs +++ b/crates/ra_ide/src/runnables.rs | |||
@@ -1,6 +1,6 @@ | |||
1 | //! FIXME: write short doc here | 1 | //! FIXME: write short doc here |
2 | 2 | ||
3 | use hir::InFile; | 3 | use hir::{InFile, SourceBinder}; |
4 | use itertools::Itertools; | 4 | use itertools::Itertools; |
5 | use ra_db::SourceDatabase; | 5 | use ra_db::SourceDatabase; |
6 | use ra_ide_db::RootDatabase; | 6 | use ra_ide_db::RootDatabase; |
@@ -10,6 +10,7 @@ use ra_syntax::{ | |||
10 | }; | 10 | }; |
11 | 11 | ||
12 | use crate::FileId; | 12 | use crate::FileId; |
13 | use std::fmt::Display; | ||
13 | 14 | ||
14 | #[derive(Debug)] | 15 | #[derive(Debug)] |
15 | pub struct Runnable { | 16 | pub struct Runnable { |
@@ -18,38 +19,86 @@ pub struct Runnable { | |||
18 | } | 19 | } |
19 | 20 | ||
20 | #[derive(Debug)] | 21 | #[derive(Debug)] |
22 | pub enum TestId { | ||
23 | Name(String), | ||
24 | Path(String), | ||
25 | } | ||
26 | |||
27 | impl Display for TestId { | ||
28 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | ||
29 | match self { | ||
30 | TestId::Name(name) => write!(f, "{}", name), | ||
31 | TestId::Path(path) => write!(f, "{}", path), | ||
32 | } | ||
33 | } | ||
34 | } | ||
35 | |||
36 | #[derive(Debug)] | ||
21 | pub enum RunnableKind { | 37 | pub enum RunnableKind { |
22 | Test { name: String }, | 38 | Test { test_id: TestId }, |
23 | TestMod { path: String }, | 39 | TestMod { path: String }, |
24 | Bench { name: String }, | 40 | Bench { test_id: TestId }, |
25 | Bin, | 41 | Bin, |
26 | } | 42 | } |
27 | 43 | ||
28 | pub(crate) fn runnables(db: &RootDatabase, file_id: FileId) -> Vec<Runnable> { | 44 | pub(crate) fn runnables(db: &RootDatabase, file_id: FileId) -> Vec<Runnable> { |
29 | let parse = db.parse(file_id); | 45 | let parse = db.parse(file_id); |
30 | parse.tree().syntax().descendants().filter_map(|i| runnable(db, file_id, i)).collect() | 46 | let mut sb = SourceBinder::new(db); |
47 | parse.tree().syntax().descendants().filter_map(|i| runnable(db, &mut sb, file_id, i)).collect() | ||
31 | } | 48 | } |
32 | 49 | ||
33 | fn runnable(db: &RootDatabase, file_id: FileId, item: SyntaxNode) -> Option<Runnable> { | 50 | fn runnable( |
51 | db: &RootDatabase, | ||
52 | source_binder: &mut SourceBinder<RootDatabase>, | ||
53 | file_id: FileId, | ||
54 | item: SyntaxNode, | ||
55 | ) -> Option<Runnable> { | ||
34 | match_ast! { | 56 | match_ast! { |
35 | match item { | 57 | match item { |
36 | ast::FnDef(it) => { runnable_fn(it) }, | 58 | ast::FnDef(it) => { runnable_fn(db, source_binder, file_id, it) }, |
37 | ast::Module(it) => { runnable_mod(db, file_id, it) }, | 59 | ast::Module(it) => { runnable_mod(db, source_binder, file_id, it) }, |
38 | _ => { None }, | 60 | _ => { None }, |
39 | } | 61 | } |
40 | } | 62 | } |
41 | } | 63 | } |
42 | 64 | ||
43 | fn runnable_fn(fn_def: ast::FnDef) -> Option<Runnable> { | 65 | fn runnable_fn( |
44 | let name = fn_def.name()?.text().clone(); | 66 | db: &RootDatabase, |
45 | let kind = if name == "main" { | 67 | source_binder: &mut SourceBinder<RootDatabase>, |
68 | file_id: FileId, | ||
69 | fn_def: ast::FnDef, | ||
70 | ) -> Option<Runnable> { | ||
71 | let name_string = fn_def.name()?.text().to_string(); | ||
72 | |||
73 | let kind = if name_string == "main" { | ||
46 | RunnableKind::Bin | 74 | RunnableKind::Bin |
47 | } else if has_test_related_attribute(&fn_def) { | ||
48 | RunnableKind::Test { name: name.to_string() } | ||
49 | } else if fn_def.has_atom_attr("bench") { | ||
50 | RunnableKind::Bench { name: name.to_string() } | ||
51 | } else { | 75 | } else { |
52 | return None; | 76 | let test_id = if let Some(module) = fn_def |
77 | .syntax() | ||
78 | .ancestors() | ||
79 | .find_map(ast::Module::cast) | ||
80 | .and_then(|module| source_binder.to_def(InFile::new(file_id.into(), module))) | ||
81 | { | ||
82 | let path = module | ||
83 | .path_to_root(db) | ||
84 | .into_iter() | ||
85 | .rev() | ||
86 | .filter_map(|it| it.name(db)) | ||
87 | .map(|name| name.to_string()) | ||
88 | .chain(std::iter::once(name_string)) | ||
89 | .join("::"); | ||
90 | TestId::Path(path) | ||
91 | } else { | ||
92 | TestId::Name(name_string) | ||
93 | }; | ||
94 | |||
95 | if has_test_related_attribute(&fn_def) { | ||
96 | RunnableKind::Test { test_id } | ||
97 | } else if fn_def.has_atom_attr("bench") { | ||
98 | RunnableKind::Bench { test_id } | ||
99 | } else { | ||
100 | return None; | ||
101 | } | ||
53 | }; | 102 | }; |
54 | Some(Runnable { range: fn_def.syntax().text_range(), kind }) | 103 | Some(Runnable { range: fn_def.syntax().text_range(), kind }) |
55 | } | 104 | } |
@@ -68,7 +117,12 @@ fn has_test_related_attribute(fn_def: &ast::FnDef) -> bool { | |||
68 | .any(|attribute_text| attribute_text.contains("test")) | 117 | .any(|attribute_text| attribute_text.contains("test")) |
69 | } | 118 | } |
70 | 119 | ||
71 | fn runnable_mod(db: &RootDatabase, file_id: FileId, module: ast::Module) -> Option<Runnable> { | 120 | fn runnable_mod( |
121 | db: &RootDatabase, | ||
122 | source_binder: &mut SourceBinder<RootDatabase>, | ||
123 | file_id: FileId, | ||
124 | module: ast::Module, | ||
125 | ) -> Option<Runnable> { | ||
72 | let has_test_function = module | 126 | let has_test_function = module |
73 | .item_list()? | 127 | .item_list()? |
74 | .items() | 128 | .items() |
@@ -76,13 +130,12 @@ fn runnable_mod(db: &RootDatabase, file_id: FileId, module: ast::Module) -> Opti | |||
76 | ast::ModuleItem::FnDef(it) => Some(it), | 130 | ast::ModuleItem::FnDef(it) => Some(it), |
77 | _ => None, | 131 | _ => None, |
78 | }) | 132 | }) |
79 | .any(|f| f.has_atom_attr("test")); | 133 | .any(|f| has_test_related_attribute(&f)); |
80 | if !has_test_function { | 134 | if !has_test_function { |
81 | return None; | 135 | return None; |
82 | } | 136 | } |
83 | let range = module.syntax().text_range(); | 137 | let range = module.syntax().text_range(); |
84 | let mut sb = hir::SourceBinder::new(db); | 138 | let module = source_binder.to_def(InFile::new(file_id.into(), module))?; |
85 | let module = sb.to_def(InFile::new(file_id.into(), module))?; | ||
86 | 139 | ||
87 | let path = module.path_to_root(db).into_iter().rev().filter_map(|it| it.name(db)).join("::"); | 140 | let path = module.path_to_root(db).into_iter().rev().filter_map(|it| it.name(db)).join("::"); |
88 | Some(Runnable { range, kind: RunnableKind::TestMod { path } }) | 141 | Some(Runnable { range, kind: RunnableKind::TestMod { path } }) |
@@ -121,13 +174,17 @@ mod tests { | |||
121 | Runnable { | 174 | Runnable { |
122 | range: [22; 46), | 175 | range: [22; 46), |
123 | kind: Test { | 176 | kind: Test { |
124 | name: "test_foo", | 177 | test_id: Name( |
178 | "test_foo", | ||
179 | ), | ||
125 | }, | 180 | }, |
126 | }, | 181 | }, |
127 | Runnable { | 182 | Runnable { |
128 | range: [47; 81), | 183 | range: [47; 81), |
129 | kind: Test { | 184 | kind: Test { |
130 | name: "test_foo", | 185 | test_id: Name( |
186 | "test_foo", | ||
187 | ), | ||
131 | }, | 188 | }, |
132 | }, | 189 | }, |
133 | ] | 190 | ] |
@@ -160,7 +217,9 @@ mod tests { | |||
160 | Runnable { | 217 | Runnable { |
161 | range: [28; 57), | 218 | range: [28; 57), |
162 | kind: Test { | 219 | kind: Test { |
163 | name: "test_foo1", | 220 | test_id: Path( |
221 | "test_mod::test_foo1", | ||
222 | ), | ||
164 | }, | 223 | }, |
165 | }, | 224 | }, |
166 | ] | 225 | ] |
@@ -195,7 +254,9 @@ mod tests { | |||
195 | Runnable { | 254 | Runnable { |
196 | range: [46; 79), | 255 | range: [46; 79), |
197 | kind: Test { | 256 | kind: Test { |
198 | name: "test_foo1", | 257 | test_id: Path( |
258 | "foo::test_mod::test_foo1", | ||
259 | ), | ||
199 | }, | 260 | }, |
200 | }, | 261 | }, |
201 | ] | 262 | ] |
@@ -232,7 +293,9 @@ mod tests { | |||
232 | Runnable { | 293 | Runnable { |
233 | range: [68; 105), | 294 | range: [68; 105), |
234 | kind: Test { | 295 | kind: Test { |
235 | name: "test_foo1", | 296 | test_id: Path( |
297 | "foo::bar::test_mod::test_foo1", | ||
298 | ), | ||
236 | }, | 299 | }, |
237 | }, | 300 | }, |
238 | ] | 301 | ] |
diff --git a/crates/ra_lsp_server/src/cargo_target_spec.rs b/crates/ra_lsp_server/src/cargo_target_spec.rs index 594caffe2..5fd1e7b6b 100644 --- a/crates/ra_lsp_server/src/cargo_target_spec.rs +++ b/crates/ra_lsp_server/src/cargo_target_spec.rs | |||
@@ -1,6 +1,6 @@ | |||
1 | //! FIXME: write short doc here | 1 | //! FIXME: write short doc here |
2 | 2 | ||
3 | use ra_ide::{FileId, RunnableKind}; | 3 | use ra_ide::{FileId, RunnableKind, TestId}; |
4 | use ra_project_model::{self, ProjectWorkspace, TargetKind}; | 4 | use ra_project_model::{self, ProjectWorkspace, TargetKind}; |
5 | 5 | ||
6 | use crate::{world::WorldSnapshot, Result}; | 6 | use crate::{world::WorldSnapshot, Result}; |
@@ -13,13 +13,16 @@ pub(crate) fn runnable_args( | |||
13 | let spec = CargoTargetSpec::for_file(world, file_id)?; | 13 | let spec = CargoTargetSpec::for_file(world, file_id)?; |
14 | let mut res = Vec::new(); | 14 | let mut res = Vec::new(); |
15 | match kind { | 15 | match kind { |
16 | RunnableKind::Test { name } => { | 16 | RunnableKind::Test { test_id } => { |
17 | res.push("test".to_string()); | 17 | res.push("test".to_string()); |
18 | if let Some(spec) = spec { | 18 | if let Some(spec) = spec { |
19 | spec.push_to(&mut res); | 19 | spec.push_to(&mut res); |
20 | } | 20 | } |
21 | res.push("--".to_string()); | 21 | res.push("--".to_string()); |
22 | res.push(name.to_string()); | 22 | res.push(test_id.to_string()); |
23 | if let TestId::Path(_) = test_id { | ||
24 | res.push("--exact".to_string()); | ||
25 | } | ||
23 | res.push("--nocapture".to_string()); | 26 | res.push("--nocapture".to_string()); |
24 | } | 27 | } |
25 | RunnableKind::TestMod { path } => { | 28 | RunnableKind::TestMod { path } => { |
@@ -31,13 +34,16 @@ pub(crate) fn runnable_args( | |||
31 | res.push(path.to_string()); | 34 | res.push(path.to_string()); |
32 | res.push("--nocapture".to_string()); | 35 | res.push("--nocapture".to_string()); |
33 | } | 36 | } |
34 | RunnableKind::Bench { name } => { | 37 | RunnableKind::Bench { test_id } => { |
35 | res.push("bench".to_string()); | 38 | res.push("bench".to_string()); |
36 | if let Some(spec) = spec { | 39 | if let Some(spec) = spec { |
37 | spec.push_to(&mut res); | 40 | spec.push_to(&mut res); |
38 | } | 41 | } |
39 | res.push("--".to_string()); | 42 | res.push("--".to_string()); |
40 | res.push(name.to_string()); | 43 | res.push(test_id.to_string()); |
44 | if let TestId::Path(_) = test_id { | ||
45 | res.push("--exact".to_string()); | ||
46 | } | ||
41 | res.push("--nocapture".to_string()); | 47 | res.push("--nocapture".to_string()); |
42 | } | 48 | } |
43 | RunnableKind::Bin => { | 49 | RunnableKind::Bin => { |
diff --git a/crates/ra_lsp_server/src/main_loop/handlers.rs b/crates/ra_lsp_server/src/main_loop/handlers.rs index 2e598fdcd..5879a1f7a 100644 --- a/crates/ra_lsp_server/src/main_loop/handlers.rs +++ b/crates/ra_lsp_server/src/main_loop/handlers.rs | |||
@@ -918,9 +918,9 @@ fn to_lsp_runnable( | |||
918 | let args = runnable_args(world, file_id, &runnable.kind)?; | 918 | let args = runnable_args(world, file_id, &runnable.kind)?; |
919 | let line_index = world.analysis().file_line_index(file_id)?; | 919 | let line_index = world.analysis().file_line_index(file_id)?; |
920 | let label = match &runnable.kind { | 920 | let label = match &runnable.kind { |
921 | RunnableKind::Test { name } => format!("test {}", name), | 921 | RunnableKind::Test { test_id } => format!("test {}", test_id), |
922 | RunnableKind::TestMod { path } => format!("test-mod {}", path), | 922 | RunnableKind::TestMod { path } => format!("test-mod {}", path), |
923 | RunnableKind::Bench { name } => format!("bench {}", name), | 923 | RunnableKind::Bench { test_id } => format!("bench {}", test_id), |
924 | RunnableKind::Bin => "run binary".to_string(), | 924 | RunnableKind::Bin => "run binary".to_string(), |
925 | }; | 925 | }; |
926 | Ok(req::Runnable { | 926 | Ok(req::Runnable { |