@@ -19,6 +19,7 @@ use rustc_ast_pretty::pprust;
19
19
use rustc_span:: { BytePos , DUMMY_SP , Ident , Span , Symbol } ;
20
20
use tracing:: debug;
21
21
22
+ use crate :: Config ;
22
23
use crate :: comment:: {
23
24
CharClasses , FindUncommented , FullCodeCharKind , LineClasses , contains_comment,
24
25
} ;
@@ -27,6 +28,7 @@ use crate::config::lists::*;
27
28
use crate :: expr:: { RhsAssignKind , rewrite_array, rewrite_assign_rhs} ;
28
29
use crate :: lists:: { ListFormatting , itemize_list, write_list} ;
29
30
use crate :: overflow;
31
+ use crate :: parse:: macros:: cfg_select:: parse_cfg_select;
30
32
use crate :: parse:: macros:: lazy_static:: parse_lazy_static;
31
33
use crate :: parse:: macros:: { ParsedMacroArgs , parse_expr, parse_macro_args} ;
32
34
use crate :: rewrite:: {
@@ -240,6 +242,20 @@ fn rewrite_macro_inner(
240
242
}
241
243
}
242
244
245
+ if macro_name. ends_with ( "cfg_select!" ) {
246
+ match format_cfg_select ( context, shape, ts. clone ( ) , mac. span ( ) ) {
247
+ Ok ( rw) => return Ok ( rw) ,
248
+ Err ( err) => match err {
249
+ // We will move on to parsing macro args just like other macros
250
+ // if we could not parse cfg_select! with known syntax
251
+ RewriteError :: MacroFailure { kind, span : _ }
252
+ if kind == MacroErrorKind :: ParseFailure => { }
253
+ // If formatting fails even though parsing succeeds, return the err early
254
+ other => return Err ( other) ,
255
+ } ,
256
+ }
257
+ }
258
+
243
259
let ParsedMacroArgs {
244
260
args : arg_vec,
245
261
vec_with_semi,
@@ -1288,17 +1304,19 @@ impl MacroBranch {
1288
1304
1289
1305
let old_body = context. snippet ( self . body ) . trim ( ) ;
1290
1306
let has_block_body = old_body. starts_with ( '{' ) ;
1291
- let mut prefix_width = 5 ; // 5 = " => {"
1292
- if context. config . style_edition ( ) >= StyleEdition :: Edition2024 {
1293
- if has_block_body {
1294
- prefix_width = 6 ; // 6 = " => {{"
1295
- }
1296
- }
1307
+
1308
+ let prefix =
1309
+ if context. config . style_edition ( ) >= StyleEdition :: Edition2024 && has_block_body {
1310
+ " => {{"
1311
+ } else {
1312
+ " => {"
1313
+ } ;
1314
+
1297
1315
let mut result = format_macro_args (
1298
1316
context,
1299
1317
self . args . clone ( ) ,
1300
1318
shape
1301
- . sub_width ( prefix_width )
1319
+ . sub_width ( prefix . len ( ) )
1302
1320
. max_width_error ( shape. width , self . span ) ?,
1303
1321
) ?;
1304
1322
@@ -1321,10 +1339,63 @@ impl MacroBranch {
1321
1339
let ( body_str, substs) =
1322
1340
replace_names ( old_body) . macro_error ( MacroErrorKind :: ReplaceMacroVariable , self . span ) ?;
1323
1341
1324
- let mut config = context . config . clone ( ) ;
1325
- config. set ( ) . show_parse_errors ( false ) ;
1342
+ let mut new_body =
1343
+ Self :: try_format_rhs ( & context . config , shape , has_block_body , & body_str , self . span ) ? ;
1326
1344
1327
- result += " {" ;
1345
+ // Undo our replacement of macro variables.
1346
+ // FIXME: this could be *much* more efficient.
1347
+ for ( old, new) in & substs {
1348
+ if old_body. contains ( new) {
1349
+ debug ! ( "rewrite_macro_def: bailing matching variable: `{}`" , new) ;
1350
+ return Err ( RewriteError :: MacroFailure {
1351
+ kind : MacroErrorKind :: ReplaceMacroVariable ,
1352
+ span : self . span ,
1353
+ } ) ;
1354
+ }
1355
+ new_body = new_body. replace ( new, old) ;
1356
+ }
1357
+
1358
+ Self :: emit_formatted_body (
1359
+ & context. config ,
1360
+ & shape,
1361
+ & mut result,
1362
+ has_block_body,
1363
+ & new_body,
1364
+ ) ;
1365
+
1366
+ Ok ( result)
1367
+ }
1368
+
1369
+ fn emit_formatted_body (
1370
+ config : & Config ,
1371
+ shape : & Shape ,
1372
+ result : & mut String ,
1373
+ has_block_body : bool ,
1374
+ body : & str ,
1375
+ ) {
1376
+ * result += " {" ;
1377
+
1378
+ if has_block_body {
1379
+ * result += body. trim ( ) ;
1380
+ } else if !body. is_empty ( ) {
1381
+ * result += "\n " ;
1382
+ * result += & body;
1383
+ * result += & shape. indent . to_string ( & config) ;
1384
+ }
1385
+
1386
+ * result += "}" ;
1387
+ }
1388
+
1389
+ fn try_format_rhs (
1390
+ config : & Config ,
1391
+ shape : Shape ,
1392
+ has_block_body : bool ,
1393
+ body_str : & str ,
1394
+ span : Span ,
1395
+ ) -> RewriteResult {
1396
+ // This is a best-effort, reporting parse errors is not helpful.
1397
+ let mut config = config. clone ( ) ;
1398
+ config. set ( ) . show_parse_errors ( false ) ;
1328
1399
1329
1400
let body_indent = if has_block_body {
1330
1401
shape. indent
@@ -1335,33 +1406,34 @@ impl MacroBranch {
1335
1406
config. set ( ) . max_width ( new_width) ;
1336
1407
1337
1408
// First try to format as items, then as statements.
1338
- let new_body_snippet = match crate :: format_snippet ( & body_str, & config, true ) {
1339
- Some ( new_body) => new_body,
1340
- None => {
1341
- let new_width = new_width + config. tab_spaces ( ) ;
1342
- config. set ( ) . max_width ( new_width) ;
1343
- match crate :: format_code_block ( & body_str, & config, true ) {
1344
- Some ( new_body) => new_body,
1345
- None => {
1346
- return Err ( RewriteError :: MacroFailure {
1347
- kind : MacroErrorKind :: Unknown ,
1348
- span : self . span ,
1349
- } ) ;
1350
- }
1351
- }
1409
+ let new_body_snippet = ' blk: {
1410
+ if let Some ( new_body) = crate :: format_snippet ( & body_str, & config, true ) {
1411
+ break ' blk new_body;
1352
1412
}
1413
+
1414
+ let new_width = config. max_width ( ) + config. tab_spaces ( ) ;
1415
+ config. set ( ) . max_width ( new_width) ;
1416
+
1417
+ if let Some ( new_body) = crate :: format_code_block ( & body_str, & config, true ) {
1418
+ break ' blk new_body;
1419
+ }
1420
+
1421
+ return Err ( RewriteError :: MacroFailure {
1422
+ kind : MacroErrorKind :: Unknown ,
1423
+ span,
1424
+ } ) ;
1353
1425
} ;
1354
1426
1355
1427
if !filtered_str_fits ( & new_body_snippet. snippet , config. max_width ( ) , shape) {
1356
1428
return Err ( RewriteError :: ExceedsMaxWidth {
1357
1429
configured_width : shape. width ,
1358
- span : self . span ,
1430
+ span,
1359
1431
} ) ;
1360
1432
}
1361
1433
1362
1434
// Indent the body since it is in a block.
1363
1435
let indent_str = body_indent. to_string ( & config) ;
1364
- let mut new_body = LineClasses :: new ( new_body_snippet. snippet . trim_end ( ) )
1436
+ let new_body = LineClasses :: new ( new_body_snippet. snippet . trim_end ( ) )
1365
1437
. enumerate ( )
1366
1438
. fold (
1367
1439
( String :: new ( ) , true ) ,
@@ -1377,30 +1449,7 @@ impl MacroBranch {
1377
1449
)
1378
1450
. 0 ;
1379
1451
1380
- // Undo our replacement of macro variables.
1381
- // FIXME: this could be *much* more efficient.
1382
- for ( old, new) in & substs {
1383
- if old_body. contains ( new) {
1384
- debug ! ( "rewrite_macro_def: bailing matching variable: `{}`" , new) ;
1385
- return Err ( RewriteError :: MacroFailure {
1386
- kind : MacroErrorKind :: ReplaceMacroVariable ,
1387
- span : self . span ,
1388
- } ) ;
1389
- }
1390
- new_body = new_body. replace ( new, old) ;
1391
- }
1392
-
1393
- if has_block_body {
1394
- result += new_body. trim ( ) ;
1395
- } else if !new_body. is_empty ( ) {
1396
- result += "\n " ;
1397
- result += & new_body;
1398
- result += & shape. indent . to_string ( & config) ;
1399
- }
1400
-
1401
- result += "}" ;
1402
-
1403
- Ok ( result)
1452
+ Ok ( new_body)
1404
1453
}
1405
1454
}
1406
1455
@@ -1464,6 +1513,94 @@ fn format_lazy_static(
1464
1513
Ok ( result)
1465
1514
}
1466
1515
1516
+ fn format_cfg_select (
1517
+ context : & RewriteContext < ' _ > ,
1518
+ shape : Shape ,
1519
+ ts : TokenStream ,
1520
+ span : Span ,
1521
+ ) -> RewriteResult {
1522
+ let mut result = String :: with_capacity ( 1024 ) ;
1523
+
1524
+ result. push_str ( "cfg_select! {" ) ;
1525
+
1526
+ let branches = parse_cfg_select ( context, ts) . macro_error ( MacroErrorKind :: ParseFailure , span) ?;
1527
+
1528
+ let shape = shape
1529
+ . block_indent ( context. config . tab_spaces ( ) )
1530
+ . with_max_width ( context. config ) ;
1531
+
1532
+ // The cfg plus ` => {` should stay within the line length.
1533
+ let rule_shape = shape
1534
+ . sub_width ( " => {" . len ( ) )
1535
+ . max_width_error ( shape. width , span) ?;
1536
+
1537
+ result. push_str ( & shape. indent . to_string_with_newline ( context. config ) ) ;
1538
+
1539
+ for ( rule, rhs, _) in branches. reachable {
1540
+ result. push_str ( & rule. rewrite_result ( context, rule_shape) ?) ;
1541
+ result. push_str ( " =>" ) ;
1542
+ result. push_str ( & format_cfg_select_rhs ( context, shape, rhs) ?) ;
1543
+ }
1544
+
1545
+ if let Some ( ( _, rhs, _) ) = branches. wildcard {
1546
+ result. push_str ( "_ =>" ) ;
1547
+ result. push_str ( & format_cfg_select_rhs ( context, shape, rhs) ?) ;
1548
+ }
1549
+
1550
+ for ( lhs, rhs, _) in branches. unreachable {
1551
+ use rustc_parse:: parser:: cfg_select:: CfgSelectPredicate ;
1552
+
1553
+ match lhs {
1554
+ CfgSelectPredicate :: Cfg ( rule) => {
1555
+ result. push_str ( & rule. rewrite_result ( context, rule_shape) ?) ;
1556
+ }
1557
+ CfgSelectPredicate :: Wildcard ( _) => {
1558
+ result. push ( '_' ) ;
1559
+ }
1560
+ }
1561
+
1562
+ result. push_str ( " =>" ) ;
1563
+ result. push_str ( & format_cfg_select_rhs ( context, shape, rhs) ?) ;
1564
+ }
1565
+
1566
+ // Emit the final `}` at the correct indentation level.
1567
+ result. truncate ( result. len ( ) - context. config . tab_spaces ( ) ) ;
1568
+ result. push ( '}' ) ;
1569
+
1570
+ Ok ( result)
1571
+ }
1572
+
1573
+ fn format_cfg_select_rhs (
1574
+ context : & RewriteContext < ' _ > ,
1575
+ shape : Shape ,
1576
+ ts : TokenStream ,
1577
+ ) -> RewriteResult {
1578
+ let has_block_body = false ;
1579
+
1580
+ let span = ts
1581
+ . iter ( )
1582
+ . map ( |tt| tt. span ( ) )
1583
+ . reduce ( Span :: to)
1584
+ . unwrap_or_default ( ) ;
1585
+
1586
+ let old_body = context. snippet ( span) . trim ( ) ;
1587
+ let new_body =
1588
+ MacroBranch :: try_format_rhs ( & context. config , shape, has_block_body, old_body, span) ?;
1589
+
1590
+ let mut result = String :: new ( ) ;
1591
+ MacroBranch :: emit_formatted_body (
1592
+ & context. config ,
1593
+ & shape,
1594
+ & mut result,
1595
+ has_block_body,
1596
+ & new_body,
1597
+ ) ;
1598
+
1599
+ result. push_str ( & shape. indent . to_string_with_newline ( context. config ) ) ;
1600
+
1601
+ Ok ( result)
1602
+ }
1603
+
1467
1604
fn rewrite_macro_with_items (
1468
1605
context : & RewriteContext < ' _ > ,
1469
1606
items : & [ MacroArg ] ,
0 commit comments