@@ -361,6 +361,15 @@ struct ScalarEnumerationTraits<
361361 }
362362};
363363
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+
364373template <>
365374struct ScalarEnumerationTraits <FormatStyle::IndentExternBlockStyle> {
366375 static void enumeration (IO &IO, FormatStyle::IndentExternBlockStyle &Value) {
@@ -1042,6 +1051,7 @@ template <> struct MappingTraits<FormatStyle> {
10421051 Style.EmptyLineAfterAccessModifier );
10431052 IO.mapOptional (" EmptyLineBeforeAccessModifier" ,
10441053 Style.EmptyLineBeforeAccessModifier );
1054+ IO.mapOptional (" EnumTrailingComma" , Style.EnumTrailingComma );
10451055 IO.mapOptional (" ExperimentalAutoDetectBinPacking" ,
10461056 Style.ExperimentalAutoDetectBinPacking );
10471057 IO.mapOptional (" FixNamespaceComments" , Style.FixNamespaceComments );
@@ -1558,6 +1568,7 @@ FormatStyle getLLVMStyle(FormatStyle::LanguageKind Language) {
15581568 LLVMStyle.DisableFormat = false ;
15591569 LLVMStyle.EmptyLineAfterAccessModifier = FormatStyle::ELAAMS_Never;
15601570 LLVMStyle.EmptyLineBeforeAccessModifier = FormatStyle::ELBAMS_LogicalBlock;
1571+ LLVMStyle.EnumTrailingComma = FormatStyle::ETC_Leave;
15611572 LLVMStyle.ExperimentalAutoDetectBinPacking = false ;
15621573 LLVMStyle.FixNamespaceComments = true ;
15631574 LLVMStyle.ForEachMacros .push_back (" foreach" );
@@ -2203,6 +2214,21 @@ FormatStyle::GetLanguageStyle(FormatStyle::LanguageKind Language) const {
22032214
22042215namespace {
22052216
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+
22062232class ParensRemover : public TokenAnalyzer {
22072233public:
22082234 ParensRemover (const Environment &Env, const FormatStyle &Style)
@@ -2229,20 +2255,8 @@ class ParensRemover : public TokenAnalyzer {
22292255 continue ;
22302256 for (const auto *Token = Line->First ; Token && !Token->Finalized ;
22312257 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, " " );
22462260 }
22472261 }
22482262 }
@@ -2331,24 +2345,13 @@ class BracesRemover : public TokenAnalyzer {
23312345 const auto *NextLine = I + 1 == End ? nullptr : I[1 ];
23322346 for (const auto *Token = Line->First ; Token && !Token->Finalized ;
23332347 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))
23372349 continue ;
23382350 auto *Next = Token->Next ;
23392351 assert (Next || Token == Line->Last );
23402352 if (!Next && NextLine)
23412353 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);
23522355 }
23532356 }
23542357 }
@@ -2400,16 +2403,51 @@ class SemiRemover : public TokenAnalyzer {
24002403 assert (Next || Token == Line->Last );
24012404 if (!Next && NextLine)
24022405 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 , " ," )));
24092450 }
2410- const auto &Range =
2411- CharSourceRange::getCharRange (Start, Token->Tok .getEndLoc ());
2412- cantFail (Result.add (tooling::Replacement (SourceMgr, Range, " " )));
24132451 }
24142452 }
24152453 }
@@ -3812,6 +3850,13 @@ reformat(const FormatStyle &Style, StringRef Code,
38123850 });
38133851 }
38143852
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+
38153860 if (Style.FixNamespaceComments ) {
38163861 Passes.emplace_back ([&](const Environment &Env) {
38173862 return NamespaceEndCommentsFixer (Env, Expanded).process ();
0 commit comments