diff options
author | Mikhail Rakhmanov <[email protected]> | 2020-06-03 19:10:54 +0100 |
---|---|---|
committer | Mikhail Rakhmanov <[email protected]> | 2020-06-03 19:10:54 +0100 |
commit | eefa10bc6bff3624ddd0bbb6bc89d8beb4bed186 (patch) | |
tree | 15c38c2993c52f4065d338090ca9185cc1fcd3da /crates/ra_ide/src/runnables.rs | |
parent | a9d567584857b1be4ca8eaa5ef2c7d85f7b2845e (diff) | |
parent | 794f6da821c5d6e2490b996baffe162e4753262d (diff) |
Merge branch 'master' into assists_extract_enum
Diffstat (limited to 'crates/ra_ide/src/runnables.rs')
-rw-r--r-- | crates/ra_ide/src/runnables.rs | 440 |
1 files changed, 382 insertions, 58 deletions
diff --git a/crates/ra_ide/src/runnables.rs b/crates/ra_ide/src/runnables.rs index 131b8f307..f32ce0d22 100644 --- a/crates/ra_ide/src/runnables.rs +++ b/crates/ra_ide/src/runnables.rs | |||
@@ -1,21 +1,21 @@ | |||
1 | //! FIXME: write short doc here | 1 | use std::fmt; |
2 | 2 | ||
3 | use hir::{AsAssocItem, Semantics}; | 3 | use hir::{AsAssocItem, Attrs, HirFileId, InFile, Semantics}; |
4 | use itertools::Itertools; | 4 | use itertools::Itertools; |
5 | use ra_cfg::CfgExpr; | ||
5 | use ra_ide_db::RootDatabase; | 6 | use ra_ide_db::RootDatabase; |
6 | use ra_syntax::{ | 7 | use ra_syntax::{ |
7 | ast::{self, AstNode, AttrsOwner, ModuleItemOwner, NameOwner}, | 8 | ast::{self, AstNode, AttrsOwner, DocCommentsOwner, ModuleItemOwner, NameOwner}, |
8 | match_ast, SyntaxNode, TextRange, | 9 | match_ast, SyntaxNode, |
9 | }; | 10 | }; |
10 | 11 | ||
11 | use crate::FileId; | 12 | use crate::{display::ToNav, FileId, NavigationTarget}; |
12 | use ast::DocCommentsOwner; | ||
13 | use std::fmt::Display; | ||
14 | 13 | ||
15 | #[derive(Debug)] | 14 | #[derive(Debug)] |
16 | pub struct Runnable { | 15 | pub struct Runnable { |
17 | pub range: TextRange, | 16 | pub nav: NavigationTarget, |
18 | pub kind: RunnableKind, | 17 | pub kind: RunnableKind, |
18 | pub cfg_exprs: Vec<CfgExpr>, | ||
19 | } | 19 | } |
20 | 20 | ||
21 | #[derive(Debug)] | 21 | #[derive(Debug)] |
@@ -24,8 +24,8 @@ pub enum TestId { | |||
24 | Path(String), | 24 | Path(String), |
25 | } | 25 | } |
26 | 26 | ||
27 | impl Display for TestId { | 27 | impl fmt::Display for TestId { |
28 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | 28 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
29 | match self { | 29 | match self { |
30 | TestId::Name(name) => write!(f, "{}", name), | 30 | TestId::Name(name) => write!(f, "{}", name), |
31 | TestId::Path(path) => write!(f, "{}", path), | 31 | TestId::Path(path) => write!(f, "{}", path), |
@@ -42,32 +42,47 @@ pub enum RunnableKind { | |||
42 | Bin, | 42 | Bin, |
43 | } | 43 | } |
44 | 44 | ||
45 | // Feature: Run | ||
46 | // | ||
47 | // Shows a popup suggesting to run a test/benchmark/binary **at the current cursor | ||
48 | // location**. Super useful for repeatedly running just a single test. Do bind this | ||
49 | // to a shortcut! | ||
50 | // | ||
51 | // |=== | ||
52 | // | Editor | Action Name | ||
53 | // | ||
54 | // | VS Code | **Rust Analyzer: Run** | ||
55 | // |=== | ||
45 | pub(crate) fn runnables(db: &RootDatabase, file_id: FileId) -> Vec<Runnable> { | 56 | pub(crate) fn runnables(db: &RootDatabase, file_id: FileId) -> Vec<Runnable> { |
46 | let sema = Semantics::new(db); | 57 | let sema = Semantics::new(db); |
47 | let source_file = sema.parse(file_id); | 58 | let source_file = sema.parse(file_id); |
48 | source_file.syntax().descendants().filter_map(|i| runnable(&sema, i)).collect() | 59 | source_file.syntax().descendants().filter_map(|i| runnable(&sema, i, file_id)).collect() |
49 | } | 60 | } |
50 | 61 | ||
51 | fn runnable(sema: &Semantics<RootDatabase>, item: SyntaxNode) -> Option<Runnable> { | 62 | fn runnable(sema: &Semantics<RootDatabase>, item: SyntaxNode, file_id: FileId) -> Option<Runnable> { |
52 | match_ast! { | 63 | match_ast! { |
53 | match item { | 64 | match item { |
54 | ast::FnDef(it) => runnable_fn(sema, it), | 65 | ast::FnDef(it) => runnable_fn(sema, it, file_id), |
55 | ast::Module(it) => runnable_mod(sema, it), | 66 | ast::Module(it) => runnable_mod(sema, it, file_id), |
56 | _ => None, | 67 | _ => None, |
57 | } | 68 | } |
58 | } | 69 | } |
59 | } | 70 | } |
60 | 71 | ||
61 | fn runnable_fn(sema: &Semantics<RootDatabase>, fn_def: ast::FnDef) -> Option<Runnable> { | 72 | fn runnable_fn( |
73 | sema: &Semantics<RootDatabase>, | ||
74 | fn_def: ast::FnDef, | ||
75 | file_id: FileId, | ||
76 | ) -> Option<Runnable> { | ||
62 | let name_string = fn_def.name()?.text().to_string(); | 77 | let name_string = fn_def.name()?.text().to_string(); |
63 | 78 | ||
64 | let kind = if name_string == "main" { | 79 | let kind = if name_string == "main" { |
65 | RunnableKind::Bin | 80 | RunnableKind::Bin |
66 | } else { | 81 | } else { |
67 | let test_id = if let Some(module) = sema.to_def(&fn_def).map(|def| def.module(sema.db)) { | 82 | let test_id = match sema.to_def(&fn_def).map(|def| def.module(sema.db)) { |
68 | let def = sema.to_def(&fn_def)?; | 83 | Some(module) => { |
69 | let impl_trait_name = | 84 | let def = sema.to_def(&fn_def)?; |
70 | def.as_assoc_item(sema.db).and_then(|assoc_item| { | 85 | let impl_trait_name = def.as_assoc_item(sema.db).and_then(|assoc_item| { |
71 | match assoc_item.container(sema.db) { | 86 | match assoc_item.container(sema.db) { |
72 | hir::AssocItemContainer::Trait(trait_item) => { | 87 | hir::AssocItemContainer::Trait(trait_item) => { |
73 | Some(trait_item.name(sema.db).to_string()) | 88 | Some(trait_item.name(sema.db).to_string()) |
@@ -79,25 +94,25 @@ fn runnable_fn(sema: &Semantics<RootDatabase>, fn_def: ast::FnDef) -> Option<Run | |||
79 | } | 94 | } |
80 | }); | 95 | }); |
81 | 96 | ||
82 | let path_iter = module | 97 | let path_iter = module |
83 | .path_to_root(sema.db) | 98 | .path_to_root(sema.db) |
84 | .into_iter() | 99 | .into_iter() |
85 | .rev() | 100 | .rev() |
86 | .filter_map(|it| it.name(sema.db)) | 101 | .filter_map(|it| it.name(sema.db)) |
87 | .map(|name| name.to_string()); | 102 | .map(|name| name.to_string()); |
88 | 103 | ||
89 | let path = if let Some(impl_trait_name) = impl_trait_name { | 104 | let path = if let Some(impl_trait_name) = impl_trait_name { |
90 | path_iter | 105 | path_iter |
91 | .chain(std::iter::once(impl_trait_name)) | 106 | .chain(std::iter::once(impl_trait_name)) |
92 | .chain(std::iter::once(name_string)) | 107 | .chain(std::iter::once(name_string)) |
93 | .join("::") | 108 | .join("::") |
94 | } else { | 109 | } else { |
95 | path_iter.chain(std::iter::once(name_string)).join("::") | 110 | path_iter.chain(std::iter::once(name_string)).join("::") |
96 | }; | 111 | }; |
97 | 112 | ||
98 | TestId::Path(path) | 113 | TestId::Path(path) |
99 | } else { | 114 | } |
100 | TestId::Name(name_string) | 115 | None => TestId::Name(name_string), |
101 | }; | 116 | }; |
102 | 117 | ||
103 | if has_test_related_attribute(&fn_def) { | 118 | if has_test_related_attribute(&fn_def) { |
@@ -111,7 +126,13 @@ fn runnable_fn(sema: &Semantics<RootDatabase>, fn_def: ast::FnDef) -> Option<Run | |||
111 | return None; | 126 | return None; |
112 | } | 127 | } |
113 | }; | 128 | }; |
114 | Some(Runnable { range: fn_def.syntax().text_range(), kind }) | 129 | |
130 | let attrs = Attrs::from_attrs_owner(sema.db, InFile::new(HirFileId::from(file_id), &fn_def)); | ||
131 | let cfg_exprs = | ||
132 | attrs.by_key("cfg").tt_values().map(|subtree| ra_cfg::parse_cfg(subtree)).collect(); | ||
133 | |||
134 | let nav = NavigationTarget::from_named(sema.db, InFile::new(file_id.into(), &fn_def)); | ||
135 | Some(Runnable { nav, kind, cfg_exprs }) | ||
115 | } | 136 | } |
116 | 137 | ||
117 | #[derive(Debug)] | 138 | #[derive(Debug)] |
@@ -147,7 +168,11 @@ fn has_doc_test(fn_def: &ast::FnDef) -> bool { | |||
147 | fn_def.doc_comment_text().map_or(false, |comment| comment.contains("```")) | 168 | fn_def.doc_comment_text().map_or(false, |comment| comment.contains("```")) |
148 | } | 169 | } |
149 | 170 | ||
150 | fn runnable_mod(sema: &Semantics<RootDatabase>, module: ast::Module) -> Option<Runnable> { | 171 | fn runnable_mod( |
172 | sema: &Semantics<RootDatabase>, | ||
173 | module: ast::Module, | ||
174 | file_id: FileId, | ||
175 | ) -> Option<Runnable> { | ||
151 | let has_test_function = module | 176 | let has_test_function = module |
152 | .item_list()? | 177 | .item_list()? |
153 | .items() | 178 | .items() |
@@ -159,12 +184,21 @@ fn runnable_mod(sema: &Semantics<RootDatabase>, module: ast::Module) -> Option<R | |||
159 | if !has_test_function { | 184 | if !has_test_function { |
160 | return None; | 185 | return None; |
161 | } | 186 | } |
162 | let range = module.syntax().text_range(); | 187 | let module_def = sema.to_def(&module)?; |
163 | let module = sema.to_def(&module)?; | ||
164 | 188 | ||
165 | let path = | 189 | let path = module_def |
166 | module.path_to_root(sema.db).into_iter().rev().filter_map(|it| it.name(sema.db)).join("::"); | 190 | .path_to_root(sema.db) |
167 | Some(Runnable { range, kind: RunnableKind::TestMod { path } }) | 191 | .into_iter() |
192 | .rev() | ||
193 | .filter_map(|it| it.name(sema.db)) | ||
194 | .join("::"); | ||
195 | |||
196 | let attrs = Attrs::from_attrs_owner(sema.db, InFile::new(HirFileId::from(file_id), &module)); | ||
197 | let cfg_exprs = | ||
198 | attrs.by_key("cfg").tt_values().map(|subtree| ra_cfg::parse_cfg(subtree)).collect(); | ||
199 | |||
200 | let nav = module_def.to_nav(sema.db); | ||
201 | Some(Runnable { nav, kind: RunnableKind::TestMod { path }, cfg_exprs }) | ||
168 | } | 202 | } |
169 | 203 | ||
170 | #[cfg(test)] | 204 | #[cfg(test)] |
@@ -194,11 +228,38 @@ mod tests { | |||
194 | @r###" | 228 | @r###" |
195 | [ | 229 | [ |
196 | Runnable { | 230 | Runnable { |
197 | range: 1..21, | 231 | nav: NavigationTarget { |
232 | file_id: FileId( | ||
233 | 1, | ||
234 | ), | ||
235 | full_range: 1..21, | ||
236 | name: "main", | ||
237 | kind: FN_DEF, | ||
238 | focus_range: Some( | ||
239 | 12..16, | ||
240 | ), | ||
241 | container_name: None, | ||
242 | description: None, | ||
243 | docs: None, | ||
244 | }, | ||
198 | kind: Bin, | 245 | kind: Bin, |
246 | cfg_exprs: [], | ||
199 | }, | 247 | }, |
200 | Runnable { | 248 | Runnable { |
201 | range: 22..46, | 249 | nav: NavigationTarget { |
250 | file_id: FileId( | ||
251 | 1, | ||
252 | ), | ||
253 | full_range: 22..46, | ||
254 | name: "test_foo", | ||
255 | kind: FN_DEF, | ||
256 | focus_range: Some( | ||
257 | 33..41, | ||
258 | ), | ||
259 | container_name: None, | ||
260 | description: None, | ||
261 | docs: None, | ||
262 | }, | ||
202 | kind: Test { | 263 | kind: Test { |
203 | test_id: Path( | 264 | test_id: Path( |
204 | "test_foo", | 265 | "test_foo", |
@@ -207,9 +268,23 @@ mod tests { | |||
207 | ignore: false, | 268 | ignore: false, |
208 | }, | 269 | }, |
209 | }, | 270 | }, |
271 | cfg_exprs: [], | ||
210 | }, | 272 | }, |
211 | Runnable { | 273 | Runnable { |
212 | range: 47..81, | 274 | nav: NavigationTarget { |
275 | file_id: FileId( | ||
276 | 1, | ||
277 | ), | ||
278 | full_range: 47..81, | ||
279 | name: "test_foo", | ||
280 | kind: FN_DEF, | ||
281 | focus_range: Some( | ||
282 | 68..76, | ||
283 | ), | ||
284 | container_name: None, | ||
285 | description: None, | ||
286 | docs: None, | ||
287 | }, | ||
213 | kind: Test { | 288 | kind: Test { |
214 | test_id: Path( | 289 | test_id: Path( |
215 | "test_foo", | 290 | "test_foo", |
@@ -218,6 +293,7 @@ mod tests { | |||
218 | ignore: true, | 293 | ignore: true, |
219 | }, | 294 | }, |
220 | }, | 295 | }, |
296 | cfg_exprs: [], | ||
221 | }, | 297 | }, |
222 | ] | 298 | ] |
223 | "### | 299 | "### |
@@ -243,16 +319,44 @@ mod tests { | |||
243 | @r###" | 319 | @r###" |
244 | [ | 320 | [ |
245 | Runnable { | 321 | Runnable { |
246 | range: 1..21, | 322 | nav: NavigationTarget { |
323 | file_id: FileId( | ||
324 | 1, | ||
325 | ), | ||
326 | full_range: 1..21, | ||
327 | name: "main", | ||
328 | kind: FN_DEF, | ||
329 | focus_range: Some( | ||
330 | 12..16, | ||
331 | ), | ||
332 | container_name: None, | ||
333 | description: None, | ||
334 | docs: None, | ||
335 | }, | ||
247 | kind: Bin, | 336 | kind: Bin, |
337 | cfg_exprs: [], | ||
248 | }, | 338 | }, |
249 | Runnable { | 339 | Runnable { |
250 | range: 22..64, | 340 | nav: NavigationTarget { |
341 | file_id: FileId( | ||
342 | 1, | ||
343 | ), | ||
344 | full_range: 22..64, | ||
345 | name: "foo", | ||
346 | kind: FN_DEF, | ||
347 | focus_range: Some( | ||
348 | 56..59, | ||
349 | ), | ||
350 | container_name: None, | ||
351 | description: None, | ||
352 | docs: None, | ||
353 | }, | ||
251 | kind: DocTest { | 354 | kind: DocTest { |
252 | test_id: Path( | 355 | test_id: Path( |
253 | "foo", | 356 | "foo", |
254 | ), | 357 | ), |
255 | }, | 358 | }, |
359 | cfg_exprs: [], | ||
256 | }, | 360 | }, |
257 | ] | 361 | ] |
258 | "### | 362 | "### |
@@ -281,16 +385,44 @@ mod tests { | |||
281 | @r###" | 385 | @r###" |
282 | [ | 386 | [ |
283 | Runnable { | 387 | Runnable { |
284 | range: 1..21, | 388 | nav: NavigationTarget { |
389 | file_id: FileId( | ||
390 | 1, | ||
391 | ), | ||
392 | full_range: 1..21, | ||
393 | name: "main", | ||
394 | kind: FN_DEF, | ||
395 | focus_range: Some( | ||
396 | 12..16, | ||
397 | ), | ||
398 | container_name: None, | ||
399 | description: None, | ||
400 | docs: None, | ||
401 | }, | ||
285 | kind: Bin, | 402 | kind: Bin, |
403 | cfg_exprs: [], | ||
286 | }, | 404 | }, |
287 | Runnable { | 405 | Runnable { |
288 | range: 51..105, | 406 | nav: NavigationTarget { |
407 | file_id: FileId( | ||
408 | 1, | ||
409 | ), | ||
410 | full_range: 51..105, | ||
411 | name: "foo", | ||
412 | kind: FN_DEF, | ||
413 | focus_range: Some( | ||
414 | 97..100, | ||
415 | ), | ||
416 | container_name: None, | ||
417 | description: None, | ||
418 | docs: None, | ||
419 | }, | ||
289 | kind: DocTest { | 420 | kind: DocTest { |
290 | test_id: Path( | 421 | test_id: Path( |
291 | "Data::foo", | 422 | "Data::foo", |
292 | ), | 423 | ), |
293 | }, | 424 | }, |
425 | cfg_exprs: [], | ||
294 | }, | 426 | }, |
295 | ] | 427 | ] |
296 | "### | 428 | "### |
@@ -314,13 +446,40 @@ mod tests { | |||
314 | @r###" | 446 | @r###" |
315 | [ | 447 | [ |
316 | Runnable { | 448 | Runnable { |
317 | range: 1..59, | 449 | nav: NavigationTarget { |
450 | file_id: FileId( | ||
451 | 1, | ||
452 | ), | ||
453 | full_range: 1..59, | ||
454 | name: "test_mod", | ||
455 | kind: MODULE, | ||
456 | focus_range: Some( | ||
457 | 13..21, | ||
458 | ), | ||
459 | container_name: None, | ||
460 | description: None, | ||
461 | docs: None, | ||
462 | }, | ||
318 | kind: TestMod { | 463 | kind: TestMod { |
319 | path: "test_mod", | 464 | path: "test_mod", |
320 | }, | 465 | }, |
466 | cfg_exprs: [], | ||
321 | }, | 467 | }, |
322 | Runnable { | 468 | Runnable { |
323 | range: 28..57, | 469 | nav: NavigationTarget { |
470 | file_id: FileId( | ||
471 | 1, | ||
472 | ), | ||
473 | full_range: 28..57, | ||
474 | name: "test_foo1", | ||
475 | kind: FN_DEF, | ||
476 | focus_range: Some( | ||
477 | 43..52, | ||
478 | ), | ||
479 | container_name: None, | ||
480 | description: None, | ||
481 | docs: None, | ||
482 | }, | ||
324 | kind: Test { | 483 | kind: Test { |
325 | test_id: Path( | 484 | test_id: Path( |
326 | "test_mod::test_foo1", | 485 | "test_mod::test_foo1", |
@@ -329,6 +488,7 @@ mod tests { | |||
329 | ignore: false, | 488 | ignore: false, |
330 | }, | 489 | }, |
331 | }, | 490 | }, |
491 | cfg_exprs: [], | ||
332 | }, | 492 | }, |
333 | ] | 493 | ] |
334 | "### | 494 | "### |
@@ -354,13 +514,40 @@ mod tests { | |||
354 | @r###" | 514 | @r###" |
355 | [ | 515 | [ |
356 | Runnable { | 516 | Runnable { |
357 | range: 23..85, | 517 | nav: NavigationTarget { |
518 | file_id: FileId( | ||
519 | 1, | ||
520 | ), | ||
521 | full_range: 23..85, | ||
522 | name: "test_mod", | ||
523 | kind: MODULE, | ||
524 | focus_range: Some( | ||
525 | 27..35, | ||
526 | ), | ||
527 | container_name: None, | ||
528 | description: None, | ||
529 | docs: None, | ||
530 | }, | ||
358 | kind: TestMod { | 531 | kind: TestMod { |
359 | path: "foo::test_mod", | 532 | path: "foo::test_mod", |
360 | }, | 533 | }, |
534 | cfg_exprs: [], | ||
361 | }, | 535 | }, |
362 | Runnable { | 536 | Runnable { |
363 | range: 46..79, | 537 | nav: NavigationTarget { |
538 | file_id: FileId( | ||
539 | 1, | ||
540 | ), | ||
541 | full_range: 46..79, | ||
542 | name: "test_foo1", | ||
543 | kind: FN_DEF, | ||
544 | focus_range: Some( | ||
545 | 65..74, | ||
546 | ), | ||
547 | container_name: None, | ||
548 | description: None, | ||
549 | docs: None, | ||
550 | }, | ||
364 | kind: Test { | 551 | kind: Test { |
365 | test_id: Path( | 552 | test_id: Path( |
366 | "foo::test_mod::test_foo1", | 553 | "foo::test_mod::test_foo1", |
@@ -369,6 +556,7 @@ mod tests { | |||
369 | ignore: false, | 556 | ignore: false, |
370 | }, | 557 | }, |
371 | }, | 558 | }, |
559 | cfg_exprs: [], | ||
372 | }, | 560 | }, |
373 | ] | 561 | ] |
374 | "### | 562 | "### |
@@ -396,13 +584,40 @@ mod tests { | |||
396 | @r###" | 584 | @r###" |
397 | [ | 585 | [ |
398 | Runnable { | 586 | Runnable { |
399 | range: 41..115, | 587 | nav: NavigationTarget { |
588 | file_id: FileId( | ||
589 | 1, | ||
590 | ), | ||
591 | full_range: 41..115, | ||
592 | name: "test_mod", | ||
593 | kind: MODULE, | ||
594 | focus_range: Some( | ||
595 | 45..53, | ||
596 | ), | ||
597 | container_name: None, | ||
598 | description: None, | ||
599 | docs: None, | ||
600 | }, | ||
400 | kind: TestMod { | 601 | kind: TestMod { |
401 | path: "foo::bar::test_mod", | 602 | path: "foo::bar::test_mod", |
402 | }, | 603 | }, |
604 | cfg_exprs: [], | ||
403 | }, | 605 | }, |
404 | Runnable { | 606 | Runnable { |
405 | range: 68..105, | 607 | nav: NavigationTarget { |
608 | file_id: FileId( | ||
609 | 1, | ||
610 | ), | ||
611 | full_range: 68..105, | ||
612 | name: "test_foo1", | ||
613 | kind: FN_DEF, | ||
614 | focus_range: Some( | ||
615 | 91..100, | ||
616 | ), | ||
617 | container_name: None, | ||
618 | description: None, | ||
619 | docs: None, | ||
620 | }, | ||
406 | kind: Test { | 621 | kind: Test { |
407 | test_id: Path( | 622 | test_id: Path( |
408 | "foo::bar::test_mod::test_foo1", | 623 | "foo::bar::test_mod::test_foo1", |
@@ -411,6 +626,115 @@ mod tests { | |||
411 | ignore: false, | 626 | ignore: false, |
412 | }, | 627 | }, |
413 | }, | 628 | }, |
629 | cfg_exprs: [], | ||
630 | }, | ||
631 | ] | ||
632 | "### | ||
633 | ); | ||
634 | } | ||
635 | |||
636 | #[test] | ||
637 | fn test_runnables_with_feature() { | ||
638 | let (analysis, pos) = analysis_and_position( | ||
639 | r#" | ||
640 | //- /lib.rs crate:foo cfg:feature=foo | ||
641 | <|> //empty | ||
642 | #[test] | ||
643 | #[cfg(feature = "foo")] | ||
644 | fn test_foo1() {} | ||
645 | "#, | ||
646 | ); | ||
647 | let runnables = analysis.runnables(pos.file_id).unwrap(); | ||
648 | assert_debug_snapshot!(&runnables, | ||
649 | @r###" | ||
650 | [ | ||
651 | Runnable { | ||
652 | nav: NavigationTarget { | ||
653 | file_id: FileId( | ||
654 | 1, | ||
655 | ), | ||
656 | full_range: 1..58, | ||
657 | name: "test_foo1", | ||
658 | kind: FN_DEF, | ||
659 | focus_range: Some( | ||
660 | 44..53, | ||
661 | ), | ||
662 | container_name: None, | ||
663 | description: None, | ||
664 | docs: None, | ||
665 | }, | ||
666 | kind: Test { | ||
667 | test_id: Path( | ||
668 | "test_foo1", | ||
669 | ), | ||
670 | attr: TestAttr { | ||
671 | ignore: false, | ||
672 | }, | ||
673 | }, | ||
674 | cfg_exprs: [ | ||
675 | KeyValue { | ||
676 | key: "feature", | ||
677 | value: "foo", | ||
678 | }, | ||
679 | ], | ||
680 | }, | ||
681 | ] | ||
682 | "### | ||
683 | ); | ||
684 | } | ||
685 | |||
686 | #[test] | ||
687 | fn test_runnables_with_features() { | ||
688 | let (analysis, pos) = analysis_and_position( | ||
689 | r#" | ||
690 | //- /lib.rs crate:foo cfg:feature=foo,feature=bar | ||
691 | <|> //empty | ||
692 | #[test] | ||
693 | #[cfg(all(feature = "foo", feature = "bar"))] | ||
694 | fn test_foo1() {} | ||
695 | "#, | ||
696 | ); | ||
697 | let runnables = analysis.runnables(pos.file_id).unwrap(); | ||
698 | assert_debug_snapshot!(&runnables, | ||
699 | @r###" | ||
700 | [ | ||
701 | Runnable { | ||
702 | nav: NavigationTarget { | ||
703 | file_id: FileId( | ||
704 | 1, | ||
705 | ), | ||
706 | full_range: 1..80, | ||
707 | name: "test_foo1", | ||
708 | kind: FN_DEF, | ||
709 | focus_range: Some( | ||
710 | 66..75, | ||
711 | ), | ||
712 | container_name: None, | ||
713 | description: None, | ||
714 | docs: None, | ||
715 | }, | ||
716 | kind: Test { | ||
717 | test_id: Path( | ||
718 | "test_foo1", | ||
719 | ), | ||
720 | attr: TestAttr { | ||
721 | ignore: false, | ||
722 | }, | ||
723 | }, | ||
724 | cfg_exprs: [ | ||
725 | All( | ||
726 | [ | ||
727 | KeyValue { | ||
728 | key: "feature", | ||
729 | value: "foo", | ||
730 | }, | ||
731 | KeyValue { | ||
732 | key: "feature", | ||
733 | value: "bar", | ||
734 | }, | ||
735 | ], | ||
736 | ), | ||
737 | ], | ||
414 | }, | 738 | }, |
415 | ] | 739 | ] |
416 | "### | 740 | "### |