Index: clang/lib/Format/FormatToken.h =================================================================== --- clang/lib/Format/FormatToken.h +++ clang/lib/Format/FormatToken.h @@ -43,12 +43,15 @@ TYPE(ConflictAlternative) \ TYPE(ConflictEnd) \ TYPE(ConflictStart) \ + /* l_brace of if/for/while */ \ + TYPE(ControlStatementLBrace) \ TYPE(CppCastLParen) \ TYPE(CtorInitializerColon) \ TYPE(CtorInitializerComma) \ TYPE(DesignatedInitializerLSquare) \ TYPE(DesignatedInitializerPeriod) \ TYPE(DictLiteral) \ + TYPE(ElseLBrace) \ TYPE(EnumLBrace) \ TYPE(FatArrow) \ TYPE(ForEachMacro) \ Index: clang/lib/Format/UnwrappedLineParser.h =================================================================== --- clang/lib/Format/UnwrappedLineParser.h +++ clang/lib/Format/UnwrappedLineParser.h @@ -92,12 +92,12 @@ void reset(); void parseFile(); bool precededByCommentOrPPDirective() const; - bool parseLevel(bool HasOpeningBrace, bool CanContainBracedList, + bool parseLevel(const FormatToken *OpeningBrace, bool CanContainBracedList, IfStmtKind *IfKind = nullptr, TokenType NextLBracesType = TT_Unknown); bool mightFitOnOneLine(UnwrappedLine &Line) const; IfStmtKind parseBlock(bool MustBeDeclaration = false, unsigned AddLevels = 1u, - bool MunchSemi = true, + bool MunchSemi = true, bool KeepBraces = true, bool UnindentWhitesmithsBraces = false, bool CanContainBracedList = true, TokenType NextLBracesType = TT_Unknown); @@ -126,7 +126,7 @@ bool handleCppAttributes(); FormatToken *parseIfThenElse(IfStmtKind *IfKind, bool KeepBraces = false); void parseTryCatch(); - void parseLoopBody(bool TryRemoveBraces, bool WrapRightBrace); + void parseLoopBody(bool KeepBraces, bool WrapRightBrace); void parseForOrWhileLoop(); void parseDoWhile(); void parseLabel(bool LeftAlignLabel = false); Index: clang/lib/Format/UnwrappedLineParser.cpp =================================================================== --- clang/lib/Format/UnwrappedLineParser.cpp +++ clang/lib/Format/UnwrappedLineParser.cpp @@ -394,7 +394,7 @@ if (Style.Language == FormatStyle::LK_TextProto) parseBracedList(); else - parseLevel(/*HasOpeningBrace=*/false, /*CanContainBracedList=*/true); + parseLevel(/*OpeningBrace=*/nullptr, /*CanContainBracedList=*/true); // Make sure to format the remaining tokens. // // LK_TextProto is special since its top-level is parsed as the body of a @@ -463,13 +463,13 @@ } /// \brief Parses a level, that is ???. -/// \param HasOpeningBrace If that level is started by an opening brace. +/// \param OpeningBrace Opening brace (\p nullptr if absent) of that level /// \param CanContainBracedList If the content can contain (at any level) a /// braced list. /// \param NextLBracesType The type for left brace found in this level. -/// \returns true if a simple block, or false otherwise. (A simple block has a -/// single statement.) -bool UnwrappedLineParser::parseLevel(bool HasOpeningBrace, +/// \returns true if a simple block of if/else/for/while, or false otherwise. +/// (A simple block has a single statement.) +bool UnwrappedLineParser::parseLevel(const FormatToken *OpeningBrace, bool CanContainBracedList, IfStmtKind *IfKind, TokenType NextLBracesType) { @@ -492,9 +492,9 @@ else if (FormatTok->getType() == TT_MacroBlockEnd) kind = tok::r_brace; - auto ParseDefault = [this, HasOpeningBrace, IfKind, NextLevelLBracesType, + auto ParseDefault = [this, OpeningBrace, IfKind, NextLevelLBracesType, &HasLabel, &StatementCount] { - parseStructuralElement(IfKind, !HasOpeningBrace, NextLevelLBracesType, + parseStructuralElement(IfKind, !OpeningBrace, NextLevelLBracesType, HasLabel ? nullptr : &HasLabel); ++StatementCount; assert(StatementCount > 0 && "StatementCount overflow!"); @@ -519,16 +519,17 @@ tryToParseBracedList()) continue; parseBlock(/*MustBeDeclaration=*/false, /*AddLevels=*/1u, - /*MunchSemi=*/true, /*UnindentWhitesmithBraces=*/false, - CanContainBracedList, - /*NextLBracesType=*/NextLBracesType); + /*MunchSemi=*/true, /*KeepBraces=*/true, + /*UnindentWhitesmithsBraces=*/false, CanContainBracedList, + NextLBracesType); ++StatementCount; assert(StatementCount > 0 && "StatementCount overflow!"); addUnwrappedLine(); break; case tok::r_brace: - if (HasOpeningBrace) { - if (!Style.RemoveBracesLLVM) + if (OpeningBrace) { + if (!Style.RemoveBracesLLVM || + !OpeningBrace->isOneOf(TT_ControlStatementLBrace, TT_ElseLBrace)) return false; if (FormatTok->isNot(tok::r_brace) || StatementCount != 1 || HasLabel || IsPrecededByCommentOrPPDirective || @@ -797,11 +798,10 @@ return Line.Level * Style.IndentWidth + Length <= ColumnLimit; } -UnwrappedLineParser::IfStmtKind -UnwrappedLineParser::parseBlock(bool MustBeDeclaration, unsigned AddLevels, - bool MunchSemi, bool UnindentWhitesmithsBraces, - bool CanContainBracedList, - TokenType NextLBracesType) { +UnwrappedLineParser::IfStmtKind UnwrappedLineParser::parseBlock( + bool MustBeDeclaration, unsigned AddLevels, bool MunchSemi, bool KeepBraces, + bool UnindentWhitesmithsBraces, bool CanContainBracedList, + TokenType NextLBracesType) { assert(FormatTok->isOneOf(tok::l_brace, TT_MacroBlockBegin) && "'{' or macro block token expected"); FormatToken *Tok = FormatTok; @@ -841,8 +841,8 @@ Line->Level += AddLevels; IfStmtKind IfKind = IfStmtKind::NotIf; - const bool SimpleBlock = parseLevel( - /*HasOpeningBrace=*/true, CanContainBracedList, &IfKind, NextLBracesType); + const bool SimpleBlock = + parseLevel(Tok, CanContainBracedList, &IfKind, NextLBracesType); if (eof()) return IfKind; @@ -854,7 +854,8 @@ return IfKind; } - if (SimpleBlock && Tok->is(tok::l_brace)) { + if (SimpleBlock && !KeepBraces && + Tok->isOneOf(TT_ControlStatementLBrace, TT_ElseLBrace)) { assert(FormatTok->is(tok::r_brace)); const FormatToken *Previous = Tokens->getPreviousToken(); assert(Previous); @@ -964,7 +965,9 @@ void UnwrappedLineParser::parseChildBlock( bool CanContainBracedList, clang::format::TokenType NextLBracesType) { + assert(FormatTok->is(tok::l_brace)); FormatTok->setBlockKind(BK_Block); + const FormatToken *OpeningBrace = FormatTok; nextToken(); { bool SkipIndent = (Style.isJavaScript() && @@ -973,8 +976,8 @@ ScopedDeclarationState DeclarationState(*Line, DeclarationScopeStack, /*MustBeDeclaration=*/false); Line->Level += SkipIndent ? 0 : 1; - parseLevel(/*HasOpeningBrace=*/true, CanContainBracedList, - /*IfKind=*/nullptr, NextLBracesType); + parseLevel(OpeningBrace, CanContainBracedList, /*IfKind=*/nullptr, + NextLBracesType); flushComments(isOnNewLine(*FormatTok)); Line->Level -= SkipIndent ? 0 : 1; } @@ -2474,13 +2477,12 @@ if (FormatTok->is(tok::exclaim)) nextToken(); - bool KeepIfBraces = false; - bool KeepElseBraces = false; + bool KeepIfBraces = true; if (FormatTok->is(tok::kw_consteval)) { - KeepIfBraces = true; - KeepElseBraces = true; nextToken(); } else { + if (Style.RemoveBracesLLVM) + KeepIfBraces = KeepBraces; if (FormatTok->isOneOf(tok::kw_constexpr, tok::identifier)) nextToken(); if (FormatTok->is(tok::l_paren)) @@ -2495,9 +2497,11 @@ IfStmtKind IfBlockKind = IfStmtKind::NotIf; if (FormatTok->is(tok::l_brace)) { + FormatTok->setFinalizedType(TT_ControlStatementLBrace); IfLeftBrace = FormatTok; CompoundStatementIndenter Indenter(this, Style, Line->Level); - IfBlockKind = parseBlock(); + IfBlockKind = parseBlock(/*MustBeDeclaration=*/false, /*AddLevels=*/1u, + /*MunchSemi=*/true, KeepIfBraces); if (Style.BraceWrapping.BeforeElse) addUnwrappedLine(); else @@ -2514,6 +2518,7 @@ IfBlockKind == IfStmtKind::IfElseIf; } + bool KeepElseBraces = KeepIfBraces; FormatToken *ElseLeftBrace = nullptr; IfStmtKind Kind = IfStmtKind::IfOnly; @@ -2525,9 +2530,11 @@ nextToken(); handleAttributes(); if (FormatTok->is(tok::l_brace)) { + FormatTok->setFinalizedType(TT_ElseLBrace); ElseLeftBrace = FormatTok; CompoundStatementIndenter Indenter(this, Style, Line->Level); - if (parseBlock() == IfStmtKind::IfOnly) + if (parseBlock(/*MustBeDeclaration=*/false, /*AddLevels=*/1u, + /*MunchSemi=*/true, KeepElseBraces) == IfStmtKind::IfOnly) Kind = IfStmtKind::IfElseIf; addUnwrappedLine(); } else if (FormatTok->is(tok::kw_if)) { @@ -2543,8 +2550,7 @@ Kind = IfStmtKind::IfElseIf; TooDeep = NestedTooDeep.pop_back_val(); } - ElseLeftBrace = - parseIfThenElse(/*IfKind=*/nullptr, KeepBraces || KeepIfBraces); + ElseLeftBrace = parseIfThenElse(/*IfKind=*/nullptr, KeepIfBraces); if (Style.RemoveBracesLLVM) NestedTooDeep.push_back(TooDeep); if (IsPrecededByComment) @@ -2569,7 +2575,7 @@ NestedTooDeep.pop_back(); - if (!KeepBraces && !KeepIfBraces && !KeepElseBraces) { + if (!KeepIfBraces && !KeepElseBraces) { markOptionalBraces(IfLeftBrace); markOptionalBraces(ElseLeftBrace); } else if (IfLeftBrace) { @@ -2720,9 +2726,8 @@ if (ManageWhitesmithsBraces) ++Line->Level; - parseBlock(/*MustBeDeclaration=*/true, AddLevels, - /*MunchSemi=*/true, - /*UnindentWhitesmithsBraces=*/ManageWhitesmithsBraces); + parseBlock(/*MustBeDeclaration=*/true, AddLevels, /*MunchSemi=*/true, + /*KeepBraces=*/true, ManageWhitesmithsBraces); // Munch the semicolon after a namespace. This is more common than one would // think. Putting the semicolon into its own line is very ugly. @@ -2775,15 +2780,17 @@ } while (!eof()); } -void UnwrappedLineParser::parseLoopBody(bool TryRemoveBraces, - bool WrapRightBrace) { +void UnwrappedLineParser::parseLoopBody(bool KeepBraces, bool WrapRightBrace) { keepAncestorBraces(); if (FormatTok->is(tok::l_brace)) { + if (!KeepBraces) + FormatTok->setFinalizedType(TT_ControlStatementLBrace); FormatToken *LeftBrace = FormatTok; CompoundStatementIndenter Indenter(this, Style, Line->Level); - parseBlock(); - if (TryRemoveBraces) { + parseBlock(/*MustBeDeclaration=*/false, /*AddLevels=*/1u, + /*MunchSemi=*/true, KeepBraces); + if (!KeepBraces) { assert(!NestedTooDeep.empty()); if (!NestedTooDeep.back()) markOptionalBraces(LeftBrace); @@ -2794,13 +2801,16 @@ parseUnbracedBody(); } - if (TryRemoveBraces) + if (!KeepBraces) NestedTooDeep.pop_back(); } void UnwrappedLineParser::parseForOrWhileLoop() { assert(FormatTok->isOneOf(tok::kw_for, tok::kw_while, TT_ForEachMacro) && "'for', 'while' or foreach macro expected"); + const bool KeepBraces = !Style.RemoveBracesLLVM || + !FormatTok->isOneOf(tok::kw_for, tok::kw_while); + nextToken(); // JS' for await ( ... if (Style.isJavaScript() && FormatTok->is(Keywords.kw_await)) @@ -2810,14 +2820,14 @@ if (FormatTok->is(tok::l_paren)) parseParens(); - parseLoopBody(Style.RemoveBracesLLVM, true); + parseLoopBody(KeepBraces, /*WrapRightBrace=*/true); } void UnwrappedLineParser::parseDoWhile() { assert(FormatTok->is(tok::kw_do) && "'do' expected"); nextToken(); - parseLoopBody(false, Style.BraceWrapping.BeforeWhile); + parseLoopBody(/*KeepBraces=*/true, Style.BraceWrapping.BeforeWhile); // FIXME: Add error handling. if (!FormatTok->is(tok::kw_while)) { @@ -3464,6 +3474,9 @@ } void UnwrappedLineParser::parseJavaEnumBody() { + assert(FormatTok->is(tok::l_brace)); + const FormatToken *OpeningBrace = FormatTok; + // Determine whether the enum is simple, i.e. does not have a semicolon or // constants with class bodies. Simple enums can be formatted like braced // lists, contracted to a single line, etc. @@ -3520,7 +3533,7 @@ } // Parse the class body after the enum's ";" if any. - parseLevel(/*HasOpeningBrace=*/true, /*CanContainBracedList=*/true); + parseLevel(OpeningBrace, /*CanContainBracedList=*/true); nextToken(); --Line->Level; addUnwrappedLine();