Index: clang/docs/ClangFormatStyleOptions.rst =================================================================== --- clang/docs/ClangFormatStyleOptions.rst +++ clang/docs/ClangFormatStyleOptions.rst @@ -3549,6 +3549,21 @@ For example: Q_UNUSED + Cases in switch block can be defined as StatementMacros. The behavior is + the same as 'case' in switch block. + + + .. code-block:: c++ + + switch (x) { + FOO: + break; + case 0: + break; + BAR(var) : + break; + } + **TabWidth** (``unsigned``) The number of columns used for tab stops. Index: clang/include/clang/Format/Format.h =================================================================== --- clang/include/clang/Format/Format.h +++ clang/include/clang/Format/Format.h @@ -2018,6 +2018,20 @@ /// clang-format aware of such cases. /// /// For example: Q_UNUSED + /// + /// Cases in switch block can be defined as StatementMacros. The behavior is + /// the same as 'case' in switch block. + /// + /// \code + /// switch (x) { + /// FOO: + /// break; + /// case 0: + /// break; + /// BAR(var) : + /// break; + /// } + /// \endcode std::vector StatementMacros; /// A vector of macros which are used to open namespace blocks. Index: clang/lib/Format/UnwrappedLineParser.h =================================================================== --- clang/lib/Format/UnwrappedLineParser.h +++ clang/lib/Format/UnwrappedLineParser.h @@ -84,10 +84,11 @@ private: void reset(); void parseFile(); - void parseLevel(bool HasOpeningBrace); + void parseLevel(bool HasOpeningBrace, bool InSwitchBlock = false); void parseBlock(bool MustBeDeclaration, unsigned AddLevels = 1u, bool MunchSemi = true, - bool UnindentWhitesmithsBraces = false); + bool UnindentWhitesmithsBraces = false, + bool InSwitchBlock = false); void parseChildBlock(); void parsePPDirective(); void parsePPDefine(); @@ -97,7 +98,7 @@ void parsePPEndIf(); void parsePPUnknown(); void readTokenWithJavaScriptASI(); - void parseStructuralElement(); + void parseStructuralElement(bool InLevelParsing = false); bool tryToParseBracedList(); bool parseBracedList(bool ContinueOnSemicolons = false, bool IsEnum = false, tok::TokenKind ClosingBraceKind = tok::r_brace); @@ -130,7 +131,7 @@ void parseObjCInterfaceOrImplementation(); bool parseObjCProtocol(); void parseJavaScriptEs6ImportExport(); - void parseStatementMacro(); + void parseStatementMacro(bool InLevelParsing = false); void parseCSharpAttribute(); // Parse a C# generic type constraint: `where T : IComparable`. // See: Index: clang/lib/Format/UnwrappedLineParser.cpp =================================================================== --- clang/lib/Format/UnwrappedLineParser.cpp +++ clang/lib/Format/UnwrappedLineParser.cpp @@ -365,7 +365,7 @@ } while (!eof()); } -void UnwrappedLineParser::parseLevel(bool HasOpeningBrace) { +void UnwrappedLineParser::parseLevel(bool HasOpeningBrace, bool InSwitchBlock) { bool SwitchLabelEncountered = false; do { tok::TokenKind kind = FormatTok->Tok.getKind(); @@ -374,7 +374,8 @@ } else if (FormatTok->getType() == TT_MacroBlockEnd) { kind = tok::r_brace; } - + if (FormatTok->is(TT_StatementMacro) && InSwitchBlock) + parseStructuralElement(/*InLevelParsing=*/true); switch (kind) { case tok::comment: nextToken(); @@ -581,7 +582,8 @@ void UnwrappedLineParser::parseBlock(bool MustBeDeclaration, unsigned AddLevels, bool MunchSemi, - bool UnindentWhitesmithsBraces) { + bool UnindentWhitesmithsBraces, + bool InSwitchBlock) { assert(FormatTok->isOneOf(tok::l_brace, TT_MacroBlockBegin) && "'{' or macro block token expected"); const bool MacroBlock = FormatTok->is(TT_MacroBlockBegin); @@ -618,7 +620,7 @@ MustBeDeclaration); if (AddLevels > 0u && Style.BreakBeforeBraces != FormatStyle::BS_Whitesmiths) Line->Level += AddLevels; - parseLevel(/*HasOpeningBrace=*/true); + parseLevel(/*HasOpeningBrace=*/true, InSwitchBlock); if (eof()) return; @@ -1040,7 +1042,7 @@ return addUnwrappedLine(); } -void UnwrappedLineParser::parseStructuralElement() { +void UnwrappedLineParser::parseStructuralElement(bool InLevelParsing) { assert(!FormatTok->is(tok::l_brace)); if (Style.Language == FormatStyle::LK_TableGen && FormatTok->is(tok::pp_include)) { @@ -1205,7 +1207,7 @@ } } if (Style.isCpp() && FormatTok->is(TT_StatementMacro)) { - parseStatementMacro(); + parseStatementMacro(InLevelParsing); return; } if (Style.isCpp() && FormatTok->is(TT_NamespaceMacro)) { @@ -2319,7 +2321,9 @@ parseParens(); if (FormatTok->Tok.is(tok::l_brace)) { CompoundStatementIndenter Indenter(this, Style, Line->Level); - parseBlock(/*MustBeDeclaration=*/false); + parseBlock(/*MustBeDeclaration=*/false, /*AddLevels=*/1u, + /*MunchSemi=*/true, /*UnindentWhitesmithsBraces=*/false, + /*InSwitchBlock=*/true); addUnwrappedLine(); } else { addUnwrappedLine(); @@ -2916,10 +2920,12 @@ } } -void UnwrappedLineParser::parseStatementMacro() { +void UnwrappedLineParser::parseStatementMacro(bool InLevelParsing) { nextToken(); if (FormatTok->is(tok::l_paren)) parseParens(); + if (InLevelParsing && FormatTok->is(tok::colon)) + parseLabel(); if (FormatTok->is(tok::semi)) nextToken(); addUnwrappedLine(); Index: clang/unittests/Format/FormatTest.cpp =================================================================== --- clang/unittests/Format/FormatTest.cpp +++ clang/unittests/Format/FormatTest.cpp @@ -3496,6 +3496,56 @@ getLLVMStyleWithColumns(11)); } +TEST_F(FormatTest, StatementMacroInSwitchBlock) { + FormatStyle Style = getLLVMStyle(); + Style.StatementMacros.push_back("FOO"); + Style.StatementMacros.push_back("BAR"); + verifyFormat("switch (x) {\n" + "FOO:\n" + " break;\n" + "case 0:\n" + " break;\n" + "FOO(var) :\n" + " break;\n" + "case 1:\n" + " break;\n" + "}", + Style); + // Check the class cases behavior + verifyFormat("switch (x) {\n" + " class S1 {};\n" + " class S2 : S1 {};\n" + " CLASS(x) : break;\n" + " CLASS(x) : S1{};\n" + "case 0:\n" + " class S3 {};\n" + " class S4 : public S3 {};\n" + "}", + Style); + verifyFormat("class FOO(x) : public x {\n" + "public:\n" + " int x;\n" + " FOO(int y) : x(y) {}\n" + "};", + Style); + // Check the TernaryOperators behaviour + Style.BreakBeforeTernaryOperators = false; + verifyFormat("return x > y ? FOO(x) : BAR(y);", Style); + // This option removes the space before the StatementMacro colon + Style.SpaceBeforeCtorInitializerColon = false; + verifyFormat("switch (x) {\n" + "FOO:\n" + " break;\n" + "case 0:\n" + " break;\n" + "FOO(var):\n" + " break;\n" + "case 1:\n" + " break;\n" + "}", + Style); +} + TEST_F(FormatTest, IndentPreprocessorDirectives) { FormatStyle Style = getLLVMStyle(); Style.IndentPPDirectives = FormatStyle::PPDIS_None;