Index: clang/include/clang/Format/Format.h =================================================================== --- clang/include/clang/Format/Format.h +++ clang/include/clang/Format/Format.h @@ -2018,6 +2018,19 @@ /// 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-block:: c + /// switch (x) { + /// FOO: + /// break; + /// case 0: + /// break; + /// BAR(var) : + /// break; + /// } 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 @@ -97,7 +97,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 +130,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 @@ -374,7 +374,8 @@ } else if (FormatTok->getType() == TT_MacroBlockEnd) { kind = tok::r_brace; } - + if (FormatTok->is(TT_StatementMacro)) + parseStructuralElement(/*inLevelParsing=*/true); switch (kind) { case tok::comment: nextToken(); @@ -1040,7 +1041,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 +1206,7 @@ } } if (Style.isCpp() && FormatTok->is(TT_StatementMacro)) { - parseStatementMacro(); + parseStatementMacro(inLevelParsing); return; } if (Style.isCpp() && FormatTok->is(TT_NamespaceMacro)) { @@ -2916,10 +2917,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,35 @@ getLLVMStyleWithColumns(11)); } +TEST_F(FormatTest, StatementMacroInSwitchBlock) { + FormatStyle Style = getLLVMStyle(); + Style.StatementMacros.push_back("FOO"); + verifyFormat("switch (x) {\n" + "FOO:\n" + " break;\n" + "case 0:\n" + " break;\n" + "FOO(var) :\n" + " break;\n" + "case 1:\n" + " break;\n" + "}", + 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;