@@ -361,6 +361,7 @@ template <> struct MappingTraits<FormatStyle> {
361
361
Style .ExperimentalAutoDetectBinPacking );
362
362
IO.mapOptional (" FixNamespaceComments" , Style .FixNamespaceComments );
363
363
IO.mapOptional (" ForEachMacros" , Style .ForEachMacros );
364
+ IO.mapOptional (" IncludeBlocks" , Style .IncludeBlocks );
364
365
IO.mapOptional (" IncludeCategories" , Style .IncludeCategories );
365
366
IO.mapOptional (" IncludeIsMainRegex" , Style .IncludeIsMainRegex );
366
367
IO.mapOptional (" IndentCaseLabels" , Style .IndentCaseLabels );
@@ -444,6 +445,14 @@ template <> struct MappingTraits<FormatStyle::IncludeCategory> {
444
445
}
445
446
};
446
447
448
+ template <> struct ScalarEnumerationTraits <FormatStyle::IncludeBlocksStyle> {
449
+ static void enumeration (IO &IO, FormatStyle::IncludeBlocksStyle &Value) {
450
+ IO.enumCase (Value, " Preserve" , FormatStyle::IBS_Preserve);
451
+ IO.enumCase (Value, " Merge" , FormatStyle::IBS_Merge);
452
+ IO.enumCase (Value, " Regroup" , FormatStyle::IBS_Regroup);
453
+ }
454
+ };
455
+
447
456
template <> struct MappingTraits <FormatStyle::RawStringFormat> {
448
457
static void mapping (IO &IO, FormatStyle::RawStringFormat &Format) {
449
458
IO.mapOptional (" Delimiter" , Format.Delimiter );
@@ -614,6 +623,7 @@ FormatStyle getLLVMStyle() {
614
623
{" ^(<|\" (gtest|gmock|isl|json)/)" , 3 },
615
624
{" .*" , 1 }};
616
625
LLVMStyle.IncludeIsMainRegex = " (Test)?$" ;
626
+ LLVMStyle.IncludeBlocks = FormatStyle::IBS_Preserve;
617
627
LLVMStyle.IndentCaseLabels = false ;
618
628
LLVMStyle.IndentPPDirectives = FormatStyle::PPDIS_None;
619
629
LLVMStyle.IndentWrappedFunctionNames = false ;
@@ -1420,19 +1430,27 @@ static void sortCppIncludes(const FormatStyle &Style,
1420
1430
}),
1421
1431
Indices.end ());
1422
1432
1433
+ int CurrentCategory = Includes.front ().Category ;
1434
+
1423
1435
// If the #includes are out of order, we generate a single replacement fixing
1424
1436
// the entire block. Otherwise, no replacement is generated.
1425
1437
if (Indices.size () == Includes.size () &&
1426
- std::is_sorted (Indices.begin (), Indices.end ()))
1438
+ std::is_sorted (Indices.begin (), Indices.end ()) &&
1439
+ Style .IncludeBlocks == FormatStyle::IBS_Preserve)
1427
1440
return ;
1428
1441
1429
1442
std::string result;
1430
1443
for (unsigned Index : Indices) {
1431
- if (!result.empty ())
1444
+ if (!result.empty ()) {
1432
1445
result += " \n " ;
1446
+ if (Style .IncludeBlocks == FormatStyle::IBS_Regroup &&
1447
+ CurrentCategory != Includes[Index].Category )
1448
+ result += " \n " ;
1449
+ }
1433
1450
result += Includes[Index].Text ;
1434
1451
if (Cursor && CursorIndex == Index)
1435
1452
*Cursor = IncludesBeginOffset + result.size () - CursorToEOLOffset;
1453
+ CurrentCategory = Includes[Index].Category ;
1436
1454
}
1437
1455
1438
1456
auto Err = Replaces.add (tooling::Replacement (
@@ -1540,6 +1558,10 @@ tooling::Replacements sortCppIncludes(const FormatStyle &Style, StringRef Code,
1540
1558
else if (Trimmed == " // clang-format on" )
1541
1559
FormattingOff = false ;
1542
1560
1561
+ const bool EmptyLineSkipped =
1562
+ Trimmed.empty () && (Style .IncludeBlocks == FormatStyle::IBS_Merge ||
1563
+ Style .IncludeBlocks == FormatStyle::IBS_Regroup);
1564
+
1543
1565
if (!FormattingOff && !Line.endswith (" \\ " )) {
1544
1566
if (IncludeRegex.match (Line, &Matches)) {
1545
1567
StringRef IncludeName = Matches[2 ];
@@ -1549,7 +1571,7 @@ tooling::Replacements sortCppIncludes(const FormatStyle &Style, StringRef Code,
1549
1571
if (Category == 0 )
1550
1572
MainIncludeFound = true ;
1551
1573
IncludesInBlock.push_back ({IncludeName, Line, Prev, Category});
1552
- } else if (!IncludesInBlock.empty ()) {
1574
+ } else if (!IncludesInBlock.empty () && !EmptyLineSkipped ) {
1553
1575
sortCppIncludes (Style , IncludesInBlock, Ranges, FileName, Replaces,
1554
1576
Cursor);
1555
1577
IncludesInBlock.clear ();
0 commit comments