1
1
//! FIXME: write short doc here
2
2
3
- use hir:: { AsAssocItem , Semantics } ;
3
+ use hir:: { AsAssocItem , Attrs , HirFileId , InFile , Semantics } ;
4
4
use itertools:: Itertools ;
5
5
use ra_ide_db:: RootDatabase ;
6
6
use ra_syntax:: {
@@ -10,12 +10,14 @@ use ra_syntax::{
10
10
11
11
use crate :: FileId ;
12
12
use ast:: DocCommentsOwner ;
13
+ use ra_cfg:: CfgExpr ;
13
14
use std:: fmt:: Display ;
14
15
15
16
#[ derive( Debug ) ]
16
17
pub struct Runnable {
17
18
pub range : TextRange ,
18
19
pub kind : RunnableKind ,
20
+ pub cfg_exprs : Vec < CfgExpr > ,
19
21
}
20
22
21
23
#[ derive( Debug ) ]
@@ -45,20 +47,24 @@ pub enum RunnableKind {
45
47
pub ( crate ) fn runnables ( db : & RootDatabase , file_id : FileId ) -> Vec < Runnable > {
46
48
let sema = Semantics :: new ( db) ;
47
49
let source_file = sema. parse ( file_id) ;
48
- source_file. syntax ( ) . descendants ( ) . filter_map ( |i| runnable ( & sema, i) ) . collect ( )
50
+ source_file. syntax ( ) . descendants ( ) . filter_map ( |i| runnable ( & sema, i, file_id ) ) . collect ( )
49
51
}
50
52
51
- fn runnable ( sema : & Semantics < RootDatabase > , item : SyntaxNode ) -> Option < Runnable > {
53
+ fn runnable ( sema : & Semantics < RootDatabase > , item : SyntaxNode , file_id : FileId ) -> Option < Runnable > {
52
54
match_ast ! {
53
55
match item {
54
- ast:: FnDef ( it) => runnable_fn( sema, it) ,
55
- ast:: Module ( it) => runnable_mod( sema, it) ,
56
+ ast:: FnDef ( it) => runnable_fn( sema, it, file_id ) ,
57
+ ast:: Module ( it) => runnable_mod( sema, it, file_id ) ,
56
58
_ => None ,
57
59
}
58
60
}
59
61
}
60
62
61
- fn runnable_fn ( sema : & Semantics < RootDatabase > , fn_def : ast:: FnDef ) -> Option < Runnable > {
63
+ fn runnable_fn (
64
+ sema : & Semantics < RootDatabase > ,
65
+ fn_def : ast:: FnDef ,
66
+ file_id : FileId ,
67
+ ) -> Option < Runnable > {
62
68
let name_string = fn_def. name ( ) ?. text ( ) . to_string ( ) ;
63
69
64
70
let kind = if name_string == "main" {
@@ -111,7 +117,12 @@ fn runnable_fn(sema: &Semantics<RootDatabase>, fn_def: ast::FnDef) -> Option<Run
111
117
return None ;
112
118
}
113
119
} ;
114
- Some ( Runnable { range : fn_def. syntax ( ) . text_range ( ) , kind } )
120
+
121
+ let attrs = Attrs :: from_attrs_owner ( sema. db , InFile :: new ( HirFileId :: from ( file_id) , & fn_def) ) ;
122
+ let cfg_exprs =
123
+ attrs. by_key ( "cfg" ) . tt_values ( ) . map ( |subtree| ra_cfg:: parse_cfg ( subtree) ) . collect ( ) ;
124
+
125
+ Some ( Runnable { range : fn_def. syntax ( ) . text_range ( ) , kind, cfg_exprs } )
115
126
}
116
127
117
128
#[ derive( Debug ) ]
@@ -147,7 +158,11 @@ fn has_doc_test(fn_def: &ast::FnDef) -> bool {
147
158
fn_def. doc_comment_text ( ) . map_or ( false , |comment| comment. contains ( "```" ) )
148
159
}
149
160
150
- fn runnable_mod ( sema : & Semantics < RootDatabase > , module : ast:: Module ) -> Option < Runnable > {
161
+ fn runnable_mod (
162
+ sema : & Semantics < RootDatabase > ,
163
+ module : ast:: Module ,
164
+ file_id : FileId ,
165
+ ) -> Option < Runnable > {
151
166
let has_test_function = module
152
167
. item_list ( ) ?
153
168
. items ( )
@@ -160,11 +175,20 @@ fn runnable_mod(sema: &Semantics<RootDatabase>, module: ast::Module) -> Option<R
160
175
return None ;
161
176
}
162
177
let range = module. syntax ( ) . text_range ( ) ;
163
- let module = sema. to_def ( & module) ?;
178
+ let module_def = sema. to_def ( & module) ?;
179
+
180
+ let path = module_def
181
+ . path_to_root ( sema. db )
182
+ . into_iter ( )
183
+ . rev ( )
184
+ . filter_map ( |it| it. name ( sema. db ) )
185
+ . join ( "::" ) ;
186
+
187
+ let attrs = Attrs :: from_attrs_owner ( sema. db , InFile :: new ( HirFileId :: from ( file_id) , & module) ) ;
188
+ let cfg_exprs =
189
+ attrs. by_key ( "cfg" ) . tt_values ( ) . map ( |subtree| ra_cfg:: parse_cfg ( subtree) ) . collect ( ) ;
164
190
165
- let path =
166
- module. path_to_root ( sema. db ) . into_iter ( ) . rev ( ) . filter_map ( |it| it. name ( sema. db ) ) . join ( "::" ) ;
167
- Some ( Runnable { range, kind : RunnableKind :: TestMod { path } } )
191
+ Some ( Runnable { range, kind : RunnableKind :: TestMod { path } , cfg_exprs } )
168
192
}
169
193
170
194
#[ cfg( test) ]
@@ -196,6 +220,7 @@ mod tests {
196
220
Runnable {
197
221
range: 1..21,
198
222
kind: Bin,
223
+ cfg_exprs: [],
199
224
},
200
225
Runnable {
201
226
range: 22..46,
@@ -207,6 +232,7 @@ mod tests {
207
232
ignore: false,
208
233
},
209
234
},
235
+ cfg_exprs: [],
210
236
},
211
237
Runnable {
212
238
range: 47..81,
@@ -218,6 +244,7 @@ mod tests {
218
244
ignore: true,
219
245
},
220
246
},
247
+ cfg_exprs: [],
221
248
},
222
249
]
223
250
"###
@@ -245,6 +272,7 @@ mod tests {
245
272
Runnable {
246
273
range: 1..21,
247
274
kind: Bin,
275
+ cfg_exprs: [],
248
276
},
249
277
Runnable {
250
278
range: 22..64,
@@ -253,6 +281,7 @@ mod tests {
253
281
"foo",
254
282
),
255
283
},
284
+ cfg_exprs: [],
256
285
},
257
286
]
258
287
"###
@@ -283,6 +312,7 @@ mod tests {
283
312
Runnable {
284
313
range: 1..21,
285
314
kind: Bin,
315
+ cfg_exprs: [],
286
316
},
287
317
Runnable {
288
318
range: 51..105,
@@ -291,6 +321,7 @@ mod tests {
291
321
"Data::foo",
292
322
),
293
323
},
324
+ cfg_exprs: [],
294
325
},
295
326
]
296
327
"###
@@ -318,6 +349,7 @@ mod tests {
318
349
kind: TestMod {
319
350
path: "test_mod",
320
351
},
352
+ cfg_exprs: [],
321
353
},
322
354
Runnable {
323
355
range: 28..57,
@@ -329,6 +361,7 @@ mod tests {
329
361
ignore: false,
330
362
},
331
363
},
364
+ cfg_exprs: [],
332
365
},
333
366
]
334
367
"###
@@ -358,6 +391,7 @@ mod tests {
358
391
kind: TestMod {
359
392
path: "foo::test_mod",
360
393
},
394
+ cfg_exprs: [],
361
395
},
362
396
Runnable {
363
397
range: 46..79,
@@ -369,6 +403,7 @@ mod tests {
369
403
ignore: false,
370
404
},
371
405
},
406
+ cfg_exprs: [],
372
407
},
373
408
]
374
409
"###
@@ -400,6 +435,7 @@ mod tests {
400
435
kind: TestMod {
401
436
path: "foo::bar::test_mod",
402
437
},
438
+ cfg_exprs: [],
403
439
},
404
440
Runnable {
405
441
range: 68..105,
@@ -411,6 +447,89 @@ mod tests {
411
447
ignore: false,
412
448
},
413
449
},
450
+ cfg_exprs: [],
451
+ },
452
+ ]
453
+ "###
454
+ ) ;
455
+ }
456
+
457
+ #[ test]
458
+ fn test_runnables_with_feature ( ) {
459
+ let ( analysis, pos) = analysis_and_position (
460
+ r#"
461
+ //- /lib.rs crate:foo cfg:feature=foo
462
+ <|> //empty
463
+ #[test]
464
+ #[cfg(feature = "foo")]
465
+ fn test_foo1() {}
466
+ "# ,
467
+ ) ;
468
+ let runnables = analysis. runnables ( pos. file_id ) . unwrap ( ) ;
469
+ assert_debug_snapshot ! ( & runnables,
470
+ @r###"
471
+ [
472
+ Runnable {
473
+ range: 1..58,
474
+ kind: Test {
475
+ test_id: Name(
476
+ "test_foo1",
477
+ ),
478
+ attr: TestAttr {
479
+ ignore: false,
480
+ },
481
+ },
482
+ cfg_exprs: [
483
+ KeyValue {
484
+ key: "feature",
485
+ value: "foo",
486
+ },
487
+ ],
488
+ },
489
+ ]
490
+ "###
491
+ ) ;
492
+ }
493
+
494
+ #[ test]
495
+ fn test_runnables_with_features ( ) {
496
+ let ( analysis, pos) = analysis_and_position (
497
+ r#"
498
+ //- /lib.rs crate:foo cfg:feature=foo,feature=bar
499
+ <|> //empty
500
+ #[test]
501
+ #[cfg(all(feature = "foo", feature = "bar"))]
502
+ fn test_foo1() {}
503
+ "# ,
504
+ ) ;
505
+ let runnables = analysis. runnables ( pos. file_id ) . unwrap ( ) ;
506
+ assert_debug_snapshot ! ( & runnables,
507
+ @r###"
508
+ [
509
+ Runnable {
510
+ range: 1..80,
511
+ kind: Test {
512
+ test_id: Name(
513
+ "test_foo1",
514
+ ),
515
+ attr: TestAttr {
516
+ ignore: false,
517
+ },
518
+ },
519
+ cfg_exprs: [
520
+ All(
521
+ [
522
+ KeyValue {
523
+ key: "feature",
524
+ value: "foo",
525
+ },
526
+ KeyValue {
527
+ key: "feature",
528
+ value: "bar",
529
+ },
530
+ ],
531
+ ),
532
+ ],
414
533
},
415
534
]
416
535
"###
0 commit comments