@@ -361,6 +361,15 @@ struct ScalarEnumerationTraits<
361
361
}
362
362
};
363
363
364
+ template <>
365
+ struct ScalarEnumerationTraits <FormatStyle::EnumTrailingCommaStyle> {
366
+ static void enumeration (IO &IO, FormatStyle::EnumTrailingCommaStyle &Value) {
367
+ IO.enumCase (Value, " Leave" , FormatStyle::ETC_Leave);
368
+ IO.enumCase (Value, " Insert" , FormatStyle::ETC_Insert);
369
+ IO.enumCase (Value, " Remove" , FormatStyle::ETC_Remove);
370
+ }
371
+ };
372
+
364
373
template <>
365
374
struct ScalarEnumerationTraits <FormatStyle::IndentExternBlockStyle> {
366
375
static void enumeration (IO &IO, FormatStyle::IndentExternBlockStyle &Value) {
@@ -1042,6 +1051,7 @@ template <> struct MappingTraits<FormatStyle> {
1042
1051
Style .EmptyLineAfterAccessModifier );
1043
1052
IO.mapOptional (" EmptyLineBeforeAccessModifier" ,
1044
1053
Style .EmptyLineBeforeAccessModifier );
1054
+ IO.mapOptional (" EnumTrailingComma" , Style .EnumTrailingComma );
1045
1055
IO.mapOptional (" ExperimentalAutoDetectBinPacking" ,
1046
1056
Style .ExperimentalAutoDetectBinPacking );
1047
1057
IO.mapOptional (" FixNamespaceComments" , Style .FixNamespaceComments );
@@ -1558,6 +1568,7 @@ FormatStyle getLLVMStyle(FormatStyle::LanguageKind Language) {
1558
1568
LLVMStyle.DisableFormat = false ;
1559
1569
LLVMStyle.EmptyLineAfterAccessModifier = FormatStyle::ELAAMS_Never;
1560
1570
LLVMStyle.EmptyLineBeforeAccessModifier = FormatStyle::ELBAMS_LogicalBlock;
1571
+ LLVMStyle.EnumTrailingComma = FormatStyle::ETC_Leave;
1561
1572
LLVMStyle.ExperimentalAutoDetectBinPacking = false ;
1562
1573
LLVMStyle.FixNamespaceComments = true ;
1563
1574
LLVMStyle.ForEachMacros .push_back (" foreach" );
@@ -2203,6 +2214,21 @@ FormatStyle::GetLanguageStyle(FormatStyle::LanguageKind Language) const {
2203
2214
2204
2215
namespace {
2205
2216
2217
+ void replaceToken (const FormatToken &Token, FormatToken *Next,
2218
+ const SourceManager &SourceMgr, tooling::Replacements &Result,
2219
+ StringRef Text = " " ) {
2220
+ const auto &Tok = Token.Tok ;
2221
+ SourceLocation Start;
2222
+ if (Next && Next->NewlinesBefore == 0 && Next->isNot (tok::eof)) {
2223
+ Start = Tok.getLocation ();
2224
+ Next->WhitespaceRange = Token.WhitespaceRange ;
2225
+ } else {
2226
+ Start = Token.WhitespaceRange .getBegin ();
2227
+ }
2228
+ const auto &Range = CharSourceRange::getCharRange (Start, Tok.getEndLoc ());
2229
+ cantFail (Result.add (tooling::Replacement (SourceMgr, Range, Text)));
2230
+ }
2231
+
2206
2232
class ParensRemover : public TokenAnalyzer {
2207
2233
public:
2208
2234
ParensRemover (const Environment &Env, const FormatStyle &Style )
@@ -2229,20 +2255,8 @@ class ParensRemover : public TokenAnalyzer {
2229
2255
continue ;
2230
2256
for (const auto *Token = Line->First ; Token && !Token->Finalized ;
2231
2257
Token = Token->Next ) {
2232
- if (!Token->Optional || !Token->isOneOf (tok::l_paren, tok::r_paren))
2233
- continue ;
2234
- auto *Next = Token->Next ;
2235
- assert (Next && Next->isNot (tok::eof));
2236
- SourceLocation Start;
2237
- if (Next->NewlinesBefore == 0 ) {
2238
- Start = Token->Tok .getLocation ();
2239
- Next->WhitespaceRange = Token->WhitespaceRange ;
2240
- } else {
2241
- Start = Token->WhitespaceRange .getBegin ();
2242
- }
2243
- const auto &Range =
2244
- CharSourceRange::getCharRange (Start, Token->Tok .getEndLoc ());
2245
- cantFail (Result.add (tooling::Replacement (SourceMgr, Range, " " )));
2258
+ if (Token->Optional && Token->isOneOf (tok::l_paren, tok::r_paren))
2259
+ replaceToken (*Token, Token->Next , SourceMgr, Result, " " );
2246
2260
}
2247
2261
}
2248
2262
}
@@ -2331,24 +2345,13 @@ class BracesRemover : public TokenAnalyzer {
2331
2345
const auto *NextLine = I + 1 == End ? nullptr : I[1 ];
2332
2346
for (const auto *Token = Line->First ; Token && !Token->Finalized ;
2333
2347
Token = Token->Next ) {
2334
- if (!Token->Optional )
2335
- continue ;
2336
- if (!Token->isOneOf (tok::l_brace, tok::r_brace))
2348
+ if (!Token->Optional || !Token->isOneOf (tok::l_brace, tok::r_brace))
2337
2349
continue ;
2338
2350
auto *Next = Token->Next ;
2339
2351
assert (Next || Token == Line->Last );
2340
2352
if (!Next && NextLine)
2341
2353
Next = NextLine->First ;
2342
- SourceLocation Start;
2343
- if (Next && Next->NewlinesBefore == 0 && Next->isNot (tok::eof)) {
2344
- Start = Token->Tok .getLocation ();
2345
- Next->WhitespaceRange = Token->WhitespaceRange ;
2346
- } else {
2347
- Start = Token->WhitespaceRange .getBegin ();
2348
- }
2349
- const auto &Range =
2350
- CharSourceRange::getCharRange (Start, Token->Tok .getEndLoc ());
2351
- cantFail (Result.add (tooling::Replacement (SourceMgr, Range, " " )));
2354
+ replaceToken (*Token, Next, SourceMgr, Result);
2352
2355
}
2353
2356
}
2354
2357
}
@@ -2400,16 +2403,51 @@ class SemiRemover : public TokenAnalyzer {
2400
2403
assert (Next || Token == Line->Last );
2401
2404
if (!Next && NextLine)
2402
2405
Next = NextLine->First ;
2403
- SourceLocation Start;
2404
- if (Next && Next->NewlinesBefore == 0 && Next->isNot (tok::eof)) {
2405
- Start = Token->Tok .getLocation ();
2406
- Next->WhitespaceRange = Token->WhitespaceRange ;
2407
- } else {
2408
- Start = Token->WhitespaceRange .getBegin ();
2406
+ replaceToken (*Token, Next, SourceMgr, Result);
2407
+ }
2408
+ }
2409
+ }
2410
+ };
2411
+
2412
+ class EnumTrailingCommaEditor : public TokenAnalyzer {
2413
+ public:
2414
+ EnumTrailingCommaEditor (const Environment &Env, const FormatStyle &Style )
2415
+ : TokenAnalyzer(Env, Style ) {}
2416
+
2417
+ std::pair<tooling::Replacements, unsigned >
2418
+ analyze (TokenAnnotator &Annotator,
2419
+ SmallVectorImpl<AnnotatedLine *> &AnnotatedLines,
2420
+ FormatTokenLexer &Tokens) override {
2421
+ AffectedRangeMgr.computeAffectedLines (AnnotatedLines);
2422
+ tooling::Replacements Result;
2423
+ editEnumTrailingComma (AnnotatedLines, Result);
2424
+ return {Result, 0 };
2425
+ }
2426
+
2427
+ private:
2428
+ void editEnumTrailingComma (SmallVectorImpl<AnnotatedLine *> &Lines,
2429
+ tooling::Replacements &Result) {
2430
+ const auto &SourceMgr = Env.getSourceManager ();
2431
+ for (auto *Line : Lines) {
2432
+ if (!Line->Children .empty ())
2433
+ editEnumTrailingComma (Line->Children , Result);
2434
+ if (!Line->Affected )
2435
+ continue ;
2436
+ for (const auto *Token = Line->First ; Token && !Token->Finalized ;
2437
+ Token = Token->Next ) {
2438
+ if (Token->isNot (TT_EnumRBrace))
2439
+ continue ;
2440
+ const auto *BeforeRBrace = Token->getPreviousNonComment ();
2441
+ assert (BeforeRBrace);
2442
+ if (BeforeRBrace->is (TT_EnumLBrace)) // Empty braces.
2443
+ continue ;
2444
+ if (BeforeRBrace->is (tok::comma)) {
2445
+ if (Style .EnumTrailingComma == FormatStyle::ETC_Remove)
2446
+ replaceToken (*BeforeRBrace, BeforeRBrace->Next , SourceMgr, Result);
2447
+ } else if (Style .EnumTrailingComma == FormatStyle::ETC_Insert) {
2448
+ cantFail (Result.add (tooling::Replacement (
2449
+ SourceMgr, BeforeRBrace->Tok .getEndLoc (), 0 , " ," )));
2409
2450
}
2410
- const auto &Range =
2411
- CharSourceRange::getCharRange (Start, Token->Tok .getEndLoc ());
2412
- cantFail (Result.add (tooling::Replacement (SourceMgr, Range, " " )));
2413
2451
}
2414
2452
}
2415
2453
}
@@ -3812,6 +3850,13 @@ reformat(const FormatStyle &Style, StringRef Code,
3812
3850
});
3813
3851
}
3814
3852
3853
+ if (Style .EnumTrailingComma != FormatStyle::ETC_Leave) {
3854
+ Passes.emplace_back ([&](const Environment &Env) {
3855
+ return EnumTrailingCommaEditor (Env, Expanded)
3856
+ .process (/* SkipAnnotation=*/ true );
3857
+ });
3858
+ }
3859
+
3815
3860
if (Style .FixNamespaceComments ) {
3816
3861
Passes.emplace_back ([&](const Environment &Env) {
3817
3862
return NamespaceEndCommentsFixer (Env, Expanded).process ();
0 commit comments