diff options
Diffstat (limited to 'crates/ra_ide/src')
-rw-r--r-- | crates/ra_ide/src/lib.rs | 2 | ||||
-rw-r--r-- | crates/ra_ide/src/runnables.rs | 109 |
2 files changed, 86 insertions, 25 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..be2a67d0a 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,84 @@ 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) = source_binder |
77 | .to_def(InFile::new(file_id.into(), fn_def.clone())) | ||
78 | .map(|def| def.module(db)) | ||
79 | { | ||
80 | let path = module | ||
81 | .path_to_root(db) | ||
82 | .into_iter() | ||
83 | .rev() | ||
84 | .filter_map(|it| it.name(db)) | ||
85 | .map(|name| name.to_string()) | ||
86 | .chain(std::iter::once(name_string)) | ||
87 | .join("::"); | ||
88 | TestId::Path(path) | ||
89 | } else { | ||
90 | TestId::Name(name_string) | ||
91 | }; | ||
92 | |||
93 | if has_test_related_attribute(&fn_def) { | ||
94 | RunnableKind::Test { test_id } | ||
95 | } else if fn_def.has_atom_attr("bench") { | ||
96 | RunnableKind::Bench { test_id } | ||
97 | } else { | ||
98 | return None; | ||
99 | } | ||
53 | }; | 100 | }; |
54 | Some(Runnable { range: fn_def.syntax().text_range(), kind }) | 101 | Some(Runnable { range: fn_def.syntax().text_range(), kind }) |
55 | } | 102 | } |
@@ -68,7 +115,12 @@ fn has_test_related_attribute(fn_def: &ast::FnDef) -> bool { | |||
68 | .any(|attribute_text| attribute_text.contains("test")) | 115 | .any(|attribute_text| attribute_text.contains("test")) |
69 | } | 116 | } |
70 | 117 | ||
71 | fn runnable_mod(db: &RootDatabase, file_id: FileId, module: ast::Module) -> Option<Runnable> { | 118 | fn runnable_mod( |
119 | db: &RootDatabase, | ||
120 | source_binder: &mut SourceBinder<RootDatabase>, | ||
121 | file_id: FileId, | ||
122 | module: ast::Module, | ||
123 | ) -> Option<Runnable> { | ||
72 | let has_test_function = module | 124 | let has_test_function = module |
73 | .item_list()? | 125 | .item_list()? |
74 | .items() | 126 | .items() |
@@ -76,13 +128,12 @@ fn runnable_mod(db: &RootDatabase, file_id: FileId, module: ast::Module) -> Opti | |||
76 | ast::ModuleItem::FnDef(it) => Some(it), | 128 | ast::ModuleItem::FnDef(it) => Some(it), |
77 | _ => None, | 129 | _ => None, |
78 | }) | 130 | }) |
79 | .any(|f| f.has_atom_attr("test")); | 131 | .any(|f| has_test_related_attribute(&f)); |
80 | if !has_test_function { | 132 | if !has_test_function { |
81 | return None; | 133 | return None; |
82 | } | 134 | } |
83 | let range = module.syntax().text_range(); | 135 | let range = module.syntax().text_range(); |
84 | let mut sb = hir::SourceBinder::new(db); | 136 | 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 | 137 | ||
87 | let path = module.path_to_root(db).into_iter().rev().filter_map(|it| it.name(db)).join("::"); | 138 | 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 } }) | 139 | Some(Runnable { range, kind: RunnableKind::TestMod { path } }) |
@@ -121,13 +172,17 @@ mod tests { | |||
121 | Runnable { | 172 | Runnable { |
122 | range: [22; 46), | 173 | range: [22; 46), |
123 | kind: Test { | 174 | kind: Test { |
124 | name: "test_foo", | 175 | test_id: Path( |
176 | "test_foo", | ||
177 | ), | ||
125 | }, | 178 | }, |
126 | }, | 179 | }, |
127 | Runnable { | 180 | Runnable { |
128 | range: [47; 81), | 181 | range: [47; 81), |
129 | kind: Test { | 182 | kind: Test { |
130 | name: "test_foo", | 183 | test_id: Path( |
184 | "test_foo", | ||
185 | ), | ||
131 | }, | 186 | }, |
132 | }, | 187 | }, |
133 | ] | 188 | ] |
@@ -160,7 +215,9 @@ mod tests { | |||
160 | Runnable { | 215 | Runnable { |
161 | range: [28; 57), | 216 | range: [28; 57), |
162 | kind: Test { | 217 | kind: Test { |
163 | name: "test_foo1", | 218 | test_id: Path( |
219 | "test_mod::test_foo1", | ||
220 | ), | ||
164 | }, | 221 | }, |
165 | }, | 222 | }, |
166 | ] | 223 | ] |
@@ -195,7 +252,9 @@ mod tests { | |||
195 | Runnable { | 252 | Runnable { |
196 | range: [46; 79), | 253 | range: [46; 79), |
197 | kind: Test { | 254 | kind: Test { |
198 | name: "test_foo1", | 255 | test_id: Path( |
256 | "foo::test_mod::test_foo1", | ||
257 | ), | ||
199 | }, | 258 | }, |
200 | }, | 259 | }, |
201 | ] | 260 | ] |
@@ -232,7 +291,9 @@ mod tests { | |||
232 | Runnable { | 291 | Runnable { |
233 | range: [68; 105), | 292 | range: [68; 105), |
234 | kind: Test { | 293 | kind: Test { |
235 | name: "test_foo1", | 294 | test_id: Path( |
295 | "foo::bar::test_mod::test_foo1", | ||
296 | ), | ||
236 | }, | 297 | }, |
237 | }, | 298 | }, |
238 | ] | 299 | ] |