diff options
Diffstat (limited to 'clang/lib/Format/UnwrappedLineParser.cpp')
| -rw-r--r-- | clang/lib/Format/UnwrappedLineParser.cpp | 1546 |
1 files changed, 1113 insertions, 433 deletions
diff --git a/clang/lib/Format/UnwrappedLineParser.cpp b/clang/lib/Format/UnwrappedLineParser.cpp index 642679128409..d3383292f7a3 100644 --- a/clang/lib/Format/UnwrappedLineParser.cpp +++ b/clang/lib/Format/UnwrappedLineParser.cpp @@ -20,6 +20,7 @@ #include "llvm/Support/raw_ostream.h" #include <algorithm> +#include <utility> #define DEBUG_TYPE "format-parser" @@ -41,6 +42,12 @@ public: // getNextToken(). virtual FormatToken *peekNextToken() = 0; + // Returns the token that would be returned after the next N calls to + // getNextToken(). N needs to be greater than zero, and small enough that + // there are still tokens. Check for tok::eof with N-1 before calling it with + // N. + virtual FormatToken *peekNextToken(int N) = 0; + // Returns whether we are at the end of the file. // This can be different from whether getNextToken() returned an eof token // when the FormatTokenSource is a view on a part of the token stream. @@ -138,6 +145,13 @@ public: return PreviousTokenSource->peekNextToken(); } + FormatToken *peekNextToken(int N) override { + assert(N > 0); + if (eof()) + return &FakeEOF; + return PreviousTokenSource->peekNextToken(N); + } + bool isEOF() override { return PreviousTokenSource->isEOF(); } unsigned getPosition() override { return PreviousTokenSource->getPosition(); } @@ -184,9 +198,8 @@ public: } ~ScopedLineState() { - if (!Parser.Line->Tokens.empty()) { + if (!Parser.Line->Tokens.empty()) Parser.addUnwrappedLine(); - } assert(Parser.Line->Tokens.empty()); Parser.Line = std::move(PreBlockLine); if (Parser.CurrentLines == &Parser.PreprocessorDirectives) @@ -259,6 +272,16 @@ public: return Tokens[Next]; } + FormatToken *peekNextToken(int N) override { + assert(N > 0); + int Next = Position + N; + LLVM_DEBUG({ + llvm::dbgs() << "Peeking (+" << (N - 1) << ") "; + dbgToken(Next); + }); + return Tokens[Next]; + } + bool isEOF() override { return Tokens[Position]->is(tok::eof); } unsigned getPosition() override { @@ -335,10 +358,11 @@ void UnwrappedLineParser::parse() { // If we found an include guard then all preprocessor directives (other than // the guard) are over-indented by one. - if (IncludeGuard == IG_Found) + if (IncludeGuard == IG_Found) { for (auto &Line : Lines) if (Line.InPPDirective && Line.Level > 0) --Line.Level; + } // Create line with eof token. pushToken(FormatTok); @@ -371,7 +395,7 @@ void UnwrappedLineParser::parseFile() { if (Style.Language == FormatStyle::LK_TextProto) parseBracedList(); else - parseLevel(/*HasOpeningBrace=*/false); + parseLevel(); // Make sure to format the remaining tokens. // // LK_TextProto is special since its top-level is parsed as the body of a @@ -383,8 +407,9 @@ void UnwrappedLineParser::parseFile() { // do not have a chance to be put on a line of their own until this point. // Here we add this newline before end-of-file comments. if (Style.Language == FormatStyle::LK_TextProto && - !CommentsBeforeNextToken.empty()) + !CommentsBeforeNextToken.empty()) { addUnwrappedLine(); + } flushComments(true); addUnwrappedLine(); } @@ -439,46 +464,50 @@ bool UnwrappedLineParser::precededByCommentOrPPDirective() const { (Previous->IsMultiline || Previous->NewlinesBefore > 0); } -bool UnwrappedLineParser::mightFitOnOneLine() const { - const auto ColumnLimit = Style.ColumnLimit; - if (ColumnLimit == 0) - return true; - - if (Lines.empty()) - return true; - - const auto &PreviousLine = Lines.back(); - const auto &Tokens = PreviousLine.Tokens; - assert(!Tokens.empty()); - const auto *LastToken = Tokens.back().Tok; - assert(LastToken); - if (!LastToken->isOneOf(tok::semi, tok::comment)) - return true; - - AnnotatedLine Line(PreviousLine); - assert(Line.Last == LastToken); - - TokenAnnotator Annotator(Style, Keywords); - Annotator.annotate(Line); - Annotator.calculateFormattingInformation(Line); - - return Line.Level * Style.IndentWidth + LastToken->TotalLength <= ColumnLimit; -} - -// Returns true if a simple block, or false otherwise. (A simple block has a -// single statement that fits on a single line.) -bool UnwrappedLineParser::parseLevel(bool HasOpeningBrace, IfStmtKind *IfKind) { +/// \brief Parses a level, that is ???. +/// \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. +/// \param IfKind The \p if statement kind in the level. +/// \param IfLeftBrace The left brace of the \p if block in the level. +/// \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, + TokenType NextLBracesType, + IfStmtKind *IfKind, + FormatToken **IfLeftBrace) { + auto NextLevelLBracesType = NextLBracesType == TT_CompoundRequirementLBrace + ? TT_BracedListLBrace + : TT_Unknown; const bool IsPrecededByCommentOrPPDirective = !Style.RemoveBracesLLVM || precededByCommentOrPPDirective(); + FormatToken *IfLBrace = nullptr; + bool HasDoWhile = false; + bool HasLabel = false; unsigned StatementCount = 0; bool SwitchLabelEncountered = false; + do { + if (FormatTok->getType() == TT_AttributeMacro) { + nextToken(); + continue; + } tok::TokenKind kind = FormatTok->Tok.getKind(); - if (FormatTok->getType() == TT_MacroBlockBegin) { + if (FormatTok->getType() == TT_MacroBlockBegin) kind = tok::l_brace; - } else if (FormatTok->getType() == TT_MacroBlockEnd) { + else if (FormatTok->getType() == TT_MacroBlockEnd) kind = tok::r_brace; - } + + auto ParseDefault = [this, OpeningBrace, NextLevelLBracesType, IfKind, + &IfLBrace, &HasDoWhile, &HasLabel, &StatementCount] { + parseStructuralElement(!OpeningBrace, NextLevelLBracesType, IfKind, + &IfLBrace, HasDoWhile ? nullptr : &HasDoWhile, + HasLabel ? nullptr : &HasLabel); + ++StatementCount; + assert(StatementCount > 0 && "StatementCount overflow!"); + }; switch (kind) { case tok::comment: @@ -486,28 +515,44 @@ bool UnwrappedLineParser::parseLevel(bool HasOpeningBrace, IfStmtKind *IfKind) { addUnwrappedLine(); break; case tok::l_brace: - // FIXME: Add parameter whether this can happen - if this happens, we must - // be in a non-declaration context. - if (!FormatTok->is(TT_MacroBlockBegin) && tryToParseBracedList()) + if (NextLBracesType != TT_Unknown) { + FormatTok->setFinalizedType(NextLBracesType); + } else if (FormatTok->Previous && + FormatTok->Previous->ClosesRequiresClause) { + // We need the 'default' case here to correctly parse a function + // l_brace. + ParseDefault(); continue; - parseBlock(); + } + if (CanContainBracedList && !FormatTok->is(TT_MacroBlockBegin) && + tryToParseBracedList()) { + continue; + } + parseBlock(/*MustBeDeclaration=*/false, /*AddLevels=*/1u, + /*MunchSemi=*/true, /*KeepBraces=*/true, /*IfKind=*/nullptr, + /*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 || - IsPrecededByCommentOrPPDirective || + } + if (FormatTok->isNot(tok::r_brace) || StatementCount != 1 || HasLabel || + HasDoWhile || IsPrecededByCommentOrPPDirective || precededByCommentOrPPDirective()) { return false; } const FormatToken *Next = Tokens->peekNextToken(); if (Next->is(tok::comment) && Next->NewlinesBefore == 0) return false; - return mightFitOnOneLine(); + if (IfLeftBrace) + *IfLeftBrace = IfLBrace; + return true; } nextToken(); addUnwrappedLine(); @@ -517,9 +562,10 @@ bool UnwrappedLineParser::parseLevel(bool HasOpeningBrace, IfStmtKind *IfKind) { FormatToken *Next; do { Next = Tokens->getNextToken(); + assert(Next); } while (Next->is(tok::comment)); FormatTok = Tokens->setPosition(StoredPosition); - if (Next && Next->isNot(tok::colon)) { + if (Next->isNot(tok::colon)) { // default not followed by ':' is not a case label; treat it like // an identifier. parseStructuralElement(); @@ -535,8 +581,10 @@ bool UnwrappedLineParser::parseLevel(bool HasOpeningBrace, IfStmtKind *IfKind) { break; } if (!SwitchLabelEncountered && - (Style.IndentCaseLabels || (Line->InPPDirective && Line->Level == 1))) + (Style.IndentCaseLabels || + (Line->InPPDirective && Line->Level == 1))) { ++Line->Level; + } SwitchLabelEncountered = true; parseStructuralElement(); break; @@ -546,14 +594,15 @@ bool UnwrappedLineParser::parseLevel(bool HasOpeningBrace, IfStmtKind *IfKind) { parseCSharpAttribute(); break; } + if (handleCppAttributes()) + break; LLVM_FALLTHROUGH; default: - parseStructuralElement(IfKind, !HasOpeningBrace); - ++StatementCount; - assert(StatementCount > 0 && "StatementCount overflow!"); + ParseDefault(); break; } } while (!eof()); + return false; } @@ -569,20 +618,18 @@ void UnwrappedLineParser::calculateBraceTypes(bool ExpectClassBody) { // update information about whether an lbrace starts a // braced init list or a different block during the loop. SmallVector<FormatToken *, 8> LBraceStack; - assert(Tok->Tok.is(tok::l_brace)); + assert(Tok->is(tok::l_brace)); do { // Get next non-comment token. FormatToken *NextTok; - unsigned ReadTokens = 0; do { NextTok = Tokens->getNextToken(); - ++ReadTokens; } while (NextTok->is(tok::comment)); switch (Tok->Tok.getKind()) { case tok::l_brace: if (Style.isJavaScript() && PrevTok) { - if (PrevTok->isOneOf(tok::colon, tok::less)) + if (PrevTok->isOneOf(tok::colon, tok::less)) { // A ':' indicates this code is in a type, or a braced list // following a label in an object literal ({a: {b: 1}}). // A '<' could be an object used in a comparison, but that is nonsense @@ -593,9 +640,10 @@ void UnwrappedLineParser::calculateBraceTypes(bool ExpectClassBody) { // trigger BK_Block. In both cases, this must be parsed as an inline // braced init. Tok->setBlockKind(BK_BracedInit); - else if (PrevTok->is(tok::r_paren)) + } else if (PrevTok->is(tok::r_paren)) { // `) { }` can only occur in function or method declarations in JS. Tok->setBlockKind(BK_Block); + } } else { Tok->setBlockKind(BK_Unknown); } @@ -616,7 +664,6 @@ void UnwrappedLineParser::calculateBraceTypes(bool ExpectClassBody) { ScopedMacroState MacroState(*Line, Tokens, NextTok); do { NextTok = Tokens->getNextToken(); - ++ReadTokens; } while (NextTok->isNot(tok::eof)); } @@ -625,32 +672,50 @@ void UnwrappedLineParser::calculateBraceTypes(bool ExpectClassBody) { bool NextIsObjCMethod = NextTok->isOneOf(tok::plus, tok::minus) && NextTok->OriginalColumn == 0; + // Try to detect a braced list. Note that regardless how we mark inner + // braces here, we will overwrite the BlockKind later if we parse a + // braced list (where all blocks inside are by default braced lists), + // or when we explicitly detect blocks (for example while parsing + // lambdas). + + // If we already marked the opening brace as braced list, the closing + // must also be part of it. + ProbablyBracedList = LBraceStack.back()->is(TT_BracedListLBrace); + + ProbablyBracedList = ProbablyBracedList || + (Style.isJavaScript() && + NextTok->isOneOf(Keywords.kw_of, Keywords.kw_in, + Keywords.kw_as)); + ProbablyBracedList = ProbablyBracedList || + (Style.isCpp() && NextTok->is(tok::l_paren)); + // If there is a comma, semicolon or right paren after the closing - // brace, we assume this is a braced initializer list. Note that - // regardless how we mark inner braces here, we will overwrite the - // BlockKind later if we parse a braced list (where all blocks - // inside are by default braced lists), or when we explicitly detect - // blocks (for example while parsing lambdas). + // brace, we assume this is a braced initializer list. // FIXME: Some of these do not apply to JS, e.g. "} {" can never be a // braced list in JS. ProbablyBracedList = - (Style.isJavaScript() && - NextTok->isOneOf(Keywords.kw_of, Keywords.kw_in, - Keywords.kw_as)) || - (Style.isCpp() && NextTok->is(tok::l_paren)) || + ProbablyBracedList || NextTok->isOneOf(tok::comma, tok::period, tok::colon, tok::r_paren, tok::r_square, tok::l_brace, - tok::ellipsis) || + tok::ellipsis); + + ProbablyBracedList = + ProbablyBracedList || (NextTok->is(tok::identifier) && - !PrevTok->isOneOf(tok::semi, tok::r_brace, tok::l_brace)) || - (NextTok->is(tok::semi) && - (!ExpectClassBody || LBraceStack.size() != 1)) || + !PrevTok->isOneOf(tok::semi, tok::r_brace, tok::l_brace)); + + ProbablyBracedList = ProbablyBracedList || + (NextTok->is(tok::semi) && + (!ExpectClassBody || LBraceStack.size() != 1)); + + ProbablyBracedList = + ProbablyBracedList || (NextTok->isBinaryOperator() && !NextIsObjCMethod); + if (!Style.isCSharp() && NextTok->is(tok::l_square)) { // We can have an array subscript after a braced init // list, but C++11 attributes are expected after blocks. NextTok = Tokens->getNextToken(); - ++ReadTokens; ProbablyBracedList = NextTok->isNot(tok::l_square); } } @@ -684,13 +749,12 @@ void UnwrappedLineParser::calculateBraceTypes(bool ExpectClassBody) { } PrevTok = Tok; Tok = NextTok; - } while (Tok->Tok.isNot(tok::eof) && !LBraceStack.empty()); + } while (Tok->isNot(tok::eof) && !LBraceStack.empty()); // Assume other blocks for all unclosed opening braces. - for (FormatToken *LBrace : LBraceStack) { + for (FormatToken *LBrace : LBraceStack) if (LBrace->is(BK_Unknown)) LBrace->setBlockKind(BK_Block); - } FormatTok = Tokens->setPosition(StoredPosition); } @@ -710,13 +774,76 @@ size_t UnwrappedLineParser::computePPHash() const { return h; } -UnwrappedLineParser::IfStmtKind -UnwrappedLineParser::parseBlock(bool MustBeDeclaration, unsigned AddLevels, - bool MunchSemi, - bool UnindentWhitesmithsBraces) { - assert(FormatTok->isOneOf(tok::l_brace, TT_MacroBlockBegin) && +// Checks whether \p ParsedLine might fit on a single line. If \p OpeningBrace +// is not null, subtracts its length (plus the preceding space) when computing +// the length of \p ParsedLine. We must clone the tokens of \p ParsedLine before +// running the token annotator on it so that we can restore them afterward. +bool UnwrappedLineParser::mightFitOnOneLine( + UnwrappedLine &ParsedLine, const FormatToken *OpeningBrace) const { + const auto ColumnLimit = Style.ColumnLimit; + if (ColumnLimit == 0) + return true; + + auto &Tokens = ParsedLine.Tokens; + assert(!Tokens.empty()); + + const auto *LastToken = Tokens.back().Tok; + assert(LastToken); + + SmallVector<UnwrappedLineNode> SavedTokens(Tokens.size()); + + int Index = 0; + for (const auto &Token : Tokens) { + assert(Token.Tok); + auto &SavedToken = SavedTokens[Index++]; + SavedToken.Tok = new FormatToken; + SavedToken.Tok->copyFrom(*Token.Tok); + SavedToken.Children = std::move(Token.Children); + } + + AnnotatedLine Line(ParsedLine); + assert(Line.Last == LastToken); + + TokenAnnotator Annotator(Style, Keywords); + Annotator.annotate(Line); + Annotator.calculateFormattingInformation(Line); + + auto Length = LastToken->TotalLength; + if (OpeningBrace) { + assert(OpeningBrace != Tokens.front().Tok); + Length -= OpeningBrace->TokenText.size() + 1; + } + + Index = 0; + for (auto &Token : Tokens) { + const auto &SavedToken = SavedTokens[Index++]; + Token.Tok->copyFrom(*SavedToken.Tok); + Token.Children = std::move(SavedToken.Children); + delete SavedToken.Tok; + } + + return Line.Level * Style.IndentWidth + Length <= ColumnLimit; +} + +FormatToken *UnwrappedLineParser::parseBlock( + bool MustBeDeclaration, unsigned AddLevels, bool MunchSemi, bool KeepBraces, + IfStmtKind *IfKind, bool UnindentWhitesmithsBraces, + bool CanContainBracedList, TokenType NextLBracesType) { + auto HandleVerilogBlockLabel = [this]() { + // ":" name + if (Style.isVerilog() && FormatTok->is(tok::colon)) { + nextToken(); + if (Keywords.isVerilogIdentifier(*FormatTok)) + nextToken(); + } + }; + + assert((FormatTok->isOneOf(tok::l_brace, TT_MacroBlockBegin) || + (Style.isVerilog() && Keywords.isVerilogBegin(*FormatTok))) && "'{' or macro block token expected"); FormatToken *Tok = FormatTok; + const bool FollowedByComment = Tokens->peekNextToken()->is(tok::comment); + auto Index = CurrentLines->size(); const bool MacroBlock = FormatTok->is(TT_MacroBlockBegin); FormatTok->setBlockKind(BK_Block); @@ -727,8 +854,13 @@ UnwrappedLineParser::parseBlock(bool MustBeDeclaration, unsigned AddLevels, size_t PPStartHash = computePPHash(); - unsigned InitialLevel = Line->Level; + const unsigned InitialLevel = Line->Level; nextToken(/*LevelDifference=*/AddLevels); + HandleVerilogBlockLabel(); + + // Bail out if there are too many levels. Otherwise, the stack might overflow. + if (Line->Level > 300) + return nullptr; if (MacroBlock && FormatTok->is(tok::l_paren)) parseParens(); @@ -752,45 +884,77 @@ UnwrappedLineParser::parseBlock(bool MustBeDeclaration, unsigned AddLevels, if (AddLevels > 0u && Style.BreakBeforeBraces != FormatStyle::BS_Whitesmiths) Line->Level += AddLevels; - IfStmtKind IfKind = IfStmtKind::NotIf; - const bool SimpleBlock = parseLevel(/*HasOpeningBrace=*/true, &IfKind); + FormatToken *IfLBrace = nullptr; + const bool SimpleBlock = + parseLevel(Tok, CanContainBracedList, NextLBracesType, IfKind, &IfLBrace); if (eof()) - return IfKind; + return IfLBrace; if (MacroBlock ? !FormatTok->is(TT_MacroBlockEnd) : !FormatTok->is(tok::r_brace)) { Line->Level = InitialLevel; FormatTok->setBlockKind(BK_Block); - return IfKind; + return IfLBrace; } - if (SimpleBlock && Tok->is(tok::l_brace)) { + auto RemoveBraces = [=]() mutable { + if (!SimpleBlock) + return false; + assert(Tok->isOneOf(TT_ControlStatementLBrace, TT_ElseLBrace)); assert(FormatTok->is(tok::r_brace)); - const FormatToken *Previous = Tokens->getPreviousToken(); - assert(Previous); - if (Previous->isNot(tok::r_brace) || Previous->Optional) { - Tok->MatchingParen = FormatTok; - FormatTok->MatchingParen = Tok; + const bool WrappedOpeningBrace = !Tok->Previous; + if (WrappedOpeningBrace && FollowedByComment) + return false; + const bool HasRequiredIfBraces = IfLBrace && !IfLBrace->Optional; + if (KeepBraces && !HasRequiredIfBraces) + return false; + if (Tok->isNot(TT_ElseLBrace) || !HasRequiredIfBraces) { + const FormatToken *Previous = Tokens->getPreviousToken(); + assert(Previous); + if (Previous->is(tok::r_brace) && !Previous->Optional) + return false; } + assert(!CurrentLines->empty()); + auto &LastLine = CurrentLines->back(); + if (LastLine.Level == InitialLevel + 1 && !mightFitOnOneLine(LastLine)) + return false; + if (Tok->is(TT_ElseLBrace)) + return true; + if (WrappedOpeningBrace) { + assert(Index > 0); + --Index; // The line above the wrapped l_brace. + Tok = nullptr; + } + return mightFitOnOneLine((*CurrentLines)[Index], Tok); + }; + if (RemoveBraces()) { + Tok->MatchingParen = FormatTok; + FormatTok->MatchingParen = Tok; } size_t PPEndHash = computePPHash(); // Munch the closing brace. nextToken(/*LevelDifference=*/-AddLevels); + HandleVerilogBlockLabel(); if (MacroBlock && FormatTok->is(tok::l_paren)) parseParens(); + if (FormatTok->is(tok::kw_noexcept)) { + // A noexcept in a requires expression. + nextToken(); + } + if (FormatTok->is(tok::arrow)) { - // Following the } we can find a trailing return type arrow + // Following the } or noexcept we can find a trailing return type arrow // as part of an implicit conversion constraint. nextToken(); parseStructuralElement(); } - if (MunchSemi && FormatTok->Tok.is(tok::semi)) + if (MunchSemi && FormatTok->is(tok::semi)) nextToken(); Line->Level = InitialLevel; @@ -804,7 +968,7 @@ UnwrappedLineParser::parseBlock(bool MustBeDeclaration, unsigned AddLevels, } } - return IfKind; + return IfLBrace; } static bool isGoogScope(const UnwrappedLine &Line) { @@ -845,21 +1009,31 @@ static bool isIIFE(const UnwrappedLine &Line, static bool ShouldBreakBeforeBrace(const FormatStyle &Style, const FormatToken &InitialToken) { - if (InitialToken.isOneOf(tok::kw_namespace, TT_NamespaceMacro)) + tok::TokenKind Kind = InitialToken.Tok.getKind(); + if (InitialToken.is(TT_NamespaceMacro)) + Kind = tok::kw_namespace; + + switch (Kind) { + case tok::kw_namespace: return Style.BraceWrapping.AfterNamespace; - if (InitialToken.is(tok::kw_class)) + case tok::kw_class: return Style.BraceWrapping.AfterClass; - if (InitialToken.is(tok::kw_union)) + case tok::kw_union: return Style.BraceWrapping.AfterUnion; - if (InitialToken.is(tok::kw_struct)) + case tok::kw_struct: return Style.BraceWrapping.AfterStruct; - if (InitialToken.is(tok::kw_enum)) + case tok::kw_enum: return Style.BraceWrapping.AfterEnum; - return false; + default: + return false; + } } -void UnwrappedLineParser::parseChildBlock() { +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() && @@ -868,7 +1042,7 @@ void UnwrappedLineParser::parseChildBlock() { ScopedDeclarationState DeclarationState(*Line, DeclarationScopeStack, /*MustBeDeclaration=*/false); Line->Level += SkipIndent ? 0 : 1; - parseLevel(/*HasOpeningBrace=*/true); + parseLevel(OpeningBrace, CanContainBracedList, NextLBracesType); flushComments(isOnNewLine(*FormatTok)); Line->Level -= SkipIndent ? 0 : 1; } @@ -876,7 +1050,7 @@ void UnwrappedLineParser::parseChildBlock() { } void UnwrappedLineParser::parsePPDirective() { - assert(FormatTok->Tok.is(tok::hash) && "'#' expected"); + assert(FormatTok->is(tok::hash) && "'#' expected"); ScopedMacroState MacroState(*Line, Tokens, FormatTok); nextToken(); @@ -920,10 +1094,11 @@ void UnwrappedLineParser::conditionalCompilationCondition(bool Unreachable) { Line += Lines.size(); if (Unreachable || - (!PPStack.empty() && PPStack.back().Kind == PP_Unreachable)) + (!PPStack.empty() && PPStack.back().Kind == PP_Unreachable)) { PPStack.push_back({PP_Unreachable, Line}); - else + } else { PPStack.push_back({PP_Conditional, Line}); + } } void UnwrappedLineParser::conditionalCompilationStart(bool Unreachable) { @@ -952,9 +1127,8 @@ void UnwrappedLineParser::conditionalCompilationAlternative() { void UnwrappedLineParser::conditionalCompilationEnd() { assert(PPBranchLevel < (int)PPLevelBranchIndex.size()); if (PPBranchLevel >= 0 && !PPChainBranchIndex.empty()) { - if (PPChainBranchIndex.top() + 1 > PPLevelBranchCount[PPBranchLevel]) { + if (PPChainBranchIndex.top() + 1 > PPLevelBranchCount[PPBranchLevel]) PPLevelBranchCount[PPBranchLevel] = PPChainBranchIndex.top() + 1; - } } // Guard against #endif's without #if. if (PPBranchLevel > -1) @@ -978,7 +1152,7 @@ void UnwrappedLineParser::parsePPIf(bool IfDef) { // If there's a #ifndef on the first line, and the only lines before it are // comments, it could be an include guard. bool MaybeIncludeGuard = IfNDef; - if (IncludeGuard == IG_Inited && MaybeIncludeGuard) + if (IncludeGuard == IG_Inited && MaybeIncludeGuard) { for (auto &Line : Lines) { if (!Line.Tokens.front().Tok->is(tok::comment)) { MaybeIncludeGuard = false; @@ -986,6 +1160,7 @@ void UnwrappedLineParser::parsePPIf(bool IfDef) { break; } } + } --PPBranchLevel; parsePPUnknown(); ++PPBranchLevel; @@ -1014,8 +1189,9 @@ void UnwrappedLineParser::parsePPEndIf() { // If the #endif of a potential include guard is the last thing in the file, // then we found an include guard. if (IncludeGuard == IG_Defined && PPBranchLevel == -1 && Tokens->isEOF() && - Style.IndentPPDirectives != FormatStyle::PPDIS_None) + Style.IndentPPDirectives != FormatStyle::PPDIS_None) { IncludeGuard = IG_Found; + } } void UnwrappedLineParser::parsePPDefine() { @@ -1040,6 +1216,13 @@ void UnwrappedLineParser::parsePPDefine() { } } + // In the context of a define, even keywords should be treated as normal + // identifiers. Setting the kind to identifier is not enough, because we need + // to treat additional keywords like __except as well, which are already + // identifiers. Setting the identifier info to null interferes with include + // guard processing above, and changes preprocessing nesting. + FormatTok->Tok.setKind(tok::identifier); + FormatTok->Tok.setIdentifierInfo(Keywords.kw_internal_ident_after_define); nextToken(); if (FormatTok->Tok.getKind() == tok::l_paren && !FormatTok->hasWhitespaceBefore()) { @@ -1167,8 +1350,9 @@ static bool isC78ParameterDecl(const FormatToken *Tok, const FormatToken *Next, return false; if (!isC78Type(*Tok) && - !Tok->isOneOf(tok::kw_register, tok::kw_struct, tok::kw_union)) + !Tok->isOneOf(tok::kw_register, tok::kw_struct, tok::kw_union)) { return false; + } if (Next->isNot(tok::star) && !Next->Tok.getIdentifierInfo()) return false; @@ -1188,7 +1372,7 @@ void UnwrappedLineParser::parseModuleImport() { nextToken(); while (!eof()) { if (FormatTok->is(tok::colon)) { - FormatTok->setType(TT_ModulePartitionColon); + FormatTok->setFinalizedType(TT_ModulePartitionColon); } // Handle import <foo/bar.h> as we would an include statement. else if (FormatTok->is(tok::less)) { @@ -1197,8 +1381,9 @@ void UnwrappedLineParser::parseModuleImport() { // Mark tokens up to the trailing line comments as implicit string // literals. if (FormatTok->isNot(tok::comment) && - !FormatTok->TokenText.startswith("//")) - FormatTok->setType(TT_ImplicitStringLiteral); + !FormatTok->TokenText.startswith("//")) { + FormatTok->setFinalizedType(TT_ImplicitStringLiteral); + } nextToken(); } } @@ -1251,15 +1436,18 @@ void UnwrappedLineParser::readTokenWithJavaScriptASI() { if (NextMustBeValue && !NextEndsTemplateExpr && !PreviousStartsTemplateExpr && (PreviousMustBeValue || Previous->isOneOf(tok::r_square, tok::r_paren, tok::plusplus, - tok::minusminus))) + tok::minusminus))) { return addUnwrappedLine(); + } if ((PreviousMustBeValue || Previous->is(tok::r_paren)) && - isJSDeclOrStmt(Keywords, Next)) + isJSDeclOrStmt(Keywords, Next)) { return addUnwrappedLine(); + } } -void UnwrappedLineParser::parseStructuralElement(IfStmtKind *IfKind, - bool IsTopLevel) { +void UnwrappedLineParser::parseStructuralElement( + bool IsTopLevel, TokenType NextLBracesType, IfStmtKind *IfKind, + FormatToken **IfLeftBrace, bool *HasDoWhile, bool *HasLabel) { if (Style.Language == FormatStyle::LK_TableGen && FormatTok->is(tok::pp_include)) { nextToken(); @@ -1272,11 +1460,11 @@ void UnwrappedLineParser::parseStructuralElement(IfStmtKind *IfKind, case tok::kw_asm: nextToken(); if (FormatTok->is(tok::l_brace)) { - FormatTok->setType(TT_InlineASMBrace); + FormatTok->setFinalizedType(TT_InlineASMBrace); nextToken(); while (FormatTok && FormatTok->isNot(tok::eof)) { if (FormatTok->is(tok::r_brace)) { - FormatTok->setType(TT_InlineASMBrace); + FormatTok->setFinalizedType(TT_InlineASMBrace); nextToken(); addUnwrappedLine(); break; @@ -1293,40 +1481,51 @@ void UnwrappedLineParser::parseStructuralElement(IfStmtKind *IfKind, case tok::kw_protected: case tok::kw_private: if (Style.Language == FormatStyle::LK_Java || Style.isJavaScript() || - Style.isCSharp()) + Style.isCSharp()) { nextToken(); - else + } else { parseAccessSpecifier(); + } return; - case tok::kw_if: - if (Style.isJavaScript() && Line->MustBeDeclaration) + case tok::kw_if: { + if (Style.isJavaScript() && Line->MustBeDeclaration) { // field/method declaration. break; - parseIfThenElse(IfKind); + } + FormatToken *Tok = parseIfThenElse(IfKind); + if (IfLeftBrace) + *IfLeftBrace = Tok; return; + } case tok::kw_for: case tok::kw_while: - if (Style.isJavaScript() && Line->MustBeDeclaration) + if (Style.isJavaScript() && Line->MustBeDeclaration) { // field/method declaration. break; + } parseForOrWhileLoop(); return; case tok::kw_do: - if (Style.isJavaScript() && Line->MustBeDeclaration) + if (Style.isJavaScript() && Line->MustBeDeclaration) { // field/method declaration. break; + } parseDoWhile(); + if (HasDoWhile) + *HasDoWhile = true; return; case tok::kw_switch: - if (Style.isJavaScript() && Line->MustBeDeclaration) + if (Style.isJavaScript() && Line->MustBeDeclaration) { // 'switch: string' field declaration. break; + } parseSwitch(); return; case tok::kw_default: - if (Style.isJavaScript() && Line->MustBeDeclaration) + if (Style.isJavaScript() && Line->MustBeDeclaration) { // 'default: string' field declaration. break; + } nextToken(); if (FormatTok->is(tok::colon)) { parseLabel(); @@ -1335,23 +1534,26 @@ void UnwrappedLineParser::parseStructuralElement(IfStmtKind *IfKind, // e.g. "default void f() {}" in a Java interface. break; case tok::kw_case: - if (Style.isJavaScript() && Line->MustBeDeclaration) + if (Style.isJavaScript() && Line->MustBeDeclaration) { // 'case: string' field declaration. + nextToken(); break; + } parseCaseLabel(); return; case tok::kw_try: case tok::kw___try: - if (Style.isJavaScript() && Line->MustBeDeclaration) + if (Style.isJavaScript() && Line->MustBeDeclaration) { // field/method declaration. break; + } parseTryCatch(); return; case tok::kw_extern: nextToken(); - if (FormatTok->Tok.is(tok::string_literal)) { + if (FormatTok->is(tok::string_literal)) { nextToken(); - if (FormatTok->Tok.is(tok::l_brace)) { + if (FormatTok->is(tok::l_brace)) { if (Style.BraceWrapping.AfterExternBlock) addUnwrappedLine(); // Either we indent or for backwards compatibility we follow the @@ -1380,7 +1582,7 @@ void UnwrappedLineParser::parseStructuralElement(IfStmtKind *IfKind, LLVM_FALLTHROUGH; case tok::kw_inline: nextToken(); - if (FormatTok->Tok.is(tok::kw_namespace)) { + if (FormatTok->is(tok::kw_namespace)) { parseNamespace(); return; } @@ -1445,7 +1647,7 @@ void UnwrappedLineParser::parseStructuralElement(IfStmtKind *IfKind, switch (FormatTok->Tok.getKind()) { case tok::at: nextToken(); - if (FormatTok->Tok.is(tok::l_brace)) { + if (FormatTok->is(tok::l_brace)) { nextToken(); parseBracedList(); break; @@ -1476,23 +1678,26 @@ void UnwrappedLineParser::parseStructuralElement(IfStmtKind *IfKind, return; case tok::objc_autoreleasepool: nextToken(); - if (FormatTok->Tok.is(tok::l_brace)) { + if (FormatTok->is(tok::l_brace)) { if (Style.BraceWrapping.AfterControlStatement == - FormatStyle::BWACS_Always) + FormatStyle::BWACS_Always) { addUnwrappedLine(); + } parseBlock(); } addUnwrappedLine(); return; case tok::objc_synchronized: nextToken(); - if (FormatTok->Tok.is(tok::l_paren)) + if (FormatTok->is(tok::l_paren)) { // Skip synchronization object parseParens(); - if (FormatTok->Tok.is(tok::l_brace)) { + } + if (FormatTok->is(tok::l_brace)) { if (Style.BraceWrapping.AfterControlStatement == - FormatStyle::BWACS_Always) + FormatStyle::BWACS_Always) { addUnwrappedLine(); + } parseBlock(); } addUnwrappedLine(); @@ -1509,9 +1714,16 @@ void UnwrappedLineParser::parseStructuralElement(IfStmtKind *IfKind, case tok::kw_concept: parseConcept(); return; - case tok::kw_requires: - parseRequires(); - return; + case tok::kw_requires: { + if (Style.isCpp()) { + bool ParsedClause = parseRequires(); + if (ParsedClause) + return; + } else { + nextToken(); + } + break; + } case tok::kw_enum: // Ignore if this is part of "template <enum ...". if (Previous && Previous->is(tok::less)) { @@ -1534,27 +1746,29 @@ void UnwrappedLineParser::parseStructuralElement(IfStmtKind *IfKind, if (FormatTok->isOneOf(Keywords.kw_NS_ENUM, Keywords.kw_NS_OPTIONS, Keywords.kw_CF_ENUM, Keywords.kw_CF_OPTIONS, Keywords.kw_CF_CLOSED_ENUM, - Keywords.kw_NS_CLOSED_ENUM)) + Keywords.kw_NS_CLOSED_ENUM)) { parseEnum(); + } break; case tok::kw_struct: case tok::kw_union: case tok::kw_class: - if (parseStructLike()) { + if (parseStructLike()) return; - } break; case tok::period: nextToken(); // In Java, classes have an implicit static member "class". if (Style.Language == FormatStyle::LK_Java && FormatTok && - FormatTok->is(tok::kw_class)) + FormatTok->is(tok::kw_class)) { nextToken(); + } if (Style.isJavaScript() && FormatTok && - FormatTok->Tok.getIdentifierInfo()) + FormatTok->Tok.getIdentifierInfo()) { // JavaScript only has pseudo keywords, all keywords are allowed to // appear in "IdentifierName" positions. See http://es5.github.io/#x7.6 nextToken(); + } break; case tok::semi: nextToken(); @@ -1583,14 +1797,17 @@ void UnwrappedLineParser::parseStructuralElement(IfStmtKind *IfKind, case tok::caret: nextToken(); if (FormatTok->Tok.isAnyIdentifier() || - FormatTok->isSimpleTypeSpecifier()) + FormatTok->isSimpleTypeSpecifier()) { nextToken(); + } if (FormatTok->is(tok::l_paren)) parseParens(); if (FormatTok->is(tok::l_brace)) parseChildBlock(); break; case tok::l_brace: + if (NextLBracesType != TT_Unknown) + FormatTok->setFinalizedType(NextLBracesType); if (!tryToParsePropertyAccessor() && !tryToParseBracedList()) { // A block outside of parentheses must be the last part of a // structural element. @@ -1601,12 +1818,14 @@ void UnwrappedLineParser::parseStructuralElement(IfStmtKind *IfKind, // If necessary, we could set the type to something different than // TT_FunctionLBrace. if (Style.BraceWrapping.AfterControlStatement == - FormatStyle::BWACS_Always) + FormatStyle::BWACS_Always) { addUnwrappedLine(); + } } else if (Style.BraceWrapping.AfterFunction) { addUnwrappedLine(); } - FormatTok->setType(TT_FunctionLBrace); + if (!Line->InPPDirective) + FormatTok->setFinalizedType(TT_FunctionLBrace); parseBlock(); addUnwrappedLine(); return; @@ -1669,9 +1888,8 @@ void UnwrappedLineParser::parseStructuralElement(IfStmtKind *IfKind, } if (FormatTok->is(Keywords.kw_interface)) { - if (parseStructLike()) { + if (parseStructLike()) return; - } break; } @@ -1691,12 +1909,23 @@ void UnwrappedLineParser::parseStructuralElement(IfStmtKind *IfKind, if (Style.isJavaScript()) break; - TokenCount = Line->Tokens.size(); - if (TokenCount == 1 || - (TokenCount == 2 && Line->Tokens.front().Tok->is(tok::comment))) { - if (FormatTok->Tok.is(tok::colon) && !Line->MustBeDeclaration) { + auto OneTokenSoFar = [&]() { + const UnwrappedLineNode *Tok = &Line->Tokens.front(), + *End = Tok + Line->Tokens.size(); + while (Tok != End && Tok->Tok->is(tok::comment)) + ++Tok; + // In Verilog, macro invocations start with a backtick which the code + // treats as a hash. Skip it. + if (Style.isVerilog() && Tok != End && Tok->Tok->is(tok::hash)) + ++Tok; + return End - Tok == 1; + }; + if (OneTokenSoFar()) { + if (FormatTok->is(tok::colon) && !Line->MustBeDeclaration) { Line->Tokens.begin()->Tok->MustBreakBefore = true; parseLabel(!Style.IndentGotoLabels); + if (HasLabel) + *HasLabel = true; return; } // Recognize function-like macro usages without trailing semicolon as @@ -1712,7 +1941,7 @@ void UnwrappedLineParser::parseStructuralElement(IfStmtKind *IfKind, if (FollowedByNewline && (Text.size() >= 5 || FunctionLike) && tokenCanStartNewLine(*FormatTok) && Text == Text.upper()) { - PreviousToken->setType(TT_FunctionLikeOrFreestandingMacro); + PreviousToken->setFinalizedType(TT_FunctionLikeOrFreestandingMacro); addUnwrappedLine(); return; } @@ -1727,7 +1956,7 @@ void UnwrappedLineParser::parseStructuralElement(IfStmtKind *IfKind, } nextToken(); - if (FormatTok->Tok.is(tok::l_brace)) { + if (FormatTok->is(tok::l_brace)) { // Block kind should probably be set to BK_BracedInit for any language. // C# needs this change to ensure that array initialisers and object // initialisers are indented the same way. @@ -1736,7 +1965,7 @@ void UnwrappedLineParser::parseStructuralElement(IfStmtKind *IfKind, nextToken(); parseBracedList(); } else if (Style.Language == FormatStyle::LK_Proto && - FormatTok->Tok.is(tok::less)) { + FormatTok->is(tok::less)) { nextToken(); parseBracedList(/*ContinueOnSemicolons=*/false, /*IsEnum=*/false, /*ClosingBraceKind=*/tok::greater); @@ -1748,6 +1977,14 @@ void UnwrappedLineParser::parseStructuralElement(IfStmtKind *IfKind, case tok::kw_new: parseNew(); break; + case tok::kw_case: + if (Style.isJavaScript() && Line->MustBeDeclaration) { + // 'case: string' field declaration. + nextToken(); + break; + } + parseCaseLabel(); + break; default: nextToken(); break; @@ -1772,16 +2009,16 @@ bool UnwrappedLineParser::tryToParsePropertyAccessor() { FormatToken *Tok = Tokens->getNextToken(); // A trivial property accessor is of the form: - // { [ACCESS_SPECIFIER] [get]; [ACCESS_SPECIFIER] [set] } + // { [ACCESS_SPECIFIER] [get]; [ACCESS_SPECIFIER] [set|init] } // Track these as they do not require line breaks to be introduced. - bool HasGetOrSet = false; + bool HasSpecialAccessor = false; bool IsTrivialPropertyAccessor = true; while (!eof()) { if (Tok->isOneOf(tok::semi, tok::kw_public, tok::kw_private, tok::kw_protected, Keywords.kw_internal, Keywords.kw_get, - Keywords.kw_set)) { - if (Tok->isOneOf(Keywords.kw_get, Keywords.kw_set)) - HasGetOrSet = true; + Keywords.kw_init, Keywords.kw_set)) { + if (Tok->isOneOf(Keywords.kw_get, Keywords.kw_init, Keywords.kw_set)) + HasSpecialAccessor = true; Tok = Tokens->getNextToken(); continue; } @@ -1790,7 +2027,7 @@ bool UnwrappedLineParser::tryToParsePropertyAccessor() { break; } - if (!HasGetOrSet) { + if (!HasSpecialAccessor) { Tokens->setPosition(StoredPosition); return false; } @@ -1832,7 +2069,8 @@ bool UnwrappedLineParser::tryToParsePropertyAccessor() { nextToken(); break; default: - if (FormatTok->isOneOf(Keywords.kw_get, Keywords.kw_set) && + if (FormatTok->isOneOf(Keywords.kw_get, Keywords.kw_init, + Keywords.kw_set) && !IsTrivialPropertyAccessor) { // Non-trivial get/set needs to be on its own line. addUnwrappedLine(); @@ -1846,11 +2084,11 @@ bool UnwrappedLineParser::tryToParsePropertyAccessor() { } bool UnwrappedLineParser::tryToParseLambda() { + assert(FormatTok->is(tok::l_square)); if (!Style.isCpp()) { nextToken(); return false; } - assert(FormatTok->is(tok::l_square)); FormatToken &LSquare = *FormatTok; if (!tryToParseLambdaIntroducer()) return false; @@ -1936,7 +2174,7 @@ bool UnwrappedLineParser::tryToParseLambda() { // This might or might not actually be a lambda arrow (this could be an // ObjC method invocation followed by a dereferencing arrow). We might // reset this back to TT_Unknown in TokenAnnotator. - FormatTok->setType(TT_LambdaArrow); + FormatTok->setFinalizedType(TT_LambdaArrow); SeenArrow = true; nextToken(); break; @@ -1944,25 +2182,29 @@ bool UnwrappedLineParser::tryToParseLambda() { return true; } } - FormatTok->setType(TT_LambdaLBrace); - LSquare.setType(TT_LambdaLSquare); + FormatTok->setFinalizedType(TT_LambdaLBrace); + LSquare.setFinalizedType(TT_LambdaLSquare); parseChildBlock(); return true; } bool UnwrappedLineParser::tryToParseLambdaIntroducer() { const FormatToken *Previous = FormatTok->Previous; + const FormatToken *LeftSquare = FormatTok; + nextToken(); if (Previous && (Previous->isOneOf(tok::identifier, tok::kw_operator, tok::kw_new, tok::kw_delete, tok::l_square) || - FormatTok->isCppStructuredBinding(Style) || Previous->closesScope() || + LeftSquare->isCppStructuredBinding(Style) || Previous->closesScope() || Previous->isSimpleTypeSpecifier())) { - nextToken(); return false; } - nextToken(); - if (FormatTok->is(tok::l_square)) { + if (FormatTok->is(tok::l_square)) return false; + if (FormatTok->is(tok::r_square)) { + const FormatToken *Next = Tokens->peekNextToken(); + if (Next->is(tok::greater)) + return false; } parseSquare(/*LambdaIntroducer=*/true); return true; @@ -1978,7 +2220,7 @@ void UnwrappedLineParser::tryToParseJSFunction() { // Consume * (generator function). Treat it like C++'s overloaded operators. if (FormatTok->is(tok::star)) { - FormatTok->setType(TT_OverloadedOperator); + FormatTok->setFinalizedType(TT_OverloadedOperator); nextToken(); } @@ -2044,8 +2286,9 @@ bool UnwrappedLineParser::parseBracedList(bool ContinueOnSemicolons, // replace this by using parseAssignmentExpression() inside. do { if (Style.isCSharp() && FormatTok->is(TT_FatArrow) && - tryToParseChildBlock()) + tryToParseChildBlock()) { continue; + } if (Style.isJavaScript()) { if (FormatTok->is(Keywords.kw_function) || FormatTok->startsSequence(Keywords.kw_async, Keywords.kw_function)) { @@ -2090,7 +2333,8 @@ bool UnwrappedLineParser::parseBracedList(bool ContinueOnSemicolons, parseBracedList(); break; case tok::less: - if (Style.Language == FormatStyle::LK_Proto) { + if (Style.Language == FormatStyle::LK_Proto || + ClosingBraceKind == tok::greater) { nextToken(); parseBracedList(/*ContinueOnSemicolons=*/false, /*IsEnum=*/false, /*ClosingBraceKind=*/tok::greater); @@ -2125,8 +2369,11 @@ bool UnwrappedLineParser::parseBracedList(bool ContinueOnSemicolons, return false; } -void UnwrappedLineParser::parseParens() { - assert(FormatTok->Tok.is(tok::l_paren) && "'(' expected."); +/// \brief Parses a pair of parentheses (and everything between them). +/// \param AmpAmpTokenType If different than TT_Unknown sets this type for all +/// double ampersands. This only counts for the current parens scope. +void UnwrappedLineParser::parseParens(TokenType AmpAmpTokenType) { + assert(FormatTok->is(tok::l_paren) && "'(' expected."); nextToken(); do { switch (FormatTok->Tok.getKind()) { @@ -2150,7 +2397,7 @@ void UnwrappedLineParser::parseParens() { break; case tok::at: nextToken(); - if (FormatTok->Tok.is(tok::l_brace)) { + if (FormatTok->is(tok::l_brace)) { nextToken(); parseBracedList(); } @@ -2170,11 +2417,23 @@ void UnwrappedLineParser::parseParens() { case tok::identifier: if (Style.isJavaScript() && (FormatTok->is(Keywords.kw_function) || - FormatTok->startsSequence(Keywords.kw_async, Keywords.kw_function))) + FormatTok->startsSequence(Keywords.kw_async, + Keywords.kw_function))) { tryToParseJSFunction(); - else + } else { nextToken(); + } break; + case tok::kw_requires: { + auto RequiresToken = FormatTok; + nextToken(); + parseRequiresExpression(RequiresToken); + break; + } + case tok::ampamp: + if (AmpAmpTokenType != TT_Unknown) + FormatTok->setFinalizedType(AmpAmpTokenType); + LLVM_FALLTHROUGH; default: nextToken(); break; @@ -2184,7 +2443,7 @@ void UnwrappedLineParser::parseParens() { void UnwrappedLineParser::parseSquare(bool LambdaIntroducer) { if (!LambdaIntroducer) { - assert(FormatTok->Tok.is(tok::l_square) && "'[' expected."); + assert(FormatTok->is(tok::l_square) && "'[' expected."); if (tryToParseLambda()) return; } @@ -2209,7 +2468,7 @@ void UnwrappedLineParser::parseSquare(bool LambdaIntroducer) { } case tok::at: nextToken(); - if (FormatTok->Tok.is(tok::l_brace)) { + if (FormatTok->is(tok::l_brace)) { nextToken(); parseBracedList(); } @@ -2232,6 +2491,52 @@ void UnwrappedLineParser::keepAncestorBraces() { NestedTooDeep.push_back(false); } +static FormatToken *getLastNonComment(const UnwrappedLine &Line) { + for (const auto &Token : llvm::reverse(Line.Tokens)) + if (Token.Tok->isNot(tok::comment)) + return Token.Tok; + + return nullptr; +} + +void UnwrappedLineParser::parseUnbracedBody(bool CheckEOF) { + FormatToken *Tok = nullptr; + + if (Style.InsertBraces && !Line->InPPDirective && !Line->Tokens.empty() && + PreprocessorDirectives.empty()) { + Tok = getLastNonComment(*Line); + assert(Tok); + if (Tok->BraceCount < 0) { + assert(Tok->BraceCount == -1); + Tok = nullptr; + } else { + Tok->BraceCount = -1; + } + } + + addUnwrappedLine(); + ++Line->Level; + parseStructuralElement(); + + if (Tok) { + assert(!Line->InPPDirective); + Tok = nullptr; + for (const auto &L : llvm::reverse(*CurrentLines)) { + if (!L.InPPDirective && getLastNonComment(L)) { + Tok = L.Tokens.back().Tok; + break; + } + } + assert(Tok); + ++Tok->BraceCount; + } + + if (CheckEOF && FormatTok->is(tok::eof)) + addUnwrappedLine(); + + --Line->Level; +} + static void markOptionalBraces(FormatToken *LeftBrace) { if (!LeftBrace) return; @@ -2252,24 +2557,40 @@ static void markOptionalBraces(FormatToken *LeftBrace) { RightBrace->Optional = true; } +void UnwrappedLineParser::handleAttributes() { + // Handle AttributeMacro, e.g. `if (x) UNLIKELY`. + if (FormatTok->is(TT_AttributeMacro)) + nextToken(); + handleCppAttributes(); +} + +bool UnwrappedLineParser::handleCppAttributes() { + // Handle [[likely]] / [[unlikely]] attributes. + if (FormatTok->is(tok::l_square) && tryToParseSimpleAttribute()) { + parseSquare(); + return true; + } + return false; +} + FormatToken *UnwrappedLineParser::parseIfThenElse(IfStmtKind *IfKind, bool KeepBraces) { - auto HandleAttributes = [this]() { - // Handle AttributeMacro, e.g. `if (x) UNLIKELY`. - if (FormatTok->is(TT_AttributeMacro)) - nextToken(); - // Handle [[likely]] / [[unlikely]] attributes. - if (FormatTok->is(tok::l_square) && tryToParseSimpleAttribute()) - parseSquare(); - }; - - assert(FormatTok->Tok.is(tok::kw_if) && "'if' expected"); + assert(FormatTok->is(tok::kw_if) && "'if' expected"); nextToken(); - if (FormatTok->Tok.isOneOf(tok::kw_constexpr, tok::identifier)) + if (FormatTok->is(tok::exclaim)) nextToken(); - if (FormatTok->Tok.is(tok::l_paren)) - parseParens(); - HandleAttributes(); + + bool KeepIfBraces = true; + if (FormatTok->is(tok::kw_consteval)) { + nextToken(); + } else { + KeepIfBraces = !Style.RemoveBracesLLVM || KeepBraces; + if (FormatTok->isOneOf(tok::kw_constexpr, tok::identifier)) + nextToken(); + if (FormatTok->is(tok::l_paren)) + parseParens(); + } + handleAttributes(); bool NeedsUnwrappedLine = false; keepAncestorBraces(); @@ -2277,48 +2598,62 @@ FormatToken *UnwrappedLineParser::parseIfThenElse(IfStmtKind *IfKind, FormatToken *IfLeftBrace = nullptr; IfStmtKind IfBlockKind = IfStmtKind::NotIf; - if (FormatTok->Tok.is(tok::l_brace)) { + if (Keywords.isBlockBegin(*FormatTok, Style)) { + FormatTok->setFinalizedType(TT_ControlStatementLBrace); IfLeftBrace = FormatTok; CompoundStatementIndenter Indenter(this, Style, Line->Level); - IfBlockKind = parseBlock(); + parseBlock(/*MustBeDeclaration=*/false, /*AddLevels=*/1u, + /*MunchSemi=*/true, KeepIfBraces, &IfBlockKind); if (Style.BraceWrapping.BeforeElse) addUnwrappedLine(); else NeedsUnwrappedLine = true; } else { - addUnwrappedLine(); - ++Line->Level; - parseStructuralElement(); - --Line->Level; + parseUnbracedBody(); } - bool KeepIfBraces = false; if (Style.RemoveBracesLLVM) { assert(!NestedTooDeep.empty()); - KeepIfBraces = (IfLeftBrace && !IfLeftBrace->MatchingParen) || + KeepIfBraces = KeepIfBraces || + (IfLeftBrace && !IfLeftBrace->MatchingParen) || NestedTooDeep.back() || IfBlockKind == IfStmtKind::IfOnly || IfBlockKind == IfStmtKind::IfElseIf; } + bool KeepElseBraces = KeepIfBraces; FormatToken *ElseLeftBrace = nullptr; IfStmtKind Kind = IfStmtKind::IfOnly; - if (FormatTok->Tok.is(tok::kw_else)) { + if (FormatTok->is(tok::kw_else)) { if (Style.RemoveBracesLLVM) { NestedTooDeep.back() = false; Kind = IfStmtKind::IfElse; } nextToken(); - HandleAttributes(); - if (FormatTok->Tok.is(tok::l_brace)) { + handleAttributes(); + if (Keywords.isBlockBegin(*FormatTok, Style)) { + const bool FollowedByIf = Tokens->peekNextToken()->is(tok::kw_if); + FormatTok->setFinalizedType(TT_ElseLBrace); ElseLeftBrace = FormatTok; CompoundStatementIndenter Indenter(this, Style, Line->Level); - if (parseBlock() == IfStmtKind::IfOnly) - Kind = IfStmtKind::IfElseIf; + IfStmtKind ElseBlockKind = IfStmtKind::NotIf; + FormatToken *IfLBrace = + parseBlock(/*MustBeDeclaration=*/false, /*AddLevels=*/1u, + /*MunchSemi=*/true, KeepElseBraces, &ElseBlockKind); + if (FormatTok->is(tok::kw_else)) { + KeepElseBraces = KeepElseBraces || + ElseBlockKind == IfStmtKind::IfOnly || + ElseBlockKind == IfStmtKind::IfElseIf; + } else if (FollowedByIf && IfLBrace && !IfLBrace->Optional) { + KeepElseBraces = true; + assert(ElseLeftBrace->MatchingParen); + markOptionalBraces(ElseLeftBrace); + } addUnwrappedLine(); - } else if (FormatTok->Tok.is(tok::kw_if)) { - FormatToken *Previous = Tokens->getPreviousToken(); - const bool IsPrecededByComment = Previous && Previous->is(tok::comment); + } else if (FormatTok->is(tok::kw_if)) { + const FormatToken *Previous = Tokens->getPreviousToken(); + assert(Previous); + const bool IsPrecededByComment = Previous->is(tok::comment); if (IsPrecededByComment) { addUnwrappedLine(); ++Line->Level; @@ -2328,23 +2663,16 @@ FormatToken *UnwrappedLineParser::parseIfThenElse(IfStmtKind *IfKind, 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) --Line->Level; } else { - addUnwrappedLine(); - ++Line->Level; - parseStructuralElement(); - if (FormatTok->is(tok::eof)) - addUnwrappedLine(); - --Line->Level; + parseUnbracedBody(/*CheckEOF=*/true); } } else { - if (Style.RemoveBracesLLVM) - KeepIfBraces = KeepIfBraces || IfBlockKind == IfStmtKind::IfElse; + KeepIfBraces = KeepIfBraces || IfBlockKind == IfStmtKind::IfElse; if (NeedsUnwrappedLine) addUnwrappedLine(); } @@ -2353,12 +2681,13 @@ FormatToken *UnwrappedLineParser::parseIfThenElse(IfStmtKind *IfKind, return nullptr; assert(!NestedTooDeep.empty()); - const bool KeepElseBraces = - (ElseLeftBrace && !ElseLeftBrace->MatchingParen) || NestedTooDeep.back(); + KeepElseBraces = KeepElseBraces || + (ElseLeftBrace && !ElseLeftBrace->MatchingParen) || + NestedTooDeep.back(); NestedTooDeep.pop_back(); - if (!KeepBraces && !KeepIfBraces && !KeepElseBraces) { + if (!KeepIfBraces && !KeepElseBraces) { markOptionalBraces(IfLeftBrace); markOptionalBraces(ElseLeftBrace); } else if (IfLeftBrace) { @@ -2410,20 +2739,18 @@ void UnwrappedLineParser::parseTryCatch() { } } // Parse try with resource. - if (Style.Language == FormatStyle::LK_Java && FormatTok->is(tok::l_paren)) { + if (Style.Language == FormatStyle::LK_Java && FormatTok->is(tok::l_paren)) parseParens(); - } keepAncestorBraces(); if (FormatTok->is(tok::l_brace)) { CompoundStatementIndenter Indenter(this, Style, Line->Level); parseBlock(); - if (Style.BraceWrapping.BeforeCatch) { + if (Style.BraceWrapping.BeforeCatch) addUnwrappedLine(); - } else { + else NeedsUnwrappedLine = true; - } } else if (!FormatTok->is(tok::kw_catch)) { // The C++ standard requires a compound-statement after a try. // If there's none, we try to assume there's a structuralElement @@ -2440,9 +2767,10 @@ void UnwrappedLineParser::parseTryCatch() { tok::kw___finally) || ((Style.Language == FormatStyle::LK_Java || Style.isJavaScript()) && FormatTok->is(Keywords.kw_finally)) || - (FormatTok->Tok.isObjCAtKeyword(tok::objc_catch) || - FormatTok->Tok.isObjCAtKeyword(tok::objc_finally)))) + (FormatTok->isObjCAtKeyword(tok::objc_catch) || + FormatTok->isObjCAtKeyword(tok::objc_finally)))) { break; + } nextToken(); while (FormatTok->isNot(tok::l_brace)) { if (FormatTok->is(tok::l_paren)) { @@ -2457,6 +2785,7 @@ void UnwrappedLineParser::parseTryCatch() { nextToken(); } NeedsUnwrappedLine = false; + Line->MustBeDeclaration = false; CompoundStatementIndenter Indenter(this, Style, Line->Level); parseBlock(); if (Style.BraceWrapping.BeforeCatch) @@ -2482,15 +2811,17 @@ void UnwrappedLineParser::parseNamespace() { parseParens(); } else { while (FormatTok->isOneOf(tok::identifier, tok::coloncolon, tok::kw_inline, - tok::l_square, tok::period) || + tok::l_square, tok::period, tok::l_paren) || (Style.isCSharp() && FormatTok->is(tok::kw_union))) { if (FormatTok->is(tok::l_square)) parseSquare(); + else if (FormatTok->is(tok::l_paren)) + parseParens(); else nextToken(); } } - if (FormatTok->Tok.is(tok::l_brace)) { + if (FormatTok->is(tok::l_brace)) { if (ShouldBreakBeforeBrace(Style, InitialToken)) addUnwrappedLine(); @@ -2509,13 +2840,13 @@ void UnwrappedLineParser::parseNamespace() { if (ManageWhitesmithsBraces) ++Line->Level; - parseBlock(/*MustBeDeclaration=*/true, AddLevels, - /*MunchSemi=*/true, - /*UnindentWhitesmithsBraces=*/ManageWhitesmithsBraces); + parseBlock(/*MustBeDeclaration=*/true, AddLevels, /*MunchSemi=*/true, + /*KeepBraces=*/true, /*IfKind=*/nullptr, + 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. - if (FormatTok->Tok.is(tok::semi)) + if (FormatTok->is(tok::semi)) nextToken(); addUnwrappedLine(AddLevels > 0 ? LineLevel::Remove : LineLevel::Keep); @@ -2564,64 +2895,58 @@ void UnwrappedLineParser::parseNew() { } while (!eof()); } -void UnwrappedLineParser::parseForOrWhileLoop() { - assert(FormatTok->isOneOf(tok::kw_for, tok::kw_while, TT_ForEachMacro) && - "'for', 'while' or foreach macro expected"); - nextToken(); - // JS' for await ( ... - if (Style.isJavaScript() && FormatTok->is(Keywords.kw_await)) - nextToken(); - if (Style.isCpp() && FormatTok->is(tok::kw_co_await)) - nextToken(); - if (FormatTok->Tok.is(tok::l_paren)) - parseParens(); - +void UnwrappedLineParser::parseLoopBody(bool KeepBraces, bool WrapRightBrace) { keepAncestorBraces(); - if (FormatTok->Tok.is(tok::l_brace)) { + if (Keywords.isBlockBegin(*FormatTok, Style)) { + if (!KeepBraces) + FormatTok->setFinalizedType(TT_ControlStatementLBrace); FormatToken *LeftBrace = FormatTok; CompoundStatementIndenter Indenter(this, Style, Line->Level); - parseBlock(); - if (Style.RemoveBracesLLVM) { + parseBlock(/*MustBeDeclaration=*/false, /*AddLevels=*/1u, + /*MunchSemi=*/true, KeepBraces); + if (!KeepBraces) { assert(!NestedTooDeep.empty()); if (!NestedTooDeep.back()) markOptionalBraces(LeftBrace); } - addUnwrappedLine(); + if (WrapRightBrace) + addUnwrappedLine(); } else { - addUnwrappedLine(); - ++Line->Level; - parseStructuralElement(); - --Line->Level; + parseUnbracedBody(); } - if (Style.RemoveBracesLLVM) + if (!KeepBraces) NestedTooDeep.pop_back(); } -void UnwrappedLineParser::parseDoWhile() { - assert(FormatTok->Tok.is(tok::kw_do) && "'do' expected"); +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)) + nextToken(); + if (Style.isCpp() && FormatTok->is(tok::kw_co_await)) + nextToken(); + if (FormatTok->is(tok::l_paren)) + parseParens(); - keepAncestorBraces(); + handleAttributes(); + parseLoopBody(KeepBraces, /*WrapRightBrace=*/true); +} - if (FormatTok->Tok.is(tok::l_brace)) { - CompoundStatementIndenter Indenter(this, Style, Line->Level); - parseBlock(); - if (Style.BraceWrapping.BeforeWhile) - addUnwrappedLine(); - } else { - addUnwrappedLine(); - ++Line->Level; - parseStructuralElement(); - --Line->Level; - } +void UnwrappedLineParser::parseDoWhile() { + assert(FormatTok->is(tok::kw_do) && "'do' expected"); + nextToken(); - if (Style.RemoveBracesLLVM) - NestedTooDeep.pop_back(); + parseLoopBody(/*KeepBraces=*/true, Style.BraceWrapping.BeforeWhile); // FIXME: Add error handling. - if (!FormatTok->Tok.is(tok::kw_while)) { + if (!FormatTok->is(tok::kw_while)) { addUnwrappedLine(); return; } @@ -2644,13 +2969,13 @@ void UnwrappedLineParser::parseLabel(bool LeftAlignLabel) { Line->Level = 0; if (!Style.IndentCaseBlocks && CommentsBeforeNextToken.empty() && - FormatTok->Tok.is(tok::l_brace)) { + FormatTok->is(tok::l_brace)) { CompoundStatementIndenter Indenter(this, Line->Level, Style.BraceWrapping.AfterCaseLabel, Style.BraceWrapping.IndentBraces); parseBlock(); - if (FormatTok->Tok.is(tok::kw_break)) { + if (FormatTok->is(tok::kw_break)) { if (Style.BraceWrapping.AfterControlStatement == FormatStyle::BWACS_Always) { addUnwrappedLine(); @@ -2675,24 +3000,24 @@ void UnwrappedLineParser::parseLabel(bool LeftAlignLabel) { } void UnwrappedLineParser::parseCaseLabel() { - assert(FormatTok->Tok.is(tok::kw_case) && "'case' expected"); + assert(FormatTok->is(tok::kw_case) && "'case' expected"); // FIXME: fix handling of complex expressions here. do { nextToken(); - } while (!eof() && !FormatTok->Tok.is(tok::colon)); + } while (!eof() && !FormatTok->is(tok::colon)); parseLabel(); } void UnwrappedLineParser::parseSwitch() { - assert(FormatTok->Tok.is(tok::kw_switch) && "'switch' expected"); + assert(FormatTok->is(tok::kw_switch) && "'switch' expected"); nextToken(); - if (FormatTok->Tok.is(tok::l_paren)) + if (FormatTok->is(tok::l_paren)) parseParens(); keepAncestorBraces(); - if (FormatTok->Tok.is(tok::l_brace)) { + if (FormatTok->is(tok::l_brace)) { CompoundStatementIndenter Indenter(this, Style, Line->Level); parseBlock(); addUnwrappedLine(); @@ -2707,6 +3032,57 @@ void UnwrappedLineParser::parseSwitch() { NestedTooDeep.pop_back(); } +// Operators that can follow a C variable. +static bool isCOperatorFollowingVar(tok::TokenKind kind) { + switch (kind) { + case tok::ampamp: + case tok::ampequal: + case tok::arrow: + case tok::caret: + case tok::caretequal: + case tok::comma: + case tok::ellipsis: + case tok::equal: + case tok::equalequal: + case tok::exclaim: + case tok::exclaimequal: + case tok::greater: + case tok::greaterequal: + case tok::greatergreater: + case tok::greatergreaterequal: + case tok::l_paren: + case tok::l_square: + case tok::less: + case tok::lessequal: + case tok::lessless: + case tok::lesslessequal: + case tok::minus: + case tok::minusequal: + case tok::minusminus: + case tok::percent: + case tok::percentequal: + case tok::period: + case tok::pipe: + case tok::pipeequal: + case tok::pipepipe: + case tok::plus: + case tok::plusequal: + case tok::plusplus: + case tok::question: + case tok::r_brace: + case tok::r_paren: + case tok::r_square: + case tok::semi: + case tok::slash: + case tok::slashequal: + case tok::star: + case tok::starequal: + return true; + default: + return false; + } +} + void UnwrappedLineParser::parseAccessSpecifier() { FormatToken *AccessSpecifierCandidate = FormatTok; nextToken(); @@ -2714,13 +3090,11 @@ void UnwrappedLineParser::parseAccessSpecifier() { if (FormatTok->isOneOf(Keywords.kw_slots, Keywords.kw_qslots)) nextToken(); // Otherwise, we don't know what it is, and we'd better keep the next token. - if (FormatTok->Tok.is(tok::colon)) { + if (FormatTok->is(tok::colon)) { nextToken(); addUnwrappedLine(); - } else if (!FormatTok->Tok.is(tok::coloncolon) && - !std::binary_search(COperatorsFollowingVar.begin(), - COperatorsFollowingVar.end(), - FormatTok->Tok.getKind())) { + } else if (!FormatTok->is(tok::coloncolon) && + !isCOperatorFollowingVar(FormatTok->Tok.getKind())) { // Not a variable name nor namespace name. addUnwrappedLine(); } else if (AccessSpecifierCandidate) { @@ -2729,122 +3103,367 @@ void UnwrappedLineParser::parseAccessSpecifier() { } } +/// \brief Parses a concept definition. +/// \pre The current token has to be the concept keyword. +/// +/// Returns if either the concept has been completely parsed, or if it detects +/// that the concept definition is incorrect. void UnwrappedLineParser::parseConcept() { - assert(FormatTok->Tok.is(tok::kw_concept) && "'concept' expected"); + assert(FormatTok->is(tok::kw_concept) && "'concept' expected"); nextToken(); - if (!FormatTok->Tok.is(tok::identifier)) + if (!FormatTok->is(tok::identifier)) return; nextToken(); - if (!FormatTok->Tok.is(tok::equal)) + if (!FormatTok->is(tok::equal)) return; nextToken(); - if (FormatTok->Tok.is(tok::kw_requires)) { + parseConstraintExpression(); + if (FormatTok->is(tok::semi)) nextToken(); - parseRequiresExpression(Line->Level); - } else { - parseConstraintExpression(Line->Level); - } + addUnwrappedLine(); } -void UnwrappedLineParser::parseRequiresExpression(unsigned int OriginalLevel) { - // requires (R range) - if (FormatTok->Tok.is(tok::l_paren)) { - parseParens(); - if (Style.IndentRequires && OriginalLevel != Line->Level) { - addUnwrappedLine(); - --Line->Level; - } +/// \brief Parses a requires, decides if it is a clause or an expression. +/// \pre The current token has to be the requires keyword. +/// \returns true if it parsed a clause. +bool clang::format::UnwrappedLineParser::parseRequires() { + assert(FormatTok->is(tok::kw_requires) && "'requires' expected"); + auto RequiresToken = FormatTok; + + // We try to guess if it is a requires clause, or a requires expression. For + // that we first consume the keyword and check the next token. + nextToken(); + + switch (FormatTok->Tok.getKind()) { + case tok::l_brace: + // This can only be an expression, never a clause. + parseRequiresExpression(RequiresToken); + return false; + case tok::l_paren: + // Clauses and expression can start with a paren, it's unclear what we have. + break; + default: + // All other tokens can only be a clause. + parseRequiresClause(RequiresToken); + return true; } - if (FormatTok->Tok.is(tok::l_brace)) { - if (Style.BraceWrapping.AfterFunction) - addUnwrappedLine(); - FormatTok->setType(TT_FunctionLBrace); - parseBlock(); - addUnwrappedLine(); - } else { - parseConstraintExpression(OriginalLevel); + // Looking forward we would have to decide if there are function declaration + // like arguments to the requires expression: + // requires (T t) { + // Or there is a constraint expression for the requires clause: + // requires (C<T> && ... + + // But first let's look behind. + auto *PreviousNonComment = RequiresToken->getPreviousNonComment(); + + if (!PreviousNonComment || + PreviousNonComment->is(TT_RequiresExpressionLBrace)) { + // If there is no token, or an expression left brace, we are a requires + // clause within a requires expression. + parseRequiresClause(RequiresToken); + return true; } -} -void UnwrappedLineParser::parseConstraintExpression( - unsigned int OriginalLevel) { - // requires Id<T> && Id<T> || Id<T> - while ( - FormatTok->isOneOf(tok::identifier, tok::kw_requires, tok::coloncolon)) { - nextToken(); - while (FormatTok->isOneOf(tok::identifier, tok::coloncolon, tok::less, - tok::greater, tok::comma, tok::ellipsis)) { - if (FormatTok->Tok.is(tok::less)) { - parseBracedList(/*ContinueOnSemicolons=*/false, /*IsEnum=*/false, - /*ClosingBraceKind=*/tok::greater); - continue; - } - nextToken(); - } - if (FormatTok->Tok.is(tok::kw_requires)) { - parseRequiresExpression(OriginalLevel); + switch (PreviousNonComment->Tok.getKind()) { + case tok::greater: + case tok::r_paren: + case tok::kw_noexcept: + case tok::kw_const: + // This is a requires clause. + parseRequiresClause(RequiresToken); + return true; + case tok::amp: + case tok::ampamp: { + // This can be either: + // if (... && requires (T t) ...) + // Or + // void member(...) && requires (C<T> ... + // We check the one token before that for a const: + // void member(...) const && requires (C<T> ... + auto PrevPrev = PreviousNonComment->getPreviousNonComment(); + if (PrevPrev && PrevPrev->is(tok::kw_const)) { + parseRequiresClause(RequiresToken); + return true; } - if (FormatTok->Tok.is(tok::less)) { - parseBracedList(/*ContinueOnSemicolons=*/false, /*IsEnum=*/false, - /*ClosingBraceKind=*/tok::greater); + break; + } + default: + if (PreviousNonComment->isTypeOrIdentifier()) { + // This is a requires clause. + parseRequiresClause(RequiresToken); + return true; } + // It's an expression. + parseRequiresExpression(RequiresToken); + return false; + } - if (FormatTok->Tok.is(tok::l_paren)) { - parseParens(); - } - if (FormatTok->Tok.is(tok::l_brace)) { - if (Style.BraceWrapping.AfterFunction) - addUnwrappedLine(); - FormatTok->setType(TT_FunctionLBrace); - parseBlock(); - } - if (FormatTok->Tok.is(tok::semi)) { - // Eat any trailing semi. - nextToken(); - addUnwrappedLine(); - } - if (FormatTok->Tok.is(tok::colon)) { - return; - } - if (!FormatTok->Tok.isOneOf(tok::ampamp, tok::pipepipe)) { - if (FormatTok->Previous && - !FormatTok->Previous->isOneOf(tok::identifier, tok::kw_requires, - tok::coloncolon)) { - addUnwrappedLine(); + // Now we look forward and try to check if the paren content is a parameter + // list. The parameters can be cv-qualified and contain references or + // pointers. + // So we want basically to check for TYPE NAME, but TYPE can contain all kinds + // of stuff: typename, const, *, &, &&, ::, identifiers. + + int NextTokenOffset = 1; + auto NextToken = Tokens->peekNextToken(NextTokenOffset); + auto PeekNext = [&NextTokenOffset, &NextToken, this] { + ++NextTokenOffset; + NextToken = Tokens->peekNextToken(NextTokenOffset); + }; + + bool FoundType = false; + bool LastWasColonColon = false; + int OpenAngles = 0; + + for (; NextTokenOffset < 50; PeekNext()) { + switch (NextToken->Tok.getKind()) { + case tok::kw_volatile: + case tok::kw_const: + case tok::comma: + parseRequiresExpression(RequiresToken); + return false; + case tok::r_paren: + case tok::pipepipe: + parseRequiresClause(RequiresToken); + return true; + case tok::eof: + // Break out of the loop. + NextTokenOffset = 50; + break; + case tok::coloncolon: + LastWasColonColon = true; + break; + case tok::identifier: + if (FoundType && !LastWasColonColon && OpenAngles == 0) { + parseRequiresExpression(RequiresToken); + return false; } - if (Style.IndentRequires && OriginalLevel != Line->Level) { - --Line->Level; + FoundType = true; + LastWasColonColon = false; + break; + case tok::less: + ++OpenAngles; + break; + case tok::greater: + --OpenAngles; + break; + default: + if (NextToken->isSimpleTypeSpecifier()) { + parseRequiresExpression(RequiresToken); + return false; } break; - } else { - FormatTok->setType(TT_ConstraintJunctions); } + } - nextToken(); + // This seems to be a complicated expression, just assume it's a clause. + parseRequiresClause(RequiresToken); + return true; +} + +/// \brief Parses a requires clause. +/// \param RequiresToken The requires keyword token, which starts this clause. +/// \pre We need to be on the next token after the requires keyword. +/// \sa parseRequiresExpression +/// +/// Returns if it either has finished parsing the clause, or it detects, that +/// the clause is incorrect. +void UnwrappedLineParser::parseRequiresClause(FormatToken *RequiresToken) { + assert(FormatTok->getPreviousNonComment() == RequiresToken); + assert(RequiresToken->is(tok::kw_requires) && "'requires' expected"); + + // If there is no previous token, we are within a requires expression, + // otherwise we will always have the template or function declaration in front + // of it. + bool InRequiresExpression = + !RequiresToken->Previous || + RequiresToken->Previous->is(TT_RequiresExpressionLBrace); + + RequiresToken->setFinalizedType(InRequiresExpression + ? TT_RequiresClauseInARequiresExpression + : TT_RequiresClause); + + parseConstraintExpression(); + + if (!InRequiresExpression) + FormatTok->Previous->ClosesRequiresClause = true; +} + +/// \brief Parses a requires expression. +/// \param RequiresToken The requires keyword token, which starts this clause. +/// \pre We need to be on the next token after the requires keyword. +/// \sa parseRequiresClause +/// +/// Returns if it either has finished parsing the expression, or it detects, +/// that the expression is incorrect. +void UnwrappedLineParser::parseRequiresExpression(FormatToken *RequiresToken) { + assert(FormatTok->getPreviousNonComment() == RequiresToken); + assert(RequiresToken->is(tok::kw_requires) && "'requires' expected"); + + RequiresToken->setFinalizedType(TT_RequiresExpression); + + if (FormatTok->is(tok::l_paren)) { + FormatTok->setFinalizedType(TT_RequiresExpressionLParen); + parseParens(); + } + + if (FormatTok->is(tok::l_brace)) { + FormatTok->setFinalizedType(TT_RequiresExpressionLBrace); + parseChildBlock(/*CanContainBracedList=*/false, + /*NextLBracesType=*/TT_CompoundRequirementLBrace); } } -void UnwrappedLineParser::parseRequires() { - assert(FormatTok->Tok.is(tok::kw_requires) && "'requires' expected"); +/// \brief Parses a constraint expression. +/// +/// This is either the definition of a concept, or the body of a requires +/// clause. It returns, when the parsing is complete, or the expression is +/// incorrect. +void UnwrappedLineParser::parseConstraintExpression() { + // The special handling for lambdas is needed since tryToParseLambda() eats a + // token and if a requires expression is the last part of a requires clause + // and followed by an attribute like [[nodiscard]] the ClosesRequiresClause is + // not set on the correct token. Thus we need to be aware if we even expect a + // lambda to be possible. + // template <typename T> requires requires { ... } [[nodiscard]] ...; + bool LambdaNextTimeAllowed = true; + do { + bool LambdaThisTimeAllowed = std::exchange(LambdaNextTimeAllowed, false); - unsigned OriginalLevel = Line->Level; - if (FormatTok->Previous && FormatTok->Previous->is(tok::greater)) { - addUnwrappedLine(); - if (Style.IndentRequires) { - ++Line->Level; + switch (FormatTok->Tok.getKind()) { + case tok::kw_requires: { + auto RequiresToken = FormatTok; + nextToken(); + parseRequiresExpression(RequiresToken); + break; } - } - nextToken(); - parseRequiresExpression(OriginalLevel); + case tok::l_paren: + parseParens(/*AmpAmpTokenType=*/TT_BinaryOperator); + break; + + case tok::l_square: + if (!LambdaThisTimeAllowed || !tryToParseLambda()) + return; + break; + + case tok::kw_const: + case tok::semi: + case tok::kw_class: + case tok::kw_struct: + case tok::kw_union: + return; + + case tok::l_brace: + // Potential function body. + return; + + case tok::ampamp: + case tok::pipepipe: + FormatTok->setFinalizedType(TT_BinaryOperator); + nextToken(); + LambdaNextTimeAllowed = true; + break; + + case tok::comma: + case tok::comment: + LambdaNextTimeAllowed = LambdaThisTimeAllowed; + nextToken(); + break; + + case tok::kw_sizeof: + case tok::greater: + case tok::greaterequal: + case tok::greatergreater: + case tok::less: + case tok::lessequal: + case tok::lessless: + case tok::equalequal: + case tok::exclaim: + case tok::exclaimequal: + case tok::plus: + case tok::minus: + case tok::star: + case tok::slash: + case tok::kw_decltype: + LambdaNextTimeAllowed = true; + // Just eat them. + nextToken(); + break; + + case tok::numeric_constant: + case tok::coloncolon: + case tok::kw_true: + case tok::kw_false: + // Just eat them. + nextToken(); + break; + + case tok::kw_static_cast: + case tok::kw_const_cast: + case tok::kw_reinterpret_cast: + case tok::kw_dynamic_cast: + nextToken(); + if (!FormatTok->is(tok::less)) + return; + + nextToken(); + parseBracedList(/*ContinueOnSemicolons=*/false, /*IsEnum=*/false, + /*ClosingBraceKind=*/tok::greater); + break; + + case tok::kw_bool: + // bool is only allowed if it is directly followed by a paren for a cast: + // concept C = bool(...); + // and bool is the only type, all other types as cast must be inside a + // cast to bool an thus are handled by the other cases. + nextToken(); + if (FormatTok->isNot(tok::l_paren)) + return; + parseParens(); + break; + + default: + if (!FormatTok->Tok.getIdentifierInfo()) { + // Identifiers are part of the default case, we check for more then + // tok::identifier to handle builtin type traits. + return; + } + + // We need to differentiate identifiers for a template deduction guide, + // variables, or function return types (the constraint expression has + // ended before that), and basically all other cases. But it's easier to + // check the other way around. + assert(FormatTok->Previous); + switch (FormatTok->Previous->Tok.getKind()) { + case tok::coloncolon: // Nested identifier. + case tok::ampamp: // Start of a function or variable for the + case tok::pipepipe: // constraint expression. + case tok::kw_requires: // Initial identifier of a requires clause. + case tok::equal: // Initial identifier of a concept declaration. + break; + default: + return; + } + + // Read identifier with optional template declaration. + nextToken(); + if (FormatTok->is(tok::less)) { + nextToken(); + parseBracedList(/*ContinueOnSemicolons=*/false, /*IsEnum=*/false, + /*ClosingBraceKind=*/tok::greater); + } + break; + } + } while (!eof()); } bool UnwrappedLineParser::parseEnum() { const FormatToken &InitialToken = *FormatTok; // Won't be 'enum' for NS_ENUMs. - if (FormatTok->Tok.is(tok::kw_enum)) + if (FormatTok->is(tok::kw_enum)) nextToken(); // In TypeScript, "enum" can also be used as property name, e.g. in interface @@ -2858,16 +3477,23 @@ bool UnwrappedLineParser::parseEnum() { return false; // Eat up enum class ... - if (FormatTok->Tok.is(tok::kw_class) || FormatTok->Tok.is(tok::kw_struct)) + if (FormatTok->isOneOf(tok::kw_class, tok::kw_struct)) nextToken(); while (FormatTok->Tok.getIdentifierInfo() || FormatTok->isOneOf(tok::colon, tok::coloncolon, tok::less, - tok::greater, tok::comma, tok::question)) { + tok::greater, tok::comma, tok::question, + tok::l_square, tok::r_square)) { nextToken(); // We can have macros or attributes in between 'enum' and the enum name. if (FormatTok->is(tok::l_paren)) parseParens(); + if (FormatTok->is(TT_AttributeSquare)) { + parseSquare(); + // Consume the closing TT_AttributeSquare. + if (FormatTok->Next && FormatTok->is(TT_AttributeSquare)) + nextToken(); + } if (FormatTok->is(tok::identifier)) { nextToken(); // If there are two identifiers in a row, this is likely an elaborate @@ -2880,7 +3506,7 @@ bool UnwrappedLineParser::parseEnum() { // Just a declaration or something is wrong. if (FormatTok->isNot(tok::l_brace)) return true; - FormatTok->setType(TT_RecordLBrace); + FormatTok->setFinalizedType(TT_EnumLBrace); FormatTok->setBlockKind(BK_Block); if (Style.Language == FormatStyle::LK_Java) { @@ -2894,8 +3520,9 @@ bool UnwrappedLineParser::parseEnum() { } if (!Style.AllowShortEnumsOnASingleLine && - ShouldBreakBeforeBrace(Style, InitialToken)) + ShouldBreakBeforeBrace(Style, InitialToken)) { addUnwrappedLine(); + } // Parse enum body. nextToken(); if (!Style.AllowShortEnumsOnASingleLine) { @@ -2956,31 +3583,30 @@ bool UnwrappedLineParser::tryToParseSimpleAttribute() { ScopedTokenPosition AutoPosition(Tokens); FormatToken *Tok = Tokens->getNextToken(); // We already read the first [ check for the second. - if (!Tok->is(tok::l_square)) { + if (!Tok->is(tok::l_square)) return false; - } // Double check that the attribute is just something // fairly simple. while (Tok->isNot(tok::eof)) { - if (Tok->is(tok::r_square)) { + if (Tok->is(tok::r_square)) break; - } Tok = Tokens->getNextToken(); } if (Tok->is(tok::eof)) return false; Tok = Tokens->getNextToken(); - if (!Tok->is(tok::r_square)) { + if (!Tok->is(tok::r_square)) return false; - } Tok = Tokens->getNextToken(); - if (Tok->is(tok::semi)) { + if (Tok->is(tok::semi)) return false; - } return true; } 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. @@ -3014,7 +3640,7 @@ void UnwrappedLineParser::parseJavaEnumBody() { ++Line->Level; // Parse the enum constants. - while (FormatTok) { + while (FormatTok->isNot(tok::eof)) { if (FormatTok->is(tok::l_brace)) { // Parse the constant's class body. parseBlock(/*MustBeDeclaration=*/true, /*AddLevels=*/1u, @@ -3037,7 +3663,7 @@ void UnwrappedLineParser::parseJavaEnumBody() { } // Parse the class body after the enum's ";" if any. - parseLevel(/*HasOpeningBrace=*/true); + parseLevel(OpeningBrace); nextToken(); --Line->Level; addUnwrappedLine(); @@ -3072,7 +3698,7 @@ void UnwrappedLineParser::parseRecord(bool ParseAsExpr) { nextToken(); // We can have macros or attributes in between 'class' and the class name. if (!IsNonMacroIdentifier) { - if (FormatTok->Tok.is(tok::l_paren)) { + if (FormatTok->is(tok::l_paren)) { parseParens(); } else if (FormatTok->is(TT_AttributeSquare)) { parseSquare(); @@ -3094,7 +3720,7 @@ void UnwrappedLineParser::parseRecord(bool ParseAsExpr) { // (this would still leave us with an ambiguity between template function // and class declarations). if (FormatTok->isOneOf(tok::colon, tok::less)) { - while (!eof()) { + do { if (FormatTok->is(tok::l_brace)) { calculateBraceTypes(/*ExpectClassBody=*/true); if (!tryToParseBracedList()) @@ -3102,14 +3728,18 @@ void UnwrappedLineParser::parseRecord(bool ParseAsExpr) { } if (FormatTok->is(tok::l_square)) { FormatToken *Previous = FormatTok->Previous; - if (!Previous || Previous->isNot(tok::r_paren)) { + if (!Previous || + !(Previous->is(tok::r_paren) || Previous->isTypeOrIdentifier())) { // Don't try parsing a lambda if we had a closing parenthesis before, // it was probably a pointer to an array: int (*)[]. if (!tryToParseLambda()) break; + } else { + parseSquare(); + continue; } } - if (FormatTok->Tok.is(tok::semi)) + if (FormatTok->is(tok::semi)) return; if (Style.isCSharp() && FormatTok->is(Keywords.kw_where)) { addUnwrappedLine(); @@ -3118,10 +3748,24 @@ void UnwrappedLineParser::parseRecord(bool ParseAsExpr) { break; } nextToken(); - } + } while (!eof()); } - if (FormatTok->Tok.is(tok::l_brace)) { - FormatTok->setType(TT_RecordLBrace); + + auto GetBraceType = [](const FormatToken &RecordTok) { + switch (RecordTok.Tok.getKind()) { + case tok::kw_class: + return TT_ClassLBrace; + case tok::kw_struct: + return TT_StructLBrace; + case tok::kw_union: + return TT_UnionLBrace; + default: + // Useful for e.g. interface. + return TT_RecordLBrace; + } + }; + if (FormatTok->is(tok::l_brace)) { + FormatTok->setFinalizedType(GetBraceType(InitialToken)); if (ParseAsExpr) { parseChildBlock(); } else { @@ -3138,14 +3782,14 @@ void UnwrappedLineParser::parseRecord(bool ParseAsExpr) { } void UnwrappedLineParser::parseObjCMethod() { - assert(FormatTok->Tok.isOneOf(tok::l_paren, tok::identifier) && + assert(FormatTok->isOneOf(tok::l_paren, tok::identifier) && "'(' or identifier expected."); do { - if (FormatTok->Tok.is(tok::semi)) { + if (FormatTok->is(tok::semi)) { nextToken(); addUnwrappedLine(); return; - } else if (FormatTok->Tok.is(tok::l_brace)) { + } else if (FormatTok->is(tok::l_brace)) { if (Style.BraceWrapping.AfterFunction) addUnwrappedLine(); parseBlock(); @@ -3158,20 +3802,21 @@ void UnwrappedLineParser::parseObjCMethod() { } void UnwrappedLineParser::parseObjCProtocolList() { - assert(FormatTok->Tok.is(tok::less) && "'<' expected."); + assert(FormatTok->is(tok::less) && "'<' expected."); do { nextToken(); // Early exit in case someone forgot a close angle. if (FormatTok->isOneOf(tok::semi, tok::l_brace) || - FormatTok->Tok.isObjCAtKeyword(tok::objc_end)) + FormatTok->isObjCAtKeyword(tok::objc_end)) { return; - } while (!eof() && FormatTok->Tok.isNot(tok::greater)); + } + } while (!eof() && FormatTok->isNot(tok::greater)); nextToken(); // Skip '>'. } void UnwrappedLineParser::parseObjCUntilAtEnd() { do { - if (FormatTok->Tok.isObjCAtKeyword(tok::objc_end)) { + if (FormatTok->isObjCAtKeyword(tok::objc_end)) { nextToken(); addUnwrappedLine(); break; @@ -3201,24 +3846,23 @@ void UnwrappedLineParser::parseObjCInterfaceOrImplementation() { // @interface can be followed by a lightweight generic // specialization list, then either a base class or a category. - if (FormatTok->Tok.is(tok::less)) { + if (FormatTok->is(tok::less)) parseObjCLightweightGenerics(); - } - if (FormatTok->Tok.is(tok::colon)) { + if (FormatTok->is(tok::colon)) { nextToken(); nextToken(); // base class name // The base class can also have lightweight generics applied to it. - if (FormatTok->Tok.is(tok::less)) { + if (FormatTok->is(tok::less)) parseObjCLightweightGenerics(); - } - } else if (FormatTok->Tok.is(tok::l_paren)) + } else if (FormatTok->is(tok::l_paren)) { // Skip category, if present. parseParens(); + } - if (FormatTok->Tok.is(tok::less)) + if (FormatTok->is(tok::less)) parseObjCProtocolList(); - if (FormatTok->Tok.is(tok::l_brace)) { + if (FormatTok->is(tok::l_brace)) { if (Style.BraceWrapping.AfterObjCDeclaration) addUnwrappedLine(); parseBlock(/*MustBeDeclaration=*/true); @@ -3232,7 +3876,7 @@ void UnwrappedLineParser::parseObjCInterfaceOrImplementation() { } void UnwrappedLineParser::parseObjCLightweightGenerics() { - assert(FormatTok->Tok.is(tok::less)); + assert(FormatTok->is(tok::less)); // Unlike protocol lists, generic parameterizations support // nested angles: // @@ -3245,11 +3889,12 @@ void UnwrappedLineParser::parseObjCLightweightGenerics() { nextToken(); // Early exit in case someone forgot a close angle. if (FormatTok->isOneOf(tok::semi, tok::l_brace) || - FormatTok->Tok.isObjCAtKeyword(tok::objc_end)) + FormatTok->isObjCAtKeyword(tok::objc_end)) { break; - if (FormatTok->Tok.is(tok::less)) + } + if (FormatTok->is(tok::less)) { ++NumOpenAngles; - else if (FormatTok->Tok.is(tok::greater)) { + } else if (FormatTok->is(tok::greater)) { assert(NumOpenAngles > 0 && "'>' makes NumOpenAngles negative"); --NumOpenAngles; } @@ -3263,9 +3908,10 @@ bool UnwrappedLineParser::parseObjCProtocol() { assert(FormatTok->Tok.getObjCKeywordID() == tok::objc_protocol); nextToken(); - if (FormatTok->is(tok::l_paren)) + if (FormatTok->is(tok::l_paren)) { // The expression form of @protocol, e.g. "Protocol* p = @protocol(foo);". return false; + } // The definition/declaration form, // @protocol Foo @@ -3274,11 +3920,11 @@ bool UnwrappedLineParser::parseObjCProtocol() { nextToken(); // protocol name - if (FormatTok->Tok.is(tok::less)) + if (FormatTok->is(tok::less)) parseObjCProtocolList(); // Check for protocol declaration. - if (FormatTok->Tok.is(tok::semi)) { + if (FormatTok->is(tok::semi)) { nextToken(); addUnwrappedLine(); return true; @@ -3313,8 +3959,9 @@ void UnwrappedLineParser::parseJavaScriptEs6ImportExport() { // parsing the structural element, i.e. the declaration or expression for // `export default`. if (!IsImport && !FormatTok->isOneOf(tok::l_brace, tok::star) && - !FormatTok->isStringLiteral()) + !FormatTok->isStringLiteral()) { return; + } while (!eof()) { if (FormatTok->is(tok::semi)) @@ -3393,7 +4040,7 @@ void UnwrappedLineParser::addUnwrappedLine(LineLevel AdjustLevel) { FormatTok->Previous = nullptr; } -bool UnwrappedLineParser::eof() const { return FormatTok->Tok.is(tok::eof); } +bool UnwrappedLineParser::eof() const { return FormatTok->is(tok::eof); } bool UnwrappedLineParser::isOnNewLine(const FormatToken &FormatTok) { return (Line->InPPDirective || FormatTok.HasUnescapedNewline) && @@ -3411,8 +4058,9 @@ continuesLineCommentSection(const FormatToken &FormatTok, StringRef IndentContent = FormatTok.TokenText; if (FormatTok.TokenText.startswith("//") || - FormatTok.TokenText.startswith("/*")) + FormatTok.TokenText.startswith("/*")) { IndentContent = FormatTok.TokenText.substr(2); + } if (CommentPragmasRegex.match(IndentContent)) return false; @@ -3496,13 +4144,11 @@ continuesLineCommentSection(const FormatToken &FormatTok, PreviousToken = Node.Tok; // Grab the last newline preceding a token in this unwrapped line. - if (Node.Tok->NewlinesBefore > 0) { + if (Node.Tok->NewlinesBefore > 0) MinColumnToken = Node.Tok; - } } - if (PreviousToken && PreviousToken->is(tok::l_brace)) { + if (PreviousToken && PreviousToken->is(tok::l_brace)) MinColumnToken = PreviousToken; - } return continuesLineComment(FormatTok, /*Previous=*/Line.Tokens.back().Tok, MinColumnToken); @@ -3541,6 +4187,16 @@ void UnwrappedLineParser::nextToken(int LevelDifference) { else readTokenWithJavaScriptASI(); FormatTok->Previous = Previous; + if (Style.isVerilog()) { + // Blocks in Verilog can have `begin` and `end` instead of braces. For + // keywords like `begin`, we can't treat them the same as left braces + // because some contexts require one of them. For example structs use + // braces and if blocks use keywords, and a left brace can occur in an if + // statement, but it is not a block. For keywords like `end`, we simply + // treat them the same as right braces. + if (Keywords.isVerilogEnd(*FormatTok)) + FormatTok->Tok.setKind(tok::r_brace); + } } void UnwrappedLineParser::distributeComments( @@ -3590,35 +4246,55 @@ void UnwrappedLineParser::distributeComments( (isOnNewLine(*FormatTok) || FormatTok->IsFirst)) { ShouldPushCommentsInCurrentLine = false; } - if (ShouldPushCommentsInCurrentLine) { + if (ShouldPushCommentsInCurrentLine) pushToken(FormatTok); - } else { + else CommentsBeforeNextToken.push_back(FormatTok); - } } } void UnwrappedLineParser::readToken(int LevelDifference) { SmallVector<FormatToken *, 1> Comments; + bool PreviousWasComment = false; + bool FirstNonCommentOnLine = false; do { FormatTok = Tokens->getNextToken(); assert(FormatTok); while (FormatTok->getType() == TT_ConflictStart || FormatTok->getType() == TT_ConflictEnd || FormatTok->getType() == TT_ConflictAlternative) { - if (FormatTok->getType() == TT_ConflictStart) { + if (FormatTok->getType() == TT_ConflictStart) conditionalCompilationStart(/*Unreachable=*/false); - } else if (FormatTok->getType() == TT_ConflictAlternative) { + else if (FormatTok->getType() == TT_ConflictAlternative) conditionalCompilationAlternative(); - } else if (FormatTok->getType() == TT_ConflictEnd) { + else if (FormatTok->getType() == TT_ConflictEnd) conditionalCompilationEnd(); - } FormatTok = Tokens->getNextToken(); FormatTok->MustBreakBefore = true; } - while (!Line->InPPDirective && FormatTok->Tok.is(tok::hash) && - (FormatTok->HasUnescapedNewline || FormatTok->IsFirst)) { + auto IsFirstNonCommentOnLine = [](bool FirstNonCommentOnLine, + const FormatToken &Tok, + bool PreviousWasComment) { + auto IsFirstOnLine = [](const FormatToken &Tok) { + return Tok.HasUnescapedNewline || Tok.IsFirst; + }; + + // Consider preprocessor directives preceded by block comments as first + // on line. + if (PreviousWasComment) + return FirstNonCommentOnLine || IsFirstOnLine(Tok); + return IsFirstOnLine(Tok); + }; + + FirstNonCommentOnLine = IsFirstNonCommentOnLine( + FirstNonCommentOnLine, *FormatTok, PreviousWasComment); + PreviousWasComment = FormatTok->is(tok::comment); + + while (!Line->InPPDirective && FormatTok->is(tok::hash) && + (!Style.isVerilog() || + Keywords.isVerilogPPDirective(*Tokens->peekNextToken())) && + FirstNonCommentOnLine) { distributeComments(Comments, FormatTok); Comments.clear(); // If there is an unfinished unwrapped line, we flush the preprocessor @@ -3633,10 +4309,14 @@ void UnwrappedLineParser::readToken(int LevelDifference) { // before the preprocessor directive, at the same level as the // preprocessor directive, as we consider them to apply to the directive. if (Style.IndentPPDirectives == FormatStyle::PPDIS_BeforeHash && - PPBranchLevel > 0) + PPBranchLevel > 0) { Line->Level += PPBranchLevel; + } flushComments(isOnNewLine(*FormatTok)); parsePPDirective(); + PreviousWasComment = FormatTok->is(tok::comment); + FirstNonCommentOnLine = IsFirstNonCommentOnLine( + FirstNonCommentOnLine, *FormatTok, PreviousWasComment); } if (!PPStack.empty() && (PPStack.back().Kind == PP_Unreachable) && @@ -3644,7 +4324,7 @@ void UnwrappedLineParser::readToken(int LevelDifference) { continue; } - if (!FormatTok->Tok.is(tok::comment)) { + if (!FormatTok->is(tok::comment)) { distributeComments(Comments, FormatTok); Comments.clear(); return; |
