aboutsummaryrefslogtreecommitdiff
path: root/clang/lib/Format/UnwrappedLineParser.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib/Format/UnwrappedLineParser.cpp')
-rw-r--r--clang/lib/Format/UnwrappedLineParser.cpp1546
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;