diff --git a/clang/lib/Format/TokenAnnotator.cpp b/clang/lib/Format/TokenAnnotator.cpp --- a/clang/lib/Format/TokenAnnotator.cpp +++ b/clang/lib/Format/TokenAnnotator.cpp @@ -3662,12 +3662,51 @@ return true; } - if (isAllmanBrace(Left) || isAllmanBrace(Right)) - return (Line.startsWith(tok::kw_enum) && Style.BraceWrapping.AfterEnum) || - (Line.startsWith(tok::kw_typedef, tok::kw_enum) && - Style.BraceWrapping.AfterEnum) || - (Line.startsWith(tok::kw_class) && Style.BraceWrapping.AfterClass) || - (Line.startsWith(tok::kw_struct) && Style.BraceWrapping.AfterStruct); + if (isAllmanBrace(Left) || isAllmanBrace(Right)) { + // The tokens that could force an enum to not be on a single line are a + // trailing comment and a trailing comma on the last case. This checks for + // those. + auto isAllowedByShortEnums = [&]() { + if (!Style.AllowShortEnumsOnASingleLine) + return true; + + const char *remainingFile = Right.TokenText.data(); + size_t remainingLineCharCount = 1; + size_t whileIndex = remainingLineCharCount; + while (remainingFile[whileIndex] != ';' && + remainingFile[whileIndex] != '\0') { + if (remainingFile[whileIndex] != '\n' && + (remainingFile[whileIndex] == ' ' && + remainingFile[whileIndex - 1] == ' ')) { + remainingLineCharCount++; + } + whileIndex++; + } + + if (remainingLineCharCount + Right.OriginalColumn > Style.ColumnLimit) + return true; + + const FormatToken *breakingSearchToken = &Right; + while ((breakingSearchToken = breakingSearchToken->Next)) { + bool hasBreakingComma = breakingSearchToken->is(tok::comma) && + breakingSearchToken->Next->is(tok::r_brace); + if (breakingSearchToken->isTrailingComment() || hasBreakingComma) { + return true; + } + } + + return false; + }; + bool isAllowedByAfterEnum = + (Line.startsWith(tok::kw_enum) || + Line.startsWith(tok::kw_typedef, tok::kw_enum)) && + Style.BraceWrapping.AfterEnum; + return (Line.startsWith(tok::kw_class) && Style.BraceWrapping.AfterClass) || + (Line.startsWith(tok::kw_struct) && + Style.BraceWrapping.AfterStruct) || + (isAllowedByAfterEnum && isAllowedByShortEnums()); + } + if (Left.is(TT_ObjCBlockLBrace) && Style.AllowShortBlocksOnASingleLine == FormatStyle::SBS_Never) return true; diff --git a/clang/lib/Format/UnwrappedLineParser.cpp b/clang/lib/Format/UnwrappedLineParser.cpp --- a/clang/lib/Format/UnwrappedLineParser.cpp +++ b/clang/lib/Format/UnwrappedLineParser.cpp @@ -694,6 +694,8 @@ return Style.BraceWrapping.AfterUnion; if (InitialToken.is(tok::kw_struct)) return Style.BraceWrapping.AfterStruct; + if (InitialToken.is(tok::kw_enum)) + return Style.BraceWrapping.AfterEnum; return false; } @@ -2482,8 +2484,9 @@ return true; } - if (!Style.AllowShortEnumsOnASingleLine) + if (!Style.AllowShortEnumsOnASingleLine && Style.BraceWrapping.AfterEnum) addUnwrappedLine(); + // Parse enum body. nextToken(); if (!Style.AllowShortEnumsOnASingleLine) { diff --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp --- a/clang/unittests/Format/FormatTest.cpp +++ b/clang/unittests/Format/FormatTest.cpp @@ -1343,16 +1343,77 @@ FormatStyle Style = getLLVMStyle(); Style.AllowShortEnumsOnASingleLine = true; verifyFormat("enum { A, B, C } ShortEnum1, ShortEnum2;", Style); + verifyFormat("enum {\n" + " A,\n" + " B,\n" + " C,\n" + "} ShortEnum;", + Style); Style.AllowShortEnumsOnASingleLine = false; + verifyFormat("enum {\n" + " A,\n" + " B,\n" + " C\n" + "} ShortEnum1, ShortEnum2;", + Style); +} + +TEST_F(FormatTest, AfterEnum) { + FormatStyle Style = getLLVMStyle(); + Style.BreakBeforeBraces = FormatStyle::BS_Custom; + + Style.AllowShortEnumsOnASingleLine = true; + Style.BraceWrapping.AfterEnum = true; + verifyFormat("enum { A, B, C } Test1;", Style); + verifyFormat("enum\n" + "{\n" + " A,\n" + " B, // foo\n" + " C\n" + "} Test2;", + Style); + Style.BraceWrapping.AfterEnum = false; + verifyFormat("enum { A, B, C } Test3;", Style); + verifyFormat("enum {\n" + " A,\n" + " B, // foo\n" + " C\n" + "} Test4;", + Style); + + Style.AllowShortEnumsOnASingleLine = false; + Style.BraceWrapping.AfterEnum = true; verifyFormat("enum\n" "{\n" " A,\n" " B,\n" " C\n" - "} ShortEnum1, ShortEnum2;", + "} Test5;", + Style); + Style.BraceWrapping.AfterEnum = false; + verifyFormat("enum {\n" + " A,\n" + " B,\n" + " C\n" + "} Test6;", Style); } +TEST_F(FormatTest, AfterEnumShortEnums) { + FormatStyle Style = getLLVMStyle(); + Style.BreakBeforeBraces = FormatStyle::BS_Custom; + + Style.AllowShortEnumsOnASingleLine = true; + Style.BraceWrapping.AfterEnum = true; + verifyFormat("enum\n" + "{\n" + " A,\n" + " B,\n" + "} ShortEnum;", + Style); + verifyFormat("enum { A, B } ShortEnum;", Style); +} + TEST_F(FormatTest, ShortCaseLabels) { FormatStyle Style = getLLVMStyle(); Style.AllowShortCaseLabelsOnASingleLine = true; @@ -13367,6 +13428,8 @@ "}\n", AllmanBraceStyle); + AllmanBraceStyle.AllowShortEnumsOnASingleLine = false; + verifyFormat("enum X\n" "{\n" " Y = 0,\n" @@ -13378,6 +13441,15 @@ "}\n", AllmanBraceStyle); + AllmanBraceStyle.AllowShortEnumsOnASingleLine = true; + + verifyFormat("enum X\n" + "{\n" + " Y = 0,\n" + "}\n", + AllmanBraceStyle); + verifyFormat("enum X { Y = 0 }", AllmanBraceStyle); + verifyFormat("@interface BSApplicationController ()\n" "{\n" "@private\n"