@@ -16,7 +16,10 @@ use rustc_hash::{FxHashMap, FxHashSet};
16
16
use stdx:: { always, format_to} ;
17
17
use syntax:: ast:: { self , AstNode , AttrsOwner } ;
18
18
19
- use crate :: { display:: TryToNav , references, FileId , NavigationTarget } ;
19
+ use crate :: {
20
+ display:: { ToNav , TryToNav } ,
21
+ references, FileId , NavigationTarget ,
22
+ } ;
20
23
21
24
#[ derive( Debug , Clone , Hash , PartialEq , Eq ) ]
22
25
pub struct Runnable {
@@ -176,6 +179,10 @@ pub(crate) fn runnables(db: &RootDatabase, file_id: FileId) -> Vec<Runnable> {
176
179
}
177
180
} ) ;
178
181
182
+ sema. to_module_defs ( file_id)
183
+ . map ( |it| runnable_mod_outline_definition ( & sema, it) )
184
+ . for_each ( |it| add_opt ( it, None ) ) ;
185
+
179
186
res. extend ( in_macro_expansion. into_iter ( ) . flat_map ( |( _, runnables) | {
180
187
let use_name_in_title = runnables. len ( ) != 1 ;
181
188
runnables. into_iter ( ) . map ( move |mut r| {
@@ -351,6 +358,30 @@ pub(crate) fn runnable_impl(sema: &Semantics<RootDatabase>, def: &hir::Impl) ->
351
358
Some ( Runnable { use_name_in_title : false , nav, kind : RunnableKind :: DocTest { test_id } , cfg } )
352
359
}
353
360
361
+ /// Creates a test mod runnable for outline modules at the top of their definition.
362
+ fn runnable_mod_outline_definition (
363
+ sema : & Semantics < RootDatabase > ,
364
+ def : hir:: Module ,
365
+ ) -> Option < Runnable > {
366
+ if !has_test_function_or_multiple_test_submodules ( sema, & def) {
367
+ return None ;
368
+ }
369
+ let path =
370
+ def. path_to_root ( sema. db ) . into_iter ( ) . rev ( ) . filter_map ( |it| it. name ( sema. db ) ) . join ( "::" ) ;
371
+
372
+ let attrs = def. attrs ( sema. db ) ;
373
+ let cfg = attrs. cfg ( ) ;
374
+ match def. definition_source ( sema. db ) . value {
375
+ hir:: ModuleSource :: SourceFile ( _) => Some ( Runnable {
376
+ use_name_in_title : false ,
377
+ nav : def. to_nav ( sema. db ) ,
378
+ kind : RunnableKind :: TestMod { path } ,
379
+ cfg,
380
+ } ) ,
381
+ _ => None ,
382
+ }
383
+ }
384
+
354
385
fn module_def_doctest ( sema : & Semantics < RootDatabase > , def : hir:: ModuleDef ) -> Option < Runnable > {
355
386
let attrs = match def {
356
387
hir:: ModuleDef :: Module ( it) => it. attrs ( sema. db ) ,
@@ -541,7 +572,7 @@ mod not_a_root {
541
572
fn main() {}
542
573
}
543
574
"# ,
544
- & [ Bin , Test , Test , Bench ] ,
575
+ & [ Bin , Test , Test , Bench , TestMod ] ,
545
576
expect ! [ [ r#"
546
577
[
547
578
Runnable {
@@ -618,6 +649,21 @@ mod not_a_root {
618
649
},
619
650
cfg: None,
620
651
},
652
+ Runnable {
653
+ use_name_in_title: false,
654
+ nav: NavigationTarget {
655
+ file_id: FileId(
656
+ 0,
657
+ ),
658
+ full_range: 0..137,
659
+ name: "",
660
+ kind: Module,
661
+ },
662
+ kind: TestMod {
663
+ path: "",
664
+ },
665
+ cfg: None,
666
+ },
621
667
]
622
668
"# ] ] ,
623
669
) ;
1143
1189
#[cfg(feature = "foo")]
1144
1190
fn test_foo1() {}
1145
1191
"# ,
1146
- & [ Test ] ,
1192
+ & [ Test , TestMod ] ,
1147
1193
expect ! [ [ r#"
1148
1194
[
1149
1195
Runnable {
@@ -1174,6 +1220,21 @@ fn test_foo1() {}
1174
1220
),
1175
1221
),
1176
1222
},
1223
+ Runnable {
1224
+ use_name_in_title: false,
1225
+ nav: NavigationTarget {
1226
+ file_id: FileId(
1227
+ 0,
1228
+ ),
1229
+ full_range: 0..51,
1230
+ name: "",
1231
+ kind: Module,
1232
+ },
1233
+ kind: TestMod {
1234
+ path: "",
1235
+ },
1236
+ cfg: None,
1237
+ },
1177
1238
]
1178
1239
"# ] ] ,
1179
1240
) ;
1189
1250
#[cfg(all(feature = "foo", feature = "bar"))]
1190
1251
fn test_foo1() {}
1191
1252
"# ,
1192
- & [ Test ] ,
1253
+ & [ Test , TestMod ] ,
1193
1254
expect ! [ [ r#"
1194
1255
[
1195
1256
Runnable {
@@ -1230,6 +1291,21 @@ fn test_foo1() {}
1230
1291
),
1231
1292
),
1232
1293
},
1294
+ Runnable {
1295
+ use_name_in_title: false,
1296
+ nav: NavigationTarget {
1297
+ file_id: FileId(
1298
+ 0,
1299
+ ),
1300
+ full_range: 0..73,
1301
+ name: "",
1302
+ kind: Module,
1303
+ },
1304
+ kind: TestMod {
1305
+ path: "",
1306
+ },
1307
+ cfg: None,
1308
+ },
1233
1309
]
1234
1310
"# ] ] ,
1235
1311
) ;
@@ -1316,7 +1392,7 @@ mod tests {
1316
1392
}
1317
1393
gen2!();
1318
1394
"# ,
1319
- & [ TestMod , TestMod , Test , Test ] ,
1395
+ & [ TestMod , TestMod , TestMod , Test , Test ] ,
1320
1396
expect ! [ [ r#"
1321
1397
[
1322
1398
Runnable {
@@ -1336,6 +1412,21 @@ gen2!();
1336
1412
},
1337
1413
cfg: None,
1338
1414
},
1415
+ Runnable {
1416
+ use_name_in_title: false,
1417
+ nav: NavigationTarget {
1418
+ file_id: FileId(
1419
+ 0,
1420
+ ),
1421
+ full_range: 0..237,
1422
+ name: "",
1423
+ kind: Module,
1424
+ },
1425
+ kind: TestMod {
1426
+ path: "",
1427
+ },
1428
+ cfg: None,
1429
+ },
1339
1430
Runnable {
1340
1431
use_name_in_title: true,
1341
1432
nav: NavigationTarget {
@@ -1579,7 +1670,7 @@ fn t0() {}
1579
1670
#[test]
1580
1671
fn t1() {}
1581
1672
"# ,
1582
- & [ Test , Test ] ,
1673
+ & [ Test , Test , TestMod ] ,
1583
1674
expect ! [ [ r#"
1584
1675
[
1585
1676
Runnable {
@@ -1624,6 +1715,21 @@ fn t1() {}
1624
1715
},
1625
1716
cfg: None,
1626
1717
},
1718
+ Runnable {
1719
+ use_name_in_title: false,
1720
+ nav: NavigationTarget {
1721
+ file_id: FileId(
1722
+ 1,
1723
+ ),
1724
+ full_range: 0..39,
1725
+ name: "m",
1726
+ kind: Module,
1727
+ },
1728
+ kind: TestMod {
1729
+ path: "m",
1730
+ },
1731
+ cfg: None,
1732
+ },
1627
1733
]
1628
1734
"# ] ] ,
1629
1735
) ;
0 commit comments