1f7935115SDaniel Jasper //===--- UnwrappedLineParser.cpp - Format C++ code ------------------------===//
2f7935115SDaniel Jasper //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6f7935115SDaniel Jasper //
7f7935115SDaniel Jasper //===----------------------------------------------------------------------===//
8f7935115SDaniel Jasper ///
9f7935115SDaniel Jasper /// \file
109fc8faf9SAdrian Prantl /// This file contains the implementation of the UnwrappedLineParser,
11f7935115SDaniel Jasper /// which turns a stream of tokens into UnwrappedLines.
12f7935115SDaniel Jasper ///
13f7935115SDaniel Jasper //===----------------------------------------------------------------------===//
14f7935115SDaniel Jasper
154b41745eSChandler Carruth #include "UnwrappedLineParser.h"
1644ad58b9SJonathan Coe #include "FormatToken.h"
17b6d8c84fSowenca #include "TokenAnnotator.h"
184de0680fSManuel Klimek #include "clang/Basic/TokenKinds.h"
1933335df8SBenjamin Kramer #include "llvm/ADT/STLExtras.h"
20ab3dc000SManuel Klimek #include "llvm/Support/Debug.h"
2153f5e893SBenjamin Kramer #include "llvm/Support/raw_ostream.h"
22ab3dc000SManuel Klimek
237e0f25b2SMartin Probst #include <algorithm>
24be9a7fddSBjörn Schäpers #include <utility>
257e0f25b2SMartin Probst
2610346667SChandler Carruth #define DEBUG_TYPE "format-parser"
2710346667SChandler Carruth
28f7935115SDaniel Jasper namespace clang {
29f7935115SDaniel Jasper namespace format {
30f7935115SDaniel Jasper
3115dfe7acSManuel Klimek class FormatTokenSource {
3215dfe7acSManuel Klimek public:
~FormatTokenSource()33637d1e66SAngel Garcia Gomez virtual ~FormatTokenSource() {}
341b5a43acSManuel Klimek
351b5a43acSManuel Klimek // Returns the next token in the token stream.
3615dfe7acSManuel Klimek virtual FormatToken *getNextToken() = 0;
3715dfe7acSManuel Klimek
38d97025adSowenca // Returns the token preceding the token returned by the last call to
391b5a43acSManuel Klimek // getNextToken() in the token stream, or nullptr if no such token exists.
401b5a43acSManuel Klimek virtual FormatToken *getPreviousToken() = 0;
411b5a43acSManuel Klimek
421b5a43acSManuel Klimek // Returns the token that would be returned by the next call to
431b5a43acSManuel Klimek // getNextToken().
441b5a43acSManuel Klimek virtual FormatToken *peekNextToken() = 0;
451b5a43acSManuel Klimek
46bcd1e461SBjörn Schäpers // Returns the token that would be returned after the next N calls to
47bcd1e461SBjörn Schäpers // getNextToken(). N needs to be greater than zero, and small enough that
48bcd1e461SBjörn Schäpers // there are still tokens. Check for tok::eof with N-1 before calling it with
49bcd1e461SBjörn Schäpers // N.
50bcd1e461SBjörn Schäpers virtual FormatToken *peekNextToken(int N) = 0;
51bcd1e461SBjörn Schäpers
521b5a43acSManuel Klimek // Returns whether we are at the end of the file.
531b5a43acSManuel Klimek // This can be different from whether getNextToken() returned an eof token
541b5a43acSManuel Klimek // when the FormatTokenSource is a view on a part of the token stream.
551b5a43acSManuel Klimek virtual bool isEOF() = 0;
561b5a43acSManuel Klimek
571b5a43acSManuel Klimek // Gets the current position in the token stream, to be used by setPosition().
5815dfe7acSManuel Klimek virtual unsigned getPosition() = 0;
591b5a43acSManuel Klimek
601b5a43acSManuel Klimek // Resets the token stream to the state it was in when getPosition() returned
611b5a43acSManuel Klimek // Position, and return the token at that position in the stream.
6215dfe7acSManuel Klimek virtual FormatToken *setPosition(unsigned Position) = 0;
6315dfe7acSManuel Klimek };
6415dfe7acSManuel Klimek
6569665e11SCraig Topper namespace {
6669665e11SCraig Topper
670a3a3c99SManuel Klimek class ScopedDeclarationState {
680a3a3c99SManuel Klimek public:
ScopedDeclarationState(UnwrappedLine & Line,llvm::BitVector & Stack,bool MustBeDeclaration)69622354a5SJan Svoboda ScopedDeclarationState(UnwrappedLine &Line, llvm::BitVector &Stack,
700a3a3c99SManuel Klimek bool MustBeDeclaration)
710a3a3c99SManuel Klimek : Line(Line), Stack(Stack) {
720a3a3c99SManuel Klimek Line.MustBeDeclaration = MustBeDeclaration;
7339080573SManuel Klimek Stack.push_back(MustBeDeclaration);
740a3a3c99SManuel Klimek }
~ScopedDeclarationState()750a3a3c99SManuel Klimek ~ScopedDeclarationState() {
760a3a3c99SManuel Klimek Stack.pop_back();
77c1237a8bSManuel Klimek if (!Stack.empty())
7839080573SManuel Klimek Line.MustBeDeclaration = Stack.back();
79c1237a8bSManuel Klimek else
80c1237a8bSManuel Klimek Line.MustBeDeclaration = true;
810a3a3c99SManuel Klimek }
82393564fdSDaniel Jasper
830a3a3c99SManuel Klimek private:
840a3a3c99SManuel Klimek UnwrappedLine &Line;
85622354a5SJan Svoboda llvm::BitVector &Stack;
860a3a3c99SManuel Klimek };
870a3a3c99SManuel Klimek
isLineComment(const FormatToken & FormatTok)88a1c30937SKrasimir Georgiev static bool isLineComment(const FormatToken &FormatTok) {
89410ed245SKrasimir Georgiev return FormatTok.is(tok::comment) && !FormatTok.TokenText.startswith("/*");
90a1c30937SKrasimir Georgiev }
91a1c30937SKrasimir Georgiev
92ea222a79SKrasimir Georgiev // Checks if \p FormatTok is a line comment that continues the line comment
93ea222a79SKrasimir Georgiev // \p Previous. The original column of \p MinColumnToken is used to determine
94ea222a79SKrasimir Georgiev // whether \p FormatTok is indented enough to the right to continue \p Previous.
continuesLineComment(const FormatToken & FormatTok,const FormatToken * Previous,const FormatToken * MinColumnToken)95ea222a79SKrasimir Georgiev static bool continuesLineComment(const FormatToken &FormatTok,
96ea222a79SKrasimir Georgiev const FormatToken *Previous,
97ea222a79SKrasimir Georgiev const FormatToken *MinColumnToken) {
98ea222a79SKrasimir Georgiev if (!Previous || !MinColumnToken)
99ea222a79SKrasimir Georgiev return false;
100ea222a79SKrasimir Georgiev unsigned MinContinueColumn =
101ea222a79SKrasimir Georgiev MinColumnToken->OriginalColumn + (isLineComment(*MinColumnToken) ? 0 : 1);
102ea222a79SKrasimir Georgiev return isLineComment(FormatTok) && FormatTok.NewlinesBefore == 1 &&
103ea222a79SKrasimir Georgiev isLineComment(*Previous) &&
104ea222a79SKrasimir Georgiev FormatTok.OriginalColumn >= MinContinueColumn;
105ea222a79SKrasimir Georgiev }
106ea222a79SKrasimir Georgiev
1071abf789cSManuel Klimek class ScopedMacroState : public FormatTokenSource {
1081abf789cSManuel Klimek public:
ScopedMacroState(UnwrappedLine & Line,FormatTokenSource * & TokenSource,FormatToken * & ResetToken)1091abf789cSManuel Klimek ScopedMacroState(UnwrappedLine &Line, FormatTokenSource *&TokenSource,
11020e0af6bSManuel Klimek FormatToken *&ResetToken)
1111abf789cSManuel Klimek : Line(Line), TokenSource(TokenSource), ResetToken(ResetToken),
1121a18c404SManuel Klimek PreviousLineLevel(Line.Level), PreviousTokenSource(TokenSource),
113a1c30937SKrasimir Georgiev Token(nullptr), PreviousToken(nullptr) {
1145de22721SDavid L. Jones FakeEOF.Tok.startToken();
1155de22721SDavid L. Jones FakeEOF.Tok.setKind(tok::eof);
1161abf789cSManuel Klimek TokenSource = this;
117ef2cfb11SManuel Klimek Line.Level = 0;
1181abf789cSManuel Klimek Line.InPPDirective = true;
1191abf789cSManuel Klimek }
1201abf789cSManuel Klimek
~ScopedMacroState()12134eb2072SAlexander Kornienko ~ScopedMacroState() override {
1221abf789cSManuel Klimek TokenSource = PreviousTokenSource;
1231abf789cSManuel Klimek ResetToken = Token;
1241abf789cSManuel Klimek Line.InPPDirective = false;
125ef2cfb11SManuel Klimek Line.Level = PreviousLineLevel;
1261abf789cSManuel Klimek }
1271abf789cSManuel Klimek
getNextToken()128fb6b25b5SCraig Topper FormatToken *getNextToken() override {
1297872571fSManuel Klimek // The \c UnwrappedLineParser guards against this by never calling
1307872571fSManuel Klimek // \c getNextToken() after it has encountered the first eof token.
1317872571fSManuel Klimek assert(!eof());
132a1c30937SKrasimir Georgiev PreviousToken = Token;
1331abf789cSManuel Klimek Token = PreviousTokenSource->getNextToken();
1341abf789cSManuel Klimek if (eof())
1355de22721SDavid L. Jones return &FakeEOF;
1361abf789cSManuel Klimek return Token;
1371abf789cSManuel Klimek }
1381abf789cSManuel Klimek
getPreviousToken()1391b5a43acSManuel Klimek FormatToken *getPreviousToken() override {
1401b5a43acSManuel Klimek return PreviousTokenSource->getPreviousToken();
1411b5a43acSManuel Klimek }
1421b5a43acSManuel Klimek
peekNextToken()1431b5a43acSManuel Klimek FormatToken *peekNextToken() override {
1441b5a43acSManuel Klimek if (eof())
1451b5a43acSManuel Klimek return &FakeEOF;
1461b5a43acSManuel Klimek return PreviousTokenSource->peekNextToken();
1471b5a43acSManuel Klimek }
1481b5a43acSManuel Klimek
peekNextToken(int N)149bcd1e461SBjörn Schäpers FormatToken *peekNextToken(int N) override {
150bcd1e461SBjörn Schäpers assert(N > 0);
151bcd1e461SBjörn Schäpers if (eof())
152bcd1e461SBjörn Schäpers return &FakeEOF;
153bcd1e461SBjörn Schäpers return PreviousTokenSource->peekNextToken(N);
154bcd1e461SBjörn Schäpers }
155bcd1e461SBjörn Schäpers
isEOF()1561b5a43acSManuel Klimek bool isEOF() override { return PreviousTokenSource->isEOF(); }
1571b5a43acSManuel Klimek
getPosition()158fb6b25b5SCraig Topper unsigned getPosition() override { return PreviousTokenSource->getPosition(); }
159ab41991cSManuel Klimek
setPosition(unsigned Position)160fb6b25b5SCraig Topper FormatToken *setPosition(unsigned Position) override {
161a1c30937SKrasimir Georgiev PreviousToken = nullptr;
162ab41991cSManuel Klimek Token = PreviousTokenSource->setPosition(Position);
163ab41991cSManuel Klimek return Token;
164ab41991cSManuel Klimek }
165ab41991cSManuel Klimek
1661abf789cSManuel Klimek private:
eof()167a1c30937SKrasimir Georgiev bool eof() {
168a1c30937SKrasimir Georgiev return Token && Token->HasUnescapedNewline &&
169ea222a79SKrasimir Georgiev !continuesLineComment(*Token, PreviousToken,
170ea222a79SKrasimir Georgiev /*MinColumnToken=*/PreviousToken);
171a1c30937SKrasimir Georgiev }
1721abf789cSManuel Klimek
1735de22721SDavid L. Jones FormatToken FakeEOF;
1741abf789cSManuel Klimek UnwrappedLine &Line;
1751abf789cSManuel Klimek FormatTokenSource *&TokenSource;
17615dfe7acSManuel Klimek FormatToken *&ResetToken;
177ef2cfb11SManuel Klimek unsigned PreviousLineLevel;
1781abf789cSManuel Klimek FormatTokenSource *PreviousTokenSource;
1791abf789cSManuel Klimek
18015dfe7acSManuel Klimek FormatToken *Token;
181a1c30937SKrasimir Georgiev FormatToken *PreviousToken;
1821abf789cSManuel Klimek };
1831abf789cSManuel Klimek
18469665e11SCraig Topper } // end anonymous namespace
18569665e11SCraig Topper
1868e07a1b6SManuel Klimek class ScopedLineState {
1878e07a1b6SManuel Klimek public:
ScopedLineState(UnwrappedLineParser & Parser,bool SwitchToPreprocessorLines=false)188d3b92fa6SManuel Klimek ScopedLineState(UnwrappedLineParser &Parser,
189d3b92fa6SManuel Klimek bool SwitchToPreprocessorLines = false)
190efb6eb26SDavid Blaikie : Parser(Parser), OriginalLines(Parser.CurrentLines) {
191d3b92fa6SManuel Klimek if (SwitchToPreprocessorLines)
192d3b92fa6SManuel Klimek Parser.CurrentLines = &Parser.PreprocessorDirectives;
1939fe0e8daSDaniel Jasper else if (!Parser.Line->Tokens.empty())
1949fe0e8daSDaniel Jasper Parser.CurrentLines = &Parser.Line->Tokens.back().Children;
195efb6eb26SDavid Blaikie PreBlockLine = std::move(Parser.Line);
1962b3d49b6SJonas Devlieghere Parser.Line = std::make_unique<UnwrappedLine>();
197daffc0ddSDaniel Jasper Parser.Line->Level = PreBlockLine->Level;
198daffc0ddSDaniel Jasper Parser.Line->InPPDirective = PreBlockLine->InPPDirective;
1998e07a1b6SManuel Klimek }
2008e07a1b6SManuel Klimek
~ScopedLineState()2018e07a1b6SManuel Klimek ~ScopedLineState() {
202d079995dSMarek Kurdej if (!Parser.Line->Tokens.empty())
2038e07a1b6SManuel Klimek Parser.addUnwrappedLine();
204daffc0ddSDaniel Jasper assert(Parser.Line->Tokens.empty());
205efb6eb26SDavid Blaikie Parser.Line = std::move(PreBlockLine);
2069fe0e8daSDaniel Jasper if (Parser.CurrentLines == &Parser.PreprocessorDirectives)
2078e07a1b6SManuel Klimek Parser.MustBreakBeforeNextToken = true;
2089fe0e8daSDaniel Jasper Parser.CurrentLines = OriginalLines;
2098e07a1b6SManuel Klimek }
2108e07a1b6SManuel Klimek
2118e07a1b6SManuel Klimek private:
2128e07a1b6SManuel Klimek UnwrappedLineParser &Parser;
2138e07a1b6SManuel Klimek
214efb6eb26SDavid Blaikie std::unique_ptr<UnwrappedLine> PreBlockLine;
2159fe0e8daSDaniel Jasper SmallVectorImpl<UnwrappedLine> *OriginalLines;
2168e07a1b6SManuel Klimek };
2178e07a1b6SManuel Klimek
2183a33f029SAlexander Kornienko class CompoundStatementIndenter {
2193a33f029SAlexander Kornienko public:
CompoundStatementIndenter(UnwrappedLineParser * Parser,const FormatStyle & Style,unsigned & LineLevel)2203a33f029SAlexander Kornienko CompoundStatementIndenter(UnwrappedLineParser *Parser,
2213a33f029SAlexander Kornienko const FormatStyle &Style, unsigned &LineLevel)
222806d5741SOwen Pan : CompoundStatementIndenter(Parser, LineLevel,
223806d5741SOwen Pan Style.BraceWrapping.AfterControlStatement,
224ff9f4b54SNico Weber Style.BraceWrapping.IndentBraces) {}
CompoundStatementIndenter(UnwrappedLineParser * Parser,unsigned & LineLevel,bool WrapBrace,bool IndentBrace)225806d5741SOwen Pan CompoundStatementIndenter(UnwrappedLineParser *Parser, unsigned &LineLevel,
226806d5741SOwen Pan bool WrapBrace, bool IndentBrace)
2273a33f029SAlexander Kornienko : LineLevel(LineLevel), OldLineLevel(LineLevel) {
228806d5741SOwen Pan if (WrapBrace)
2293a33f029SAlexander Kornienko Parser->addUnwrappedLine();
230806d5741SOwen Pan if (IndentBrace)
2313a33f029SAlexander Kornienko ++LineLevel;
2323a33f029SAlexander Kornienko }
~CompoundStatementIndenter()233b05a81deSDaniel Jasper ~CompoundStatementIndenter() { LineLevel = OldLineLevel; }
2343a33f029SAlexander Kornienko
2353a33f029SAlexander Kornienko private:
2363a33f029SAlexander Kornienko unsigned &LineLevel;
2373a33f029SAlexander Kornienko unsigned OldLineLevel;
2383a33f029SAlexander Kornienko };
2393a33f029SAlexander Kornienko
24069665e11SCraig Topper namespace {
24169665e11SCraig Topper
242ab41991cSManuel Klimek class IndexedTokenSource : public FormatTokenSource {
243ab41991cSManuel Klimek public:
IndexedTokenSource(ArrayRef<FormatToken * > Tokens)24415dfe7acSManuel Klimek IndexedTokenSource(ArrayRef<FormatToken *> Tokens)
245ab41991cSManuel Klimek : Tokens(Tokens), Position(-1) {}
246ab41991cSManuel Klimek
getNextToken()247fb6b25b5SCraig Topper FormatToken *getNextToken() override {
2481b5a43acSManuel Klimek if (Position >= 0 && Tokens[Position]->is(tok::eof)) {
2491b5a43acSManuel Klimek LLVM_DEBUG({
2501b5a43acSManuel Klimek llvm::dbgs() << "Next ";
2511b5a43acSManuel Klimek dbgToken(Position);
2521b5a43acSManuel Klimek });
25384bf5e32SManuel Klimek return Tokens[Position];
2541b5a43acSManuel Klimek }
255ab41991cSManuel Klimek ++Position;
2561b5a43acSManuel Klimek LLVM_DEBUG({
2571b5a43acSManuel Klimek llvm::dbgs() << "Next ";
2581b5a43acSManuel Klimek dbgToken(Position);
2591b5a43acSManuel Klimek });
260ab41991cSManuel Klimek return Tokens[Position];
261ab41991cSManuel Klimek }
262ab41991cSManuel Klimek
getPreviousToken()2631b5a43acSManuel Klimek FormatToken *getPreviousToken() override {
264d97025adSowenca return Position > 0 ? Tokens[Position - 1] : nullptr;
2651b5a43acSManuel Klimek }
2661b5a43acSManuel Klimek
peekNextToken()2671b5a43acSManuel Klimek FormatToken *peekNextToken() override {
2681b5a43acSManuel Klimek int Next = Position + 1;
2691b5a43acSManuel Klimek LLVM_DEBUG({
2701b5a43acSManuel Klimek llvm::dbgs() << "Peeking ";
2711b5a43acSManuel Klimek dbgToken(Next);
2721b5a43acSManuel Klimek });
2731b5a43acSManuel Klimek return Tokens[Next];
2741b5a43acSManuel Klimek }
2751b5a43acSManuel Klimek
peekNextToken(int N)276bcd1e461SBjörn Schäpers FormatToken *peekNextToken(int N) override {
277bcd1e461SBjörn Schäpers assert(N > 0);
278bcd1e461SBjörn Schäpers int Next = Position + N;
279bcd1e461SBjörn Schäpers LLVM_DEBUG({
280bcd1e461SBjörn Schäpers llvm::dbgs() << "Peeking (+" << (N - 1) << ") ";
281bcd1e461SBjörn Schäpers dbgToken(Next);
282bcd1e461SBjörn Schäpers });
283bcd1e461SBjörn Schäpers return Tokens[Next];
284bcd1e461SBjörn Schäpers }
285bcd1e461SBjörn Schäpers
isEOF()2861b5a43acSManuel Klimek bool isEOF() override { return Tokens[Position]->is(tok::eof); }
2871b5a43acSManuel Klimek
getPosition()288fb6b25b5SCraig Topper unsigned getPosition() override {
2891b5a43acSManuel Klimek LLVM_DEBUG(llvm::dbgs() << "Getting Position: " << Position << "\n");
290ab41991cSManuel Klimek assert(Position >= 0);
291ab41991cSManuel Klimek return Position;
292ab41991cSManuel Klimek }
293ab41991cSManuel Klimek
setPosition(unsigned P)294fb6b25b5SCraig Topper FormatToken *setPosition(unsigned P) override {
2951b5a43acSManuel Klimek LLVM_DEBUG(llvm::dbgs() << "Setting Position: " << P << "\n");
296ab41991cSManuel Klimek Position = P;
297ab41991cSManuel Klimek return Tokens[Position];
298ab41991cSManuel Klimek }
299ab41991cSManuel Klimek
reset()30071814b44SManuel Klimek void reset() { Position = -1; }
30171814b44SManuel Klimek
302ab41991cSManuel Klimek private:
dbgToken(int Position,llvm::StringRef Indent="")3031b5a43acSManuel Klimek void dbgToken(int Position, llvm::StringRef Indent = "") {
3041b5a43acSManuel Klimek FormatToken *Tok = Tokens[Position];
3051b5a43acSManuel Klimek llvm::dbgs() << Indent << "[" << Position
3061b5a43acSManuel Klimek << "] Token: " << Tok->Tok.getName() << " / " << Tok->TokenText
3071b5a43acSManuel Klimek << ", Macro: " << !!Tok->MacroCtx << "\n";
3081b5a43acSManuel Klimek }
3091b5a43acSManuel Klimek
31015dfe7acSManuel Klimek ArrayRef<FormatToken *> Tokens;
311ab41991cSManuel Klimek int Position;
312ab41991cSManuel Klimek };
313ab41991cSManuel Klimek
31469665e11SCraig Topper } // end anonymous namespace
31569665e11SCraig Topper
UnwrappedLineParser(const FormatStyle & Style,const AdditionalKeywords & Keywords,unsigned FirstStartColumn,ArrayRef<FormatToken * > Tokens,UnwrappedLineConsumer & Callback)316d2ae41a7SDaniel Jasper UnwrappedLineParser::UnwrappedLineParser(const FormatStyle &Style,
317d0ec0d62SDaniel Jasper const AdditionalKeywords &Keywords,
3189ad83fe7SKrasimir Georgiev unsigned FirstStartColumn,
31915dfe7acSManuel Klimek ArrayRef<FormatToken *> Tokens,
320d2ae41a7SDaniel Jasper UnwrappedLineConsumer &Callback)
321d3b92fa6SManuel Klimek : Line(new UnwrappedLine), MustBreakBeforeNextToken(false),
32200c5c72dSKrasimir Georgiev CurrentLines(&Lines), Style(Style), Keywords(Keywords),
32300c5c72dSKrasimir Georgiev CommentPragmasRegex(Style.CommentPragmas), Tokens(nullptr),
324ad47c907SKrasimir Georgiev Callback(Callback), AllTokens(Tokens), PPBranchLevel(-1),
3251c3afaf5SMark Zeren IncludeGuard(Style.IndentPPDirectives == FormatStyle::PPDIS_None
3261c3afaf5SMark Zeren ? IG_Rejected
3271c3afaf5SMark Zeren : IG_Inited),
3281c3afaf5SMark Zeren IncludeGuardToken(nullptr), FirstStartColumn(FirstStartColumn) {}
32971814b44SManuel Klimek
reset()33071814b44SManuel Klimek void UnwrappedLineParser::reset() {
33171814b44SManuel Klimek PPBranchLevel = -1;
3321c3afaf5SMark Zeren IncludeGuard = Style.IndentPPDirectives == FormatStyle::PPDIS_None
3331c3afaf5SMark Zeren ? IG_Rejected
3341c3afaf5SMark Zeren : IG_Inited;
3351c3afaf5SMark Zeren IncludeGuardToken = nullptr;
33671814b44SManuel Klimek Line.reset(new UnwrappedLine);
33771814b44SManuel Klimek CommentsBeforeNextToken.clear();
3382145bc02SCraig Topper FormatTok = nullptr;
33971814b44SManuel Klimek MustBreakBeforeNextToken = false;
34071814b44SManuel Klimek PreprocessorDirectives.clear();
34171814b44SManuel Klimek CurrentLines = &Lines;
34271814b44SManuel Klimek DeclarationScopeStack.clear();
343533fbae8SOwen Pan NestedTooDeep.clear();
34471814b44SManuel Klimek PPStack.clear();
3459ad83fe7SKrasimir Georgiev Line->FirstStartColumn = FirstStartColumn;
34671814b44SManuel Klimek }
347f7935115SDaniel Jasper
parse()34820e0af6bSManuel Klimek void UnwrappedLineParser::parse() {
349ab41991cSManuel Klimek IndexedTokenSource TokenSource(AllTokens);
3509ad83fe7SKrasimir Georgiev Line->FirstStartColumn = FirstStartColumn;
35171814b44SManuel Klimek do {
3523538b39eSNicola Zaghen LLVM_DEBUG(llvm::dbgs() << "----\n");
35371814b44SManuel Klimek reset();
354ab41991cSManuel Klimek Tokens = &TokenSource;
35571814b44SManuel Klimek TokenSource.reset();
35671814b44SManuel Klimek
3571abf789cSManuel Klimek readToken();
3581a18c404SManuel Klimek parseFile();
3591c3afaf5SMark Zeren
3601c3afaf5SMark Zeren // If we found an include guard then all preprocessor directives (other than
3611c3afaf5SMark Zeren // the guard) are over-indented by one.
362bebf7bdfSowenca if (IncludeGuard == IG_Found) {
3631c3afaf5SMark Zeren for (auto &Line : Lines)
3641c3afaf5SMark Zeren if (Line.InPPDirective && Line.Level > 0)
3651c3afaf5SMark Zeren --Line.Level;
366bebf7bdfSowenca }
3671c3afaf5SMark Zeren
36871814b44SManuel Klimek // Create line with eof token.
36971814b44SManuel Klimek pushToken(FormatTok);
37071814b44SManuel Klimek addUnwrappedLine();
37171814b44SManuel Klimek
37201f355feSMarek Kurdej for (const UnwrappedLine &Line : Lines)
37301f355feSMarek Kurdej Callback.consumeUnwrappedLine(Line);
37401f355feSMarek Kurdej
37571814b44SManuel Klimek Callback.finishRun();
37671814b44SManuel Klimek Lines.clear();
37771814b44SManuel Klimek while (!PPLevelBranchIndex.empty() &&
37853bd167cSDaniel Jasper PPLevelBranchIndex.back() + 1 >= PPLevelBranchCount.back()) {
37971814b44SManuel Klimek PPLevelBranchIndex.resize(PPLevelBranchIndex.size() - 1);
38071814b44SManuel Klimek PPLevelBranchCount.resize(PPLevelBranchCount.size() - 1);
38171814b44SManuel Klimek }
38271814b44SManuel Klimek if (!PPLevelBranchIndex.empty()) {
38371814b44SManuel Klimek ++PPLevelBranchIndex.back();
38471814b44SManuel Klimek assert(PPLevelBranchIndex.size() == PPLevelBranchCount.size());
38571814b44SManuel Klimek assert(PPLevelBranchIndex.back() <= PPLevelBranchCount.back());
38671814b44SManuel Klimek }
38771814b44SManuel Klimek } while (!PPLevelBranchIndex.empty());
3881abf789cSManuel Klimek }
3891abf789cSManuel Klimek
parseFile()3901a18c404SManuel Klimek void UnwrappedLineParser::parseFile() {
3919326f919SDaniel Jasper // The top-level context in a file always has declarations, except for pre-
3929326f919SDaniel Jasper // processor directives and JavaScript files.
393142e79b8Smydeveloperday bool MustBeDeclaration = !Line->InPPDirective && !Style.isJavaScript();
3949326f919SDaniel Jasper ScopedDeclarationState DeclarationState(*Line, DeclarationScopeStack,
3959326f919SDaniel Jasper MustBeDeclaration);
39626b144ccSKrasimir Georgiev if (Style.Language == FormatStyle::LK_TextProto)
39726b144ccSKrasimir Georgiev parseBracedList();
39826b144ccSKrasimir Georgiev else
399ec90bc0eSowenca parseLevel();
4001abf789cSManuel Klimek // Make sure to format the remaining tokens.
4010895f5e8SKrasimir Georgiev //
4020895f5e8SKrasimir Georgiev // LK_TextProto is special since its top-level is parsed as the body of a
4030895f5e8SKrasimir Georgiev // braced list, which does not necessarily have natural line separators such
4040895f5e8SKrasimir Georgiev // as a semicolon. Comments after the last entry that have been determined to
4050895f5e8SKrasimir Georgiev // not belong to that line, as in:
4060895f5e8SKrasimir Georgiev // key: value
4070895f5e8SKrasimir Georgiev // // endfile comment
4080895f5e8SKrasimir Georgiev // do not have a chance to be put on a line of their own until this point.
4090895f5e8SKrasimir Georgiev // Here we add this newline before end-of-file comments.
4100895f5e8SKrasimir Georgiev if (Style.Language == FormatStyle::LK_TextProto &&
411bebf7bdfSowenca !CommentsBeforeNextToken.empty()) {
4120895f5e8SKrasimir Georgiev addUnwrappedLine();
413bebf7bdfSowenca }
414f92f7bc5SManuel Klimek flushComments(true);
4151abf789cSManuel Klimek addUnwrappedLine();
416f7935115SDaniel Jasper }
417f7935115SDaniel Jasper
parseCSharpGenericTypeConstraint()418dcbcec48SJonathan Coe void UnwrappedLineParser::parseCSharpGenericTypeConstraint() {
419dcbcec48SJonathan Coe do {
420dcbcec48SJonathan Coe switch (FormatTok->Tok.getKind()) {
421dcbcec48SJonathan Coe case tok::l_brace:
422dcbcec48SJonathan Coe return;
423dcbcec48SJonathan Coe default:
424dcbcec48SJonathan Coe if (FormatTok->is(Keywords.kw_where)) {
425dcbcec48SJonathan Coe addUnwrappedLine();
426dcbcec48SJonathan Coe nextToken();
427dcbcec48SJonathan Coe parseCSharpGenericTypeConstraint();
428dcbcec48SJonathan Coe break;
429dcbcec48SJonathan Coe }
430dcbcec48SJonathan Coe nextToken();
431dcbcec48SJonathan Coe break;
432dcbcec48SJonathan Coe }
433dcbcec48SJonathan Coe } while (!eof());
434dcbcec48SJonathan Coe }
435dcbcec48SJonathan Coe
parseCSharpAttribute()436b46f925dSJonathan Coe void UnwrappedLineParser::parseCSharpAttribute() {
4379f8a7e82SJonathan Coe int UnpairedSquareBrackets = 1;
438b46f925dSJonathan Coe do {
439b46f925dSJonathan Coe switch (FormatTok->Tok.getKind()) {
440b46f925dSJonathan Coe case tok::r_square:
441b46f925dSJonathan Coe nextToken();
4429f8a7e82SJonathan Coe --UnpairedSquareBrackets;
4439f8a7e82SJonathan Coe if (UnpairedSquareBrackets == 0) {
444b46f925dSJonathan Coe addUnwrappedLine();
445b46f925dSJonathan Coe return;
4469f8a7e82SJonathan Coe }
4479f8a7e82SJonathan Coe break;
4489f8a7e82SJonathan Coe case tok::l_square:
4499f8a7e82SJonathan Coe ++UnpairedSquareBrackets;
4509f8a7e82SJonathan Coe nextToken();
4519f8a7e82SJonathan Coe break;
452b46f925dSJonathan Coe default:
453b46f925dSJonathan Coe nextToken();
454b46f925dSJonathan Coe break;
455b46f925dSJonathan Coe }
456b46f925dSJonathan Coe } while (!eof());
457b46f925dSJonathan Coe }
458b46f925dSJonathan Coe
precededByCommentOrPPDirective() const459533fbae8SOwen Pan bool UnwrappedLineParser::precededByCommentOrPPDirective() const {
460533fbae8SOwen Pan if (!Lines.empty() && Lines.back().InPPDirective)
461533fbae8SOwen Pan return true;
462533fbae8SOwen Pan
463533fbae8SOwen Pan const FormatToken *Previous = Tokens->getPreviousToken();
464533fbae8SOwen Pan return Previous && Previous->is(tok::comment) &&
465533fbae8SOwen Pan (Previous->IsMultiline || Previous->NewlinesBefore > 0);
466533fbae8SOwen Pan }
467b6d8c84fSowenca
4689aab0db1SBjörn Schäpers /// \brief Parses a level, that is ???.
4699dffab9dSowenca /// \param OpeningBrace Opening brace (\p nullptr if absent) of that level
4709aab0db1SBjörn Schäpers /// \param CanContainBracedList If the content can contain (at any level) a
4719aab0db1SBjörn Schäpers /// braced list.
4729aab0db1SBjörn Schäpers /// \param NextLBracesType The type for left brace found in this level.
4735ead1f13Sowenca /// \param IfKind The \p if statement kind in the level.
4745ead1f13Sowenca /// \param IfLeftBrace The left brace of the \p if block in the level.
4759dffab9dSowenca /// \returns true if a simple block of if/else/for/while, or false otherwise.
4769dffab9dSowenca /// (A simple block has a single statement.)
parseLevel(const FormatToken * OpeningBrace,bool CanContainBracedList,TokenType NextLBracesType,IfStmtKind * IfKind,FormatToken ** IfLeftBrace)4779dffab9dSowenca bool UnwrappedLineParser::parseLevel(const FormatToken *OpeningBrace,
4789aab0db1SBjörn Schäpers bool CanContainBracedList,
479ec90bc0eSowenca TokenType NextLBracesType,
4805ead1f13Sowenca IfStmtKind *IfKind,
4815ead1f13Sowenca FormatToken **IfLeftBrace) {
4829aab0db1SBjörn Schäpers auto NextLevelLBracesType = NextLBracesType == TT_CompoundRequirementLBrace
4839aab0db1SBjörn Schäpers ? TT_BracedListLBrace
4849aab0db1SBjörn Schäpers : TT_Unknown;
485533fbae8SOwen Pan const bool IsPrecededByCommentOrPPDirective =
486533fbae8SOwen Pan !Style.RemoveBracesLLVM || precededByCommentOrPPDirective();
4875ead1f13Sowenca FormatToken *IfLBrace = nullptr;
488db15e312Sowenca bool HasDoWhile = false;
48928b76b1eSowenca bool HasLabel = false;
490533fbae8SOwen Pan unsigned StatementCount = 0;
491516d7971SDaniel Jasper bool SwitchLabelEncountered = false;
492ec90bc0eSowenca
493f7935115SDaniel Jasper do {
4944e88cb68SMarek Kurdej if (FormatTok->getType() == TT_AttributeMacro) {
4954e88cb68SMarek Kurdej nextToken();
4964e88cb68SMarek Kurdej continue;
4974e88cb68SMarek Kurdej }
498b001a0baSBirunthan Mohanathas tok::TokenKind kind = FormatTok->Tok.getKind();
499d079995dSMarek Kurdej if (FormatTok->getType() == TT_MacroBlockBegin)
500b001a0baSBirunthan Mohanathas kind = tok::l_brace;
501d079995dSMarek Kurdej else if (FormatTok->getType() == TT_MacroBlockEnd)
502b001a0baSBirunthan Mohanathas kind = tok::r_brace;
503b001a0baSBirunthan Mohanathas
504ec90bc0eSowenca auto ParseDefault = [this, OpeningBrace, NextLevelLBracesType, IfKind,
5055ead1f13Sowenca &IfLBrace, &HasDoWhile, &HasLabel, &StatementCount] {
506ec90bc0eSowenca parseStructuralElement(!OpeningBrace, NextLevelLBracesType, IfKind,
5075ead1f13Sowenca &IfLBrace, HasDoWhile ? nullptr : &HasDoWhile,
50828b76b1eSowenca HasLabel ? nullptr : &HasLabel);
5099aab0db1SBjörn Schäpers ++StatementCount;
5109aab0db1SBjörn Schäpers assert(StatementCount > 0 && "StatementCount overflow!");
5119aab0db1SBjörn Schäpers };
5129aab0db1SBjörn Schäpers
513b001a0baSBirunthan Mohanathas switch (kind) {
514f7935115SDaniel Jasper case tok::comment:
515e25509f8SDaniel Jasper nextToken();
516e25509f8SDaniel Jasper addUnwrappedLine();
517f7935115SDaniel Jasper break;
518f7935115SDaniel Jasper case tok::l_brace:
519bebf7bdfSowenca if (NextLBracesType != TT_Unknown) {
5201e7cc72aSBjörn Schäpers FormatTok->setFinalizedType(NextLBracesType);
521bebf7bdfSowenca } else if (FormatTok->Previous &&
5229aab0db1SBjörn Schäpers FormatTok->Previous->ClosesRequiresClause) {
5239aab0db1SBjörn Schäpers // We need the 'default' case here to correctly parse a function
5249aab0db1SBjörn Schäpers // l_brace.
5259aab0db1SBjörn Schäpers ParseDefault();
526b86e2727SDaniel Jasper continue;
5279aab0db1SBjörn Schäpers }
5289aab0db1SBjörn Schäpers if (CanContainBracedList && !FormatTok->is(TT_MacroBlockBegin) &&
529bebf7bdfSowenca tryToParseBracedList()) {
5309aab0db1SBjörn Schäpers continue;
531bebf7bdfSowenca }
5329aab0db1SBjörn Schäpers parseBlock(/*MustBeDeclaration=*/false, /*AddLevels=*/1u,
533ec90bc0eSowenca /*MunchSemi=*/true, /*KeepBraces=*/true, /*IfKind=*/nullptr,
5349dffab9dSowenca /*UnindentWhitesmithsBraces=*/false, CanContainBracedList,
5359dffab9dSowenca NextLBracesType);
536533fbae8SOwen Pan ++StatementCount;
537533fbae8SOwen Pan assert(StatementCount > 0 && "StatementCount overflow!");
538f7935115SDaniel Jasper addUnwrappedLine();
539f7935115SDaniel Jasper break;
540f7935115SDaniel Jasper case tok::r_brace:
5419dffab9dSowenca if (OpeningBrace) {
542a0458d92Sowenca if (!Style.RemoveBracesLLVM || Line->InPPDirective ||
543bebf7bdfSowenca !OpeningBrace->isOneOf(TT_ControlStatementLBrace, TT_ElseLBrace)) {
544533fbae8SOwen Pan return false;
545bebf7bdfSowenca }
54628b76b1eSowenca if (FormatTok->isNot(tok::r_brace) || StatementCount != 1 || HasLabel ||
547db15e312Sowenca HasDoWhile || IsPrecededByCommentOrPPDirective ||
548bebf7bdfSowenca precededByCommentOrPPDirective()) {
549533fbae8SOwen Pan return false;
550bebf7bdfSowenca }
551533fbae8SOwen Pan const FormatToken *Next = Tokens->peekNextToken();
5525ead1f13Sowenca if (Next->is(tok::comment) && Next->NewlinesBefore == 0)
5535ead1f13Sowenca return false;
5545ead1f13Sowenca if (IfLeftBrace)
5555ead1f13Sowenca *IfLeftBrace = IfLBrace;
5565ead1f13Sowenca return true;
557533fbae8SOwen Pan }
5581058d987SManuel Klimek nextToken();
5591058d987SManuel Klimek addUnwrappedLine();
5601058d987SManuel Klimek break;
561c29f83b7SNico Weber case tok::kw_default: {
562c29f83b7SNico Weber unsigned StoredPosition = Tokens->getPosition();
56390d2aa23SJonas Toth FormatToken *Next;
56490d2aa23SJonas Toth do {
56590d2aa23SJonas Toth Next = Tokens->getNextToken();
566bb1b53daSMarek Kurdej assert(Next);
56784bf5e32SManuel Klimek } while (Next->is(tok::comment));
568c29f83b7SNico Weber FormatTok = Tokens->setPosition(StoredPosition);
569bb1b53daSMarek Kurdej if (Next->isNot(tok::colon)) {
570c29f83b7SNico Weber // default not followed by ':' is not a case label; treat it like
571c29f83b7SNico Weber // an identifier.
572c29f83b7SNico Weber parseStructuralElement();
573c29f83b7SNico Weber break;
574c29f83b7SNico Weber }
575c29f83b7SNico Weber // Else, if it is 'default:', fall through to the case handling.
576f1add5e0SNico Weber LLVM_FALLTHROUGH;
577c29f83b7SNico Weber }
578516d7971SDaniel Jasper case tok::kw_case:
579142e79b8Smydeveloperday if (Style.isJavaScript() && Line->MustBeDeclaration) {
580f785fd94SMartin Probst // A 'case: string' style field declaration.
581f785fd94SMartin Probst parseStructuralElement();
582f785fd94SMartin Probst break;
583f785fd94SMartin Probst }
58472407625SDaniel Jasper if (!SwitchLabelEncountered &&
585bebf7bdfSowenca (Style.IndentCaseLabels ||
586bebf7bdfSowenca (Line->InPPDirective && Line->Level == 1))) {
58772407625SDaniel Jasper ++Line->Level;
588bebf7bdfSowenca }
589516d7971SDaniel Jasper SwitchLabelEncountered = true;
590516d7971SDaniel Jasper parseStructuralElement();
591516d7971SDaniel Jasper break;
592b46f925dSJonathan Coe case tok::l_square:
593b46f925dSJonathan Coe if (Style.isCSharp()) {
594b46f925dSJonathan Coe nextToken();
595b46f925dSJonathan Coe parseCSharpAttribute();
596b46f925dSJonathan Coe break;
597b46f925dSJonathan Coe }
5984e88cb68SMarek Kurdej if (handleCppAttributes())
5994e88cb68SMarek Kurdej break;
600b46f925dSJonathan Coe LLVM_FALLTHROUGH;
601f7935115SDaniel Jasper default:
6029aab0db1SBjörn Schäpers ParseDefault();
603f7935115SDaniel Jasper break;
604f7935115SDaniel Jasper }
605f7935115SDaniel Jasper } while (!eof());
606ec90bc0eSowenca
607533fbae8SOwen Pan return false;
608f7935115SDaniel Jasper }
609f7935115SDaniel Jasper
calculateBraceTypes(bool ExpectClassBody)610adba2aadSDaniel Jasper void UnwrappedLineParser::calculateBraceTypes(bool ExpectClassBody) {
611ab41991cSManuel Klimek // We'll parse forward through the tokens until we hit
612ab41991cSManuel Klimek // a closing brace or eof - note that getNextToken() will
613ab41991cSManuel Klimek // parse macros, so this will magically work inside macro
614ab41991cSManuel Klimek // definitions, too.
615ab41991cSManuel Klimek unsigned StoredPosition = Tokens->getPosition();
61615dfe7acSManuel Klimek FormatToken *Tok = FormatTok;
617e411aa85SManuel Klimek const FormatToken *PrevTok = Tok->Previous;
618ab41991cSManuel Klimek // Keep a stack of positions of lbrace tokens. We will
619ab41991cSManuel Klimek // update information about whether an lbrace starts a
620ab41991cSManuel Klimek // braced init list or a different block during the loop.
621b1f74a81SDaniel Jasper SmallVector<FormatToken *, 8> LBraceStack;
622fee4a971SMarek Kurdej assert(Tok->is(tok::l_brace));
623ab41991cSManuel Klimek do {
624eb65e912SDaniel Jasper // Get next non-comment token.
6257f5d53e5SDaniel Jasper FormatToken *NextTok;
6267f5d53e5SDaniel Jasper do {
6277f5d53e5SDaniel Jasper NextTok = Tokens->getNextToken();
6287f5d53e5SDaniel Jasper } while (NextTok->is(tok::comment));
6297f5d53e5SDaniel Jasper
63015dfe7acSManuel Klimek switch (Tok->Tok.getKind()) {
631ab41991cSManuel Klimek case tok::l_brace:
632142e79b8Smydeveloperday if (Style.isJavaScript() && PrevTok) {
633bebf7bdfSowenca if (PrevTok->isOneOf(tok::colon, tok::less)) {
634e8e27ca8SMartin Probst // A ':' indicates this code is in a type, or a braced list
635e8e27ca8SMartin Probst // following a label in an object literal ({a: {b: 1}}).
636e8e27ca8SMartin Probst // A '<' could be an object used in a comparison, but that is nonsense
637e8e27ca8SMartin Probst // code (can never return true), so more likely it is a generic type
638e8e27ca8SMartin Probst // argument (`X<{a: string; b: number}>`).
639e8e27ca8SMartin Probst // The code below could be confused by semicolons between the
640e8e27ca8SMartin Probst // individual members in a type member list, which would normally
641e8e27ca8SMartin Probst // trigger BK_Block. In both cases, this must be parsed as an inline
642e8e27ca8SMartin Probst // braced init.
643f5acd11dSBruno Ricci Tok->setBlockKind(BK_BracedInit);
644bebf7bdfSowenca } else if (PrevTok->is(tok::r_paren)) {
64595ed8e79SMartin Probst // `) { }` can only occur in function or method declarations in JS.
646f5acd11dSBruno Ricci Tok->setBlockKind(BK_Block);
647bebf7bdfSowenca }
64895ed8e79SMartin Probst } else {
649f5acd11dSBruno Ricci Tok->setBlockKind(BK_Unknown);
65095ed8e79SMartin Probst }
651b1f74a81SDaniel Jasper LBraceStack.push_back(Tok);
652ab41991cSManuel Klimek break;
653ab41991cSManuel Klimek case tok::r_brace:
654b9a4990aSDaniel Jasper if (LBraceStack.empty())
655b9a4990aSDaniel Jasper break;
656f5acd11dSBruno Ricci if (LBraceStack.back()->is(BK_Unknown)) {
657220c0d1fSDaniel Jasper bool ProbablyBracedList = false;
658220c0d1fSDaniel Jasper if (Style.Language == FormatStyle::LK_Proto) {
659220c0d1fSDaniel Jasper ProbablyBracedList = NextTok->isOneOf(tok::comma, tok::r_square);
660220c0d1fSDaniel Jasper } else {
6613d209c76SJosh Learn // Skip NextTok over preprocessor lines, otherwise we may not
6623d209c76SJosh Learn // properly diagnose the block as a braced intializer
6633d209c76SJosh Learn // if the comma separator appears after the pp directive.
6643d209c76SJosh Learn while (NextTok->is(tok::hash)) {
6653d209c76SJosh Learn ScopedMacroState MacroState(*Line, Tokens, NextTok);
6663d209c76SJosh Learn do {
6673d209c76SJosh Learn NextTok = Tokens->getNextToken();
6683d209c76SJosh Learn } while (NextTok->isNot(tok::eof));
6693d209c76SJosh Learn }
6703d209c76SJosh Learn
67191b032abSDaniel Jasper // Using OriginalColumn to distinguish between ObjC methods and
67291b032abSDaniel Jasper // binary operators is a bit hacky.
67391b032abSDaniel Jasper bool NextIsObjCMethod = NextTok->isOneOf(tok::plus, tok::minus) &&
67491b032abSDaniel Jasper NextTok->OriginalColumn == 0;
67591b032abSDaniel Jasper
6769aab0db1SBjörn Schäpers // Try to detect a braced list. Note that regardless how we mark inner
6779aab0db1SBjörn Schäpers // braces here, we will overwrite the BlockKind later if we parse a
6789aab0db1SBjörn Schäpers // braced list (where all blocks inside are by default braced lists),
6799aab0db1SBjörn Schäpers // or when we explicitly detect blocks (for example while parsing
6809aab0db1SBjörn Schäpers // lambdas).
6819aab0db1SBjörn Schäpers
6829aab0db1SBjörn Schäpers // If we already marked the opening brace as braced list, the closing
6839aab0db1SBjörn Schäpers // must also be part of it.
6849aab0db1SBjörn Schäpers ProbablyBracedList = LBraceStack.back()->is(TT_BracedListLBrace);
6859aab0db1SBjörn Schäpers
6869aab0db1SBjörn Schäpers ProbablyBracedList = ProbablyBracedList ||
6879aab0db1SBjörn Schäpers (Style.isJavaScript() &&
6889aab0db1SBjörn Schäpers NextTok->isOneOf(Keywords.kw_of, Keywords.kw_in,
6899aab0db1SBjörn Schäpers Keywords.kw_as));
6909aab0db1SBjörn Schäpers ProbablyBracedList = ProbablyBracedList ||
6919aab0db1SBjörn Schäpers (Style.isCpp() && NextTok->is(tok::l_paren));
6929aab0db1SBjörn Schäpers
693ab41991cSManuel Klimek // If there is a comma, semicolon or right paren after the closing
6949aab0db1SBjörn Schäpers // brace, we assume this is a braced initializer list.
695d96bf6eaSKrasimir Georgiev // FIXME: Some of these do not apply to JS, e.g. "} {" can never be a
696d96bf6eaSKrasimir Georgiev // braced list in JS.
697220c0d1fSDaniel Jasper ProbablyBracedList =
6989aab0db1SBjörn Schäpers ProbablyBracedList ||
699adba2aadSDaniel Jasper NextTok->isOneOf(tok::comma, tok::period, tok::colon,
700d96bf6eaSKrasimir Georgiev tok::r_paren, tok::r_square, tok::l_brace,
7019aab0db1SBjörn Schäpers tok::ellipsis);
7029aab0db1SBjörn Schäpers
7039aab0db1SBjörn Schäpers ProbablyBracedList =
7049aab0db1SBjörn Schäpers ProbablyBracedList ||
705d96bf6eaSKrasimir Georgiev (NextTok->is(tok::identifier) &&
7069aab0db1SBjörn Schäpers !PrevTok->isOneOf(tok::semi, tok::r_brace, tok::l_brace));
7079aab0db1SBjörn Schäpers
7089aab0db1SBjörn Schäpers ProbablyBracedList = ProbablyBracedList ||
709cec9ffd2SDaniel Jasper (NextTok->is(tok::semi) &&
7109aab0db1SBjörn Schäpers (!ExpectClassBody || LBraceStack.size() != 1));
7119aab0db1SBjörn Schäpers
7129aab0db1SBjörn Schäpers ProbablyBracedList =
7139aab0db1SBjörn Schäpers ProbablyBracedList ||
71491b032abSDaniel Jasper (NextTok->isBinaryOperator() && !NextIsObjCMethod);
7159aab0db1SBjörn Schäpers
7162f209ccfSmydeveloperday if (!Style.isCSharp() && NextTok->is(tok::l_square)) {
717d0f3fe55SManuel Klimek // We can have an array subscript after a braced init
718d0f3fe55SManuel Klimek // list, but C++11 attributes are expected after blocks.
719d0f3fe55SManuel Klimek NextTok = Tokens->getNextToken();
720d0f3fe55SManuel Klimek ProbablyBracedList = NextTok->isNot(tok::l_square);
721d0f3fe55SManuel Klimek }
722220c0d1fSDaniel Jasper }
723220c0d1fSDaniel Jasper if (ProbablyBracedList) {
724f5acd11dSBruno Ricci Tok->setBlockKind(BK_BracedInit);
725f5acd11dSBruno Ricci LBraceStack.back()->setBlockKind(BK_BracedInit);
726b1f74a81SDaniel Jasper } else {
727f5acd11dSBruno Ricci Tok->setBlockKind(BK_Block);
728f5acd11dSBruno Ricci LBraceStack.back()->setBlockKind(BK_Block);
729b1f74a81SDaniel Jasper }
730ab41991cSManuel Klimek }
731ab41991cSManuel Klimek LBraceStack.pop_back();
732ab41991cSManuel Klimek break;
7336f40e21aSFrancois Ferrand case tok::identifier:
7346f40e21aSFrancois Ferrand if (!Tok->is(TT_StatementMacro))
7356f40e21aSFrancois Ferrand break;
7366f40e21aSFrancois Ferrand LLVM_FALLTHROUGH;
737ac7e34e7SDaniel Jasper case tok::at:
738ab41991cSManuel Klimek case tok::semi:
739ab41991cSManuel Klimek case tok::kw_if:
740ab41991cSManuel Klimek case tok::kw_while:
741ab41991cSManuel Klimek case tok::kw_for:
742ab41991cSManuel Klimek case tok::kw_switch:
743ab41991cSManuel Klimek case tok::kw_try:
744fac2371bSNico Weber case tok::kw___try:
745f5acd11dSBruno Ricci if (!LBraceStack.empty() && LBraceStack.back()->is(BK_Unknown))
746f5acd11dSBruno Ricci LBraceStack.back()->setBlockKind(BK_Block);
747ab41991cSManuel Klimek break;
748ab41991cSManuel Klimek default:
749ab41991cSManuel Klimek break;
750ab41991cSManuel Klimek }
751b9a4990aSDaniel Jasper PrevTok = Tok;
752ab41991cSManuel Klimek Tok = NextTok;
753fee4a971SMarek Kurdej } while (Tok->isNot(tok::eof) && !LBraceStack.empty());
754b9a4990aSDaniel Jasper
755ab41991cSManuel Klimek // Assume other blocks for all unclosed opening braces.
756d079995dSMarek Kurdej for (FormatToken *LBrace : LBraceStack)
757545317cbSMarek Kurdej if (LBrace->is(BK_Unknown))
758545317cbSMarek Kurdej LBrace->setBlockKind(BK_Block);
759bab25fdfSManuel Klimek
760ab41991cSManuel Klimek FormatTok = Tokens->setPosition(StoredPosition);
761ab41991cSManuel Klimek }
762ab41991cSManuel Klimek
763a98a95ccSFrancois Ferrand template <class T>
hash_combine(std::size_t & seed,const T & v)764a98a95ccSFrancois Ferrand static inline void hash_combine(std::size_t &seed, const T &v) {
765a98a95ccSFrancois Ferrand std::hash<T> hasher;
766a98a95ccSFrancois Ferrand seed ^= hasher(v) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
767a98a95ccSFrancois Ferrand }
768a98a95ccSFrancois Ferrand
computePPHash() const769a98a95ccSFrancois Ferrand size_t UnwrappedLineParser::computePPHash() const {
770a98a95ccSFrancois Ferrand size_t h = 0;
771a98a95ccSFrancois Ferrand for (const auto &i : PPStack) {
772a98a95ccSFrancois Ferrand hash_combine(h, size_t(i.Kind));
773a98a95ccSFrancois Ferrand hash_combine(h, i.Line);
774a98a95ccSFrancois Ferrand }
775a98a95ccSFrancois Ferrand return h;
776a98a95ccSFrancois Ferrand }
777a98a95ccSFrancois Ferrand
7781443dbabSowenca // Checks whether \p ParsedLine might fit on a single line. If \p OpeningBrace
7791443dbabSowenca // is not null, subtracts its length (plus the preceding space) when computing
7801443dbabSowenca // the length of \p ParsedLine. We must clone the tokens of \p ParsedLine before
7811443dbabSowenca // running the token annotator on it so that we can restore them afterward.
mightFitOnOneLine(UnwrappedLine & ParsedLine,const FormatToken * OpeningBrace) const7821443dbabSowenca bool UnwrappedLineParser::mightFitOnOneLine(
7831443dbabSowenca UnwrappedLine &ParsedLine, const FormatToken *OpeningBrace) const {
784b6d8c84fSowenca const auto ColumnLimit = Style.ColumnLimit;
785b6d8c84fSowenca if (ColumnLimit == 0)
786b6d8c84fSowenca return true;
787b6d8c84fSowenca
788b6d8c84fSowenca auto &Tokens = ParsedLine.Tokens;
789b6d8c84fSowenca assert(!Tokens.empty());
7901443dbabSowenca
791b6d8c84fSowenca const auto *LastToken = Tokens.back().Tok;
792b6d8c84fSowenca assert(LastToken);
793b6d8c84fSowenca
794b6d8c84fSowenca SmallVector<UnwrappedLineNode> SavedTokens(Tokens.size());
795b6d8c84fSowenca
796b6d8c84fSowenca int Index = 0;
797b6d8c84fSowenca for (const auto &Token : Tokens) {
798b6d8c84fSowenca assert(Token.Tok);
799b6d8c84fSowenca auto &SavedToken = SavedTokens[Index++];
800b6d8c84fSowenca SavedToken.Tok = new FormatToken;
801b6d8c84fSowenca SavedToken.Tok->copyFrom(*Token.Tok);
802b6d8c84fSowenca SavedToken.Children = std::move(Token.Children);
803b6d8c84fSowenca }
804b6d8c84fSowenca
805b6d8c84fSowenca AnnotatedLine Line(ParsedLine);
806b6d8c84fSowenca assert(Line.Last == LastToken);
807b6d8c84fSowenca
808b6d8c84fSowenca TokenAnnotator Annotator(Style, Keywords);
809b6d8c84fSowenca Annotator.annotate(Line);
810b6d8c84fSowenca Annotator.calculateFormattingInformation(Line);
811b6d8c84fSowenca
8121443dbabSowenca auto Length = LastToken->TotalLength;
8131443dbabSowenca if (OpeningBrace) {
8141443dbabSowenca assert(OpeningBrace != Tokens.front().Tok);
8151443dbabSowenca Length -= OpeningBrace->TokenText.size() + 1;
8161443dbabSowenca }
817b6d8c84fSowenca
818b6d8c84fSowenca Index = 0;
819b6d8c84fSowenca for (auto &Token : Tokens) {
820b6d8c84fSowenca const auto &SavedToken = SavedTokens[Index++];
821b6d8c84fSowenca Token.Tok->copyFrom(*SavedToken.Tok);
822b6d8c84fSowenca Token.Children = std::move(SavedToken.Children);
823b6d8c84fSowenca delete SavedToken.Tok;
824b6d8c84fSowenca }
825b6d8c84fSowenca
826b6d8c84fSowenca return Line.Level * Style.IndentWidth + Length <= ColumnLimit;
827b6d8c84fSowenca }
828b6d8c84fSowenca
parseBlock(bool MustBeDeclaration,unsigned AddLevels,bool MunchSemi,bool KeepBraces,IfStmtKind * IfKind,bool UnindentWhitesmithsBraces,bool CanContainBracedList,TokenType NextLBracesType)8295ead1f13Sowenca FormatToken *UnwrappedLineParser::parseBlock(
8305ead1f13Sowenca bool MustBeDeclaration, unsigned AddLevels, bool MunchSemi, bool KeepBraces,
8315ead1f13Sowenca IfStmtKind *IfKind, bool UnindentWhitesmithsBraces,
8325ead1f13Sowenca bool CanContainBracedList, TokenType NextLBracesType) {
8339ed2e68cSsstwcw auto HandleVerilogBlockLabel = [this]() {
8349ed2e68cSsstwcw // ":" name
8359ed2e68cSsstwcw if (Style.isVerilog() && FormatTok->is(tok::colon)) {
8369ed2e68cSsstwcw nextToken();
8379ed2e68cSsstwcw if (Keywords.isVerilogIdentifier(*FormatTok))
8389ed2e68cSsstwcw nextToken();
8399ed2e68cSsstwcw }
8409ed2e68cSsstwcw };
8419ed2e68cSsstwcw
8429ed2e68cSsstwcw assert((FormatTok->isOneOf(tok::l_brace, TT_MacroBlockBegin) ||
8439ed2e68cSsstwcw (Style.isVerilog() && Keywords.isVerilogBegin(*FormatTok))) &&
844b001a0baSBirunthan Mohanathas "'{' or macro block token expected");
845533fbae8SOwen Pan FormatToken *Tok = FormatTok;
8461443dbabSowenca const bool FollowedByComment = Tokens->peekNextToken()->is(tok::comment);
8471443dbabSowenca auto Index = CurrentLines->size();
848b001a0baSBirunthan Mohanathas const bool MacroBlock = FormatTok->is(TT_MacroBlockBegin);
849f5acd11dSBruno Ricci FormatTok->setBlockKind(BK_Block);
850b001a0baSBirunthan Mohanathas
851f7f9f94bSTim Wojtulewicz // For Whitesmiths mode, jump to the next level prior to skipping over the
852f7f9f94bSTim Wojtulewicz // braces.
853f7f9f94bSTim Wojtulewicz if (AddLevels > 0 && Style.BreakBeforeBraces == FormatStyle::BS_Whitesmiths)
854f7f9f94bSTim Wojtulewicz ++Line->Level;
855f7f9f94bSTim Wojtulewicz
856a98a95ccSFrancois Ferrand size_t PPStartHash = computePPHash();
857a98a95ccSFrancois Ferrand
8587cb0bc8aSowenca const unsigned InitialLevel = Line->Level;
8592a42c759SJakub Budiský nextToken(/*LevelDifference=*/AddLevels);
8609ed2e68cSsstwcw HandleVerilogBlockLabel();
861f7935115SDaniel Jasper
862b5b33fbfSowenca // Bail out if there are too many levels. Otherwise, the stack might overflow.
863b5b33fbfSowenca if (Line->Level > 300)
8645ead1f13Sowenca return nullptr;
865b5b33fbfSowenca
866b001a0baSBirunthan Mohanathas if (MacroBlock && FormatTok->is(tok::l_paren))
867b001a0baSBirunthan Mohanathas parseParens();
868b001a0baSBirunthan Mohanathas
869a98a95ccSFrancois Ferrand size_t NbPreprocessorDirectives =
870a98a95ccSFrancois Ferrand CurrentLines == &Lines ? PreprocessorDirectives.size() : 0;
871f7935115SDaniel Jasper addUnwrappedLine();
872a98a95ccSFrancois Ferrand size_t OpeningLineIndex =
873a98a95ccSFrancois Ferrand CurrentLines->empty()
8749f5608a8SKrasimir Georgiev ? (UnwrappedLine::kInvalidIndex)
875a98a95ccSFrancois Ferrand : (CurrentLines->size() - 1 - NbPreprocessorDirectives);
876f7935115SDaniel Jasper
877f7f9f94bSTim Wojtulewicz // Whitesmiths is weird here. The brace needs to be indented for the namespace
878f7f9f94bSTim Wojtulewicz // block, but the block itself may not be indented depending on the style
879f7f9f94bSTim Wojtulewicz // settings. This allows the format to back up one level in those cases.
880f7f9f94bSTim Wojtulewicz if (UnindentWhitesmithsBraces)
881f7f9f94bSTim Wojtulewicz --Line->Level;
882f7f9f94bSTim Wojtulewicz
8830a3a3c99SManuel Klimek ScopedDeclarationState DeclarationState(*Line, DeclarationScopeStack,
8840a3a3c99SManuel Klimek MustBeDeclaration);
885f7f9f94bSTim Wojtulewicz if (AddLevels > 0u && Style.BreakBeforeBraces != FormatStyle::BS_Whitesmiths)
8862a42c759SJakub Budiský Line->Level += AddLevels;
887533fbae8SOwen Pan
8885ead1f13Sowenca FormatToken *IfLBrace = nullptr;
8899dffab9dSowenca const bool SimpleBlock =
8905ead1f13Sowenca parseLevel(Tok, CanContainBracedList, NextLBracesType, IfKind, &IfLBrace);
891578fdd89SAlexander Kornienko
89203137c65SMarianne Mailhot-Sarrasin if (eof())
8935ead1f13Sowenca return IfLBrace;
89403137c65SMarianne Mailhot-Sarrasin
895b001a0baSBirunthan Mohanathas if (MacroBlock ? !FormatTok->is(TT_MacroBlockEnd)
896b001a0baSBirunthan Mohanathas : !FormatTok->is(tok::r_brace)) {
897516d7971SDaniel Jasper Line->Level = InitialLevel;
898f5acd11dSBruno Ricci FormatTok->setBlockKind(BK_Block);
8995ead1f13Sowenca return IfLBrace;
900533fbae8SOwen Pan }
901533fbae8SOwen Pan
9025bf44aa4Sowenca auto RemoveBraces = [=]() mutable {
9035ead1f13Sowenca if (!SimpleBlock)
9045bf44aa4Sowenca return false;
9051443dbabSowenca assert(Tok->isOneOf(TT_ControlStatementLBrace, TT_ElseLBrace));
906533fbae8SOwen Pan assert(FormatTok->is(tok::r_brace));
9075bf44aa4Sowenca const bool WrappedOpeningBrace = !Tok->Previous;
9085bf44aa4Sowenca if (WrappedOpeningBrace && FollowedByComment)
9095bf44aa4Sowenca return false;
9105ead1f13Sowenca const bool HasRequiredIfBraces = IfLBrace && !IfLBrace->Optional;
9115ead1f13Sowenca if (KeepBraces && !HasRequiredIfBraces)
9125ead1f13Sowenca return false;
9135ead1f13Sowenca if (Tok->isNot(TT_ElseLBrace) || !HasRequiredIfBraces) {
914533fbae8SOwen Pan const FormatToken *Previous = Tokens->getPreviousToken();
915533fbae8SOwen Pan assert(Previous);
9165bf44aa4Sowenca if (Previous->is(tok::r_brace) && !Previous->Optional)
9175bf44aa4Sowenca return false;
9185ead1f13Sowenca }
919b6d8c84fSowenca assert(!CurrentLines->empty());
9207cb0bc8aSowenca auto &LastLine = CurrentLines->back();
9217cb0bc8aSowenca if (LastLine.Level == InitialLevel + 1 && !mightFitOnOneLine(LastLine))
9225bf44aa4Sowenca return false;
9235bf44aa4Sowenca if (Tok->is(TT_ElseLBrace))
9245bf44aa4Sowenca return true;
9255bf44aa4Sowenca if (WrappedOpeningBrace) {
9261443dbabSowenca assert(Index > 0);
9271443dbabSowenca --Index; // The line above the wrapped l_brace.
9285bf44aa4Sowenca Tok = nullptr;
9291443dbabSowenca }
9305bf44aa4Sowenca return mightFitOnOneLine((*CurrentLines)[Index], Tok);
9315bf44aa4Sowenca };
9325bf44aa4Sowenca if (RemoveBraces()) {
933533fbae8SOwen Pan Tok->MatchingParen = FormatTok;
934533fbae8SOwen Pan FormatTok->MatchingParen = Tok;
935533fbae8SOwen Pan }
9360ea8e107SAlexander Kornienko
937a98a95ccSFrancois Ferrand size_t PPEndHash = computePPHash();
938a98a95ccSFrancois Ferrand
9393e051054SKrasimir Georgiev // Munch the closing brace.
9402a42c759SJakub Budiský nextToken(/*LevelDifference=*/-AddLevels);
9419ed2e68cSsstwcw HandleVerilogBlockLabel();
942b001a0baSBirunthan Mohanathas
943b001a0baSBirunthan Mohanathas if (MacroBlock && FormatTok->is(tok::l_paren))
944b001a0baSBirunthan Mohanathas parseParens();
945b001a0baSBirunthan Mohanathas
9469aab0db1SBjörn Schäpers if (FormatTok->is(tok::kw_noexcept)) {
9479aab0db1SBjörn Schäpers // A noexcept in a requires expression.
9489aab0db1SBjörn Schäpers nextToken();
9499aab0db1SBjörn Schäpers }
9509aab0db1SBjörn Schäpers
951840e651dSmydeveloperday if (FormatTok->is(tok::arrow)) {
9529aab0db1SBjörn Schäpers // Following the } or noexcept we can find a trailing return type arrow
953840e651dSmydeveloperday // as part of an implicit conversion constraint.
954840e651dSmydeveloperday nextToken();
955840e651dSmydeveloperday parseStructuralElement();
956840e651dSmydeveloperday }
957840e651dSmydeveloperday
958fee4a971SMarek Kurdej if (MunchSemi && FormatTok->is(tok::semi))
959b212f3baSManuel Klimek nextToken();
960840e651dSmydeveloperday
9613e051054SKrasimir Georgiev Line->Level = InitialLevel;
962a98a95ccSFrancois Ferrand
963a98a95ccSFrancois Ferrand if (PPStartHash == PPEndHash) {
964f77ada0fSKrasimir Georgiev Line->MatchingOpeningBlockLineIndex = OpeningLineIndex;
965e56a829eSFrancois Ferrand if (OpeningLineIndex != UnwrappedLine::kInvalidIndex) {
966e56a829eSFrancois Ferrand // Update the opening line to add the forward reference as well
9670dddcf78SManuel Klimek (*CurrentLines)[OpeningLineIndex].MatchingClosingBlockLineIndex =
968e56a829eSFrancois Ferrand CurrentLines->size() - 1;
969e56a829eSFrancois Ferrand }
970f7935115SDaniel Jasper }
9715ead1f13Sowenca
9725ead1f13Sowenca return IfLBrace;
973a98a95ccSFrancois Ferrand }
974f7935115SDaniel Jasper
isGoogScope(const UnwrappedLine & Line)97502c7bca5SDaniel Jasper static bool isGoogScope(const UnwrappedLine &Line) {
976616de864SDaniel Jasper // FIXME: Closure-library specific stuff should not be hard-coded but be
977616de864SDaniel Jasper // configurable.
9784a39c84cSDaniel Jasper if (Line.Tokens.size() < 4)
9794a39c84cSDaniel Jasper return false;
9804a39c84cSDaniel Jasper auto I = Line.Tokens.begin();
9814a39c84cSDaniel Jasper if (I->Tok->TokenText != "goog")
9824a39c84cSDaniel Jasper return false;
9834a39c84cSDaniel Jasper ++I;
9844a39c84cSDaniel Jasper if (I->Tok->isNot(tok::period))
9854a39c84cSDaniel Jasper return false;
9864a39c84cSDaniel Jasper ++I;
9874a39c84cSDaniel Jasper if (I->Tok->TokenText != "scope")
9884a39c84cSDaniel Jasper return false;
9894a39c84cSDaniel Jasper ++I;
9904a39c84cSDaniel Jasper return I->Tok->is(tok::l_paren);
9914a39c84cSDaniel Jasper }
9924a39c84cSDaniel Jasper
isIIFE(const UnwrappedLine & Line,const AdditionalKeywords & Keywords)993101ec894SMartin Probst static bool isIIFE(const UnwrappedLine &Line,
994101ec894SMartin Probst const AdditionalKeywords &Keywords) {
995101ec894SMartin Probst // Look for the start of an immediately invoked anonymous function.
996101ec894SMartin Probst // https://en.wikipedia.org/wiki/Immediately-invoked_function_expression
997101ec894SMartin Probst // This is commonly done in JavaScript to create a new, anonymous scope.
998101ec894SMartin Probst // Example: (function() { ... })()
999101ec894SMartin Probst if (Line.Tokens.size() < 3)
1000101ec894SMartin Probst return false;
1001101ec894SMartin Probst auto I = Line.Tokens.begin();
1002101ec894SMartin Probst if (I->Tok->isNot(tok::l_paren))
1003101ec894SMartin Probst return false;
1004101ec894SMartin Probst ++I;
1005101ec894SMartin Probst if (I->Tok->isNot(Keywords.kw_function))
1006101ec894SMartin Probst return false;
1007101ec894SMartin Probst ++I;
1008101ec894SMartin Probst return I->Tok->is(tok::l_paren);
1009101ec894SMartin Probst }
1010101ec894SMartin Probst
ShouldBreakBeforeBrace(const FormatStyle & Style,const FormatToken & InitialToken)1011a043cedfSRoman Kashitsyn static bool ShouldBreakBeforeBrace(const FormatStyle &Style,
1012a043cedfSRoman Kashitsyn const FormatToken &InitialToken) {
1013c59c2b6bSMarek Kurdej tok::TokenKind Kind = InitialToken.Tok.getKind();
1014c59c2b6bSMarek Kurdej if (InitialToken.is(TT_NamespaceMacro))
1015c59c2b6bSMarek Kurdej Kind = tok::kw_namespace;
1016c59c2b6bSMarek Kurdej
1017c59c2b6bSMarek Kurdej switch (Kind) {
1018c59c2b6bSMarek Kurdej case tok::kw_namespace:
1019c1bc38edSDaniel Jasper return Style.BraceWrapping.AfterNamespace;
1020c59c2b6bSMarek Kurdej case tok::kw_class:
1021c1bc38edSDaniel Jasper return Style.BraceWrapping.AfterClass;
1022c59c2b6bSMarek Kurdej case tok::kw_union:
1023c1bc38edSDaniel Jasper return Style.BraceWrapping.AfterUnion;
1024c59c2b6bSMarek Kurdej case tok::kw_struct:
1025c1bc38edSDaniel Jasper return Style.BraceWrapping.AfterStruct;
1026c59c2b6bSMarek Kurdej case tok::kw_enum:
10277972b2e4SMichael Zimmermann return Style.BraceWrapping.AfterEnum;
1028c59c2b6bSMarek Kurdej default:
1029a043cedfSRoman Kashitsyn return false;
1030a043cedfSRoman Kashitsyn }
1031c59c2b6bSMarek Kurdej }
1032a043cedfSRoman Kashitsyn
parseChildBlock(bool CanContainBracedList,clang::format::TokenType NextLBracesType)10339aab0db1SBjörn Schäpers void UnwrappedLineParser::parseChildBlock(
10349aab0db1SBjörn Schäpers bool CanContainBracedList, clang::format::TokenType NextLBracesType) {
10359dffab9dSowenca assert(FormatTok->is(tok::l_brace));
1036f5acd11dSBruno Ricci FormatTok->setBlockKind(BK_Block);
10379dffab9dSowenca const FormatToken *OpeningBrace = FormatTok;
1038516e054cSManuel Klimek nextToken();
1039516e054cSManuel Klimek {
1040142e79b8Smydeveloperday bool SkipIndent = (Style.isJavaScript() &&
1041101ec894SMartin Probst (isGoogScope(*Line) || isIIFE(*Line, Keywords)));
1042516e054cSManuel Klimek ScopedLineState LineState(*this);
1043516e054cSManuel Klimek ScopedDeclarationState DeclarationState(*Line, DeclarationScopeStack,
1044516e054cSManuel Klimek /*MustBeDeclaration=*/false);
1045101ec894SMartin Probst Line->Level += SkipIndent ? 0 : 1;
1046ec90bc0eSowenca parseLevel(OpeningBrace, CanContainBracedList, NextLBracesType);
104702c7bca5SDaniel Jasper flushComments(isOnNewLine(*FormatTok));
1048101ec894SMartin Probst Line->Level -= SkipIndent ? 0 : 1;
1049516e054cSManuel Klimek }
1050516e054cSManuel Klimek nextToken();
1051516e054cSManuel Klimek }
1052516e054cSManuel Klimek
parsePPDirective()10539af03864Smydeveloperday void UnwrappedLineParser::parsePPDirective() {
1054fee4a971SMarek Kurdej assert(FormatTok->is(tok::hash) && "'#' expected");
105520e0af6bSManuel Klimek ScopedMacroState MacroState(*Line, Tokens, FormatTok);
1056701a0d7eSPaul Hoad
1057f7935115SDaniel Jasper nextToken();
1058a71e5d81SManuel Klimek
10592145bc02SCraig Topper if (!FormatTok->Tok.getIdentifierInfo()) {
1060591b5802SManuel Klimek parsePPUnknown();
1061f7935115SDaniel Jasper return;
1062f7935115SDaniel Jasper }
1063a71e5d81SManuel Klimek
106415dfe7acSManuel Klimek switch (FormatTok->Tok.getIdentifierInfo()->getPPKeywordID()) {
10651abf789cSManuel Klimek case tok::pp_define:
10661abf789cSManuel Klimek parsePPDefine();
1067f2e02123SAlexander Kornienko return;
1068f2e02123SAlexander Kornienko case tok::pp_if:
106971814b44SManuel Klimek parsePPIf(/*IfDef=*/false);
1070f2e02123SAlexander Kornienko break;
1071f2e02123SAlexander Kornienko case tok::pp_ifdef:
1072f2e02123SAlexander Kornienko case tok::pp_ifndef:
107371814b44SManuel Klimek parsePPIf(/*IfDef=*/true);
1074f2e02123SAlexander Kornienko break;
1075f2e02123SAlexander Kornienko case tok::pp_else:
1076f2e02123SAlexander Kornienko parsePPElse();
1077f2e02123SAlexander Kornienko break;
10788edd3464SAaron Ballman case tok::pp_elifdef:
10798edd3464SAaron Ballman case tok::pp_elifndef:
1080f2e02123SAlexander Kornienko case tok::pp_elif:
1081f2e02123SAlexander Kornienko parsePPElIf();
1082f2e02123SAlexander Kornienko break;
1083f2e02123SAlexander Kornienko case tok::pp_endif:
1084f2e02123SAlexander Kornienko parsePPEndIf();
10851abf789cSManuel Klimek break;
10861abf789cSManuel Klimek default:
10871abf789cSManuel Klimek parsePPUnknown();
1088a71e5d81SManuel Klimek break;
1089f7935115SDaniel Jasper }
10901abf789cSManuel Klimek }
10911abf789cSManuel Klimek
conditionalCompilationCondition(bool Unreachable)109268b03049SManuel Klimek void UnwrappedLineParser::conditionalCompilationCondition(bool Unreachable) {
1093a98a95ccSFrancois Ferrand size_t Line = CurrentLines->size();
1094a98a95ccSFrancois Ferrand if (CurrentLines == &PreprocessorDirectives)
1095a98a95ccSFrancois Ferrand Line += Lines.size();
1096a98a95ccSFrancois Ferrand
1097a98a95ccSFrancois Ferrand if (Unreachable ||
1098bebf7bdfSowenca (!PPStack.empty() && PPStack.back().Kind == PP_Unreachable)) {
1099a98a95ccSFrancois Ferrand PPStack.push_back({PP_Unreachable, Line});
1100bebf7bdfSowenca } else {
1101a98a95ccSFrancois Ferrand PPStack.push_back({PP_Conditional, Line});
1102f2e02123SAlexander Kornienko }
1103bebf7bdfSowenca }
1104f2e02123SAlexander Kornienko
conditionalCompilationStart(bool Unreachable)110568b03049SManuel Klimek void UnwrappedLineParser::conditionalCompilationStart(bool Unreachable) {
110671814b44SManuel Klimek ++PPBranchLevel;
110771814b44SManuel Klimek assert(PPBranchLevel >= 0 && PPBranchLevel <= (int)PPLevelBranchIndex.size());
110871814b44SManuel Klimek if (PPBranchLevel == (int)PPLevelBranchIndex.size()) {
110971814b44SManuel Klimek PPLevelBranchIndex.push_back(0);
111071814b44SManuel Klimek PPLevelBranchCount.push_back(0);
111171814b44SManuel Klimek }
111271814b44SManuel Klimek PPChainBranchIndex.push(0);
111368b03049SManuel Klimek bool Skip = PPLevelBranchIndex[PPBranchLevel] > 0;
111468b03049SManuel Klimek conditionalCompilationCondition(Unreachable || Skip);
1115f2e02123SAlexander Kornienko }
1116f2e02123SAlexander Kornienko
conditionalCompilationAlternative()111768b03049SManuel Klimek void UnwrappedLineParser::conditionalCompilationAlternative() {
1118f2e02123SAlexander Kornienko if (!PPStack.empty())
1119f2e02123SAlexander Kornienko PPStack.pop_back();
112071814b44SManuel Klimek assert(PPBranchLevel < (int)PPLevelBranchIndex.size());
112171814b44SManuel Klimek if (!PPChainBranchIndex.empty())
112271814b44SManuel Klimek ++PPChainBranchIndex.top();
112368b03049SManuel Klimek conditionalCompilationCondition(
112468b03049SManuel Klimek PPBranchLevel >= 0 && !PPChainBranchIndex.empty() &&
112568b03049SManuel Klimek PPLevelBranchIndex[PPBranchLevel] != PPChainBranchIndex.top());
1126f2e02123SAlexander Kornienko }
1127f2e02123SAlexander Kornienko
conditionalCompilationEnd()112868b03049SManuel Klimek void UnwrappedLineParser::conditionalCompilationEnd() {
112971814b44SManuel Klimek assert(PPBranchLevel < (int)PPLevelBranchIndex.size());
113071814b44SManuel Klimek if (PPBranchLevel >= 0 && !PPChainBranchIndex.empty()) {
1131d079995dSMarek Kurdej if (PPChainBranchIndex.top() + 1 > PPLevelBranchCount[PPBranchLevel])
113271814b44SManuel Klimek PPLevelBranchCount[PPBranchLevel] = PPChainBranchIndex.top() + 1;
113371814b44SManuel Klimek }
113414bd9174SManuel Klimek // Guard against #endif's without #if.
1135ad47c907SKrasimir Georgiev if (PPBranchLevel > -1)
113671814b44SManuel Klimek --PPBranchLevel;
113771814b44SManuel Klimek if (!PPChainBranchIndex.empty())
113871814b44SManuel Klimek PPChainBranchIndex.pop();
1139f2e02123SAlexander Kornienko if (!PPStack.empty())
1140f2e02123SAlexander Kornienko PPStack.pop_back();
114168b03049SManuel Klimek }
114268b03049SManuel Klimek
parsePPIf(bool IfDef)114368b03049SManuel Klimek void UnwrappedLineParser::parsePPIf(bool IfDef) {
114462703eb8SDaniel Jasper bool IfNDef = FormatTok->is(tok::pp_ifndef);
114568b03049SManuel Klimek nextToken();
1146eab6cd47SDaniel Jasper bool Unreachable = false;
1147eab6cd47SDaniel Jasper if (!IfDef && (FormatTok->is(tok::kw_false) || FormatTok->TokenText == "0"))
1148eab6cd47SDaniel Jasper Unreachable = true;
114962703eb8SDaniel Jasper if (IfDef && !IfNDef && FormatTok->TokenText == "SWIG")
1150eab6cd47SDaniel Jasper Unreachable = true;
1151eab6cd47SDaniel Jasper conditionalCompilationStart(Unreachable);
1152ad47c907SKrasimir Georgiev FormatToken *IfCondition = FormatTok;
1153ad47c907SKrasimir Georgiev // If there's a #ifndef on the first line, and the only lines before it are
1154ad47c907SKrasimir Georgiev // comments, it could be an include guard.
1155ad47c907SKrasimir Georgiev bool MaybeIncludeGuard = IfNDef;
1156bebf7bdfSowenca if (IncludeGuard == IG_Inited && MaybeIncludeGuard) {
1157ad47c907SKrasimir Georgiev for (auto &Line : Lines) {
1158ad47c907SKrasimir Georgiev if (!Line.Tokens.front().Tok->is(tok::comment)) {
1159ad47c907SKrasimir Georgiev MaybeIncludeGuard = false;
11601c3afaf5SMark Zeren IncludeGuard = IG_Rejected;
1161ad47c907SKrasimir Georgiev break;
1162ad47c907SKrasimir Georgiev }
1163ad47c907SKrasimir Georgiev }
1164bebf7bdfSowenca }
1165ad47c907SKrasimir Georgiev --PPBranchLevel;
116668b03049SManuel Klimek parsePPUnknown();
1167ad47c907SKrasimir Georgiev ++PPBranchLevel;
11681c3afaf5SMark Zeren if (IncludeGuard == IG_Inited && MaybeIncludeGuard) {
11691c3afaf5SMark Zeren IncludeGuard = IG_IfNdefed;
11701c3afaf5SMark Zeren IncludeGuardToken = IfCondition;
11711c3afaf5SMark Zeren }
117268b03049SManuel Klimek }
117368b03049SManuel Klimek
parsePPElse()117468b03049SManuel Klimek void UnwrappedLineParser::parsePPElse() {
1175ad47c907SKrasimir Georgiev // If a potential include guard has an #else, it's not an include guard.
11761c3afaf5SMark Zeren if (IncludeGuard == IG_Defined && PPBranchLevel == 0)
11771c3afaf5SMark Zeren IncludeGuard = IG_Rejected;
117868b03049SManuel Klimek conditionalCompilationAlternative();
1179ad47c907SKrasimir Georgiev if (PPBranchLevel > -1)
1180ad47c907SKrasimir Georgiev --PPBranchLevel;
118168b03049SManuel Klimek parsePPUnknown();
1182ad47c907SKrasimir Georgiev ++PPBranchLevel;
118368b03049SManuel Klimek }
118468b03049SManuel Klimek
parsePPElIf()118568b03049SManuel Klimek void UnwrappedLineParser::parsePPElIf() { parsePPElse(); }
118668b03049SManuel Klimek
parsePPEndIf()118768b03049SManuel Klimek void UnwrappedLineParser::parsePPEndIf() {
118868b03049SManuel Klimek conditionalCompilationEnd();
1189f2e02123SAlexander Kornienko parsePPUnknown();
1190ad47c907SKrasimir Georgiev // If the #endif of a potential include guard is the last thing in the file,
11911c3afaf5SMark Zeren // then we found an include guard.
11921b5a43acSManuel Klimek if (IncludeGuard == IG_Defined && PPBranchLevel == -1 && Tokens->isEOF() &&
1193bebf7bdfSowenca Style.IndentPPDirectives != FormatStyle::PPDIS_None) {
11941c3afaf5SMark Zeren IncludeGuard = IG_Found;
1195ad47c907SKrasimir Georgiev }
1196bebf7bdfSowenca }
1197f2e02123SAlexander Kornienko
parsePPDefine()11981abf789cSManuel Klimek void UnwrappedLineParser::parsePPDefine() {
11991abf789cSManuel Klimek nextToken();
12001abf789cSManuel Klimek
1201fb73b79aSOwen Pan if (!FormatTok->Tok.getIdentifierInfo()) {
12021c3afaf5SMark Zeren IncludeGuard = IG_Rejected;
12031c3afaf5SMark Zeren IncludeGuardToken = nullptr;
12041abf789cSManuel Klimek parsePPUnknown();
12051abf789cSManuel Klimek return;
12061abf789cSManuel Klimek }
12071c3afaf5SMark Zeren
12081c3afaf5SMark Zeren if (IncludeGuard == IG_IfNdefed &&
12091c3afaf5SMark Zeren IncludeGuardToken->TokenText == FormatTok->TokenText) {
12101c3afaf5SMark Zeren IncludeGuard = IG_Defined;
12111c3afaf5SMark Zeren IncludeGuardToken = nullptr;
1212ad47c907SKrasimir Georgiev for (auto &Line : Lines) {
1213ad47c907SKrasimir Georgiev if (!Line.Tokens.front().Tok->isOneOf(tok::comment, tok::hash)) {
12141c3afaf5SMark Zeren IncludeGuard = IG_Rejected;
1215ad47c907SKrasimir Georgiev break;
1216ad47c907SKrasimir Georgiev }
1217ad47c907SKrasimir Georgiev }
1218ad47c907SKrasimir Georgiev }
12191c3afaf5SMark Zeren
1220529aa4b0SMarek Kurdej // In the context of a define, even keywords should be treated as normal
1221529aa4b0SMarek Kurdej // identifiers. Setting the kind to identifier is not enough, because we need
1222529aa4b0SMarek Kurdej // to treat additional keywords like __except as well, which are already
1223c9592ae4SKrasimir Georgiev // identifiers. Setting the identifier info to null interferes with include
1224c9592ae4SKrasimir Georgiev // guard processing above, and changes preprocessing nesting.
1225529aa4b0SMarek Kurdej FormatTok->Tok.setKind(tok::identifier);
1226c9592ae4SKrasimir Georgiev FormatTok->Tok.setIdentifierInfo(Keywords.kw_internal_ident_after_define);
12271abf789cSManuel Klimek nextToken();
122815dfe7acSManuel Klimek if (FormatTok->Tok.getKind() == tok::l_paren &&
1229bebf7bdfSowenca !FormatTok->hasWhitespaceBefore()) {
12301abf789cSManuel Klimek parseParens();
1231bebf7bdfSowenca }
1232701a0d7eSPaul Hoad if (Style.IndentPPDirectives != FormatStyle::PPDIS_None)
1233ad47c907SKrasimir Georgiev Line->Level += PPBranchLevel + 1;
12341abf789cSManuel Klimek addUnwrappedLine();
1235ad47c907SKrasimir Georgiev ++Line->Level;
12361b896296SManuel Klimek
12371b896296SManuel Klimek // Errors during a preprocessor directive can only affect the layout of the
12381b896296SManuel Klimek // preprocessor directive, and thus we ignore them. An alternative approach
12391b896296SManuel Klimek // would be to use the same approach we use on the file level (no
12401b896296SManuel Klimek // re-indentation if there was a structural error) within the macro
12411b896296SManuel Klimek // definition.
12421abf789cSManuel Klimek parseFile();
12431abf789cSManuel Klimek }
12441abf789cSManuel Klimek
parsePPUnknown()12451abf789cSManuel Klimek void UnwrappedLineParser::parsePPUnknown() {
12461abf789cSManuel Klimek do {
1247a71e5d81SManuel Klimek nextToken();
1248a71e5d81SManuel Klimek } while (!eof());
1249701a0d7eSPaul Hoad if (Style.IndentPPDirectives != FormatStyle::PPDIS_None)
1250ad47c907SKrasimir Georgiev Line->Level += PPBranchLevel + 1;
1251a71e5d81SManuel Klimek addUnwrappedLine();
1252f7935115SDaniel Jasper }
1253f7935115SDaniel Jasper
12540861889bSEric Christopher // Here we exclude certain tokens that are not usually the first token in an
1255a04e5e21SAlexander Kornienko // unwrapped line. This is used in attempt to distinguish macro calls without
1256a04e5e21SAlexander Kornienko // trailing semicolons from other constructs split to several lines.
tokenCanStartNewLine(const FormatToken & Tok)1257575c59cfSmydeveloperday static bool tokenCanStartNewLine(const FormatToken &Tok) {
1258a04e5e21SAlexander Kornienko // Semicolon can be a null-statement, l_square can be a start of a macro or
1259a04e5e21SAlexander Kornienko // a C++11 attribute, but this doesn't seem to be common.
1260a04e5e21SAlexander Kornienko return Tok.isNot(tok::semi) && Tok.isNot(tok::l_brace) &&
1261575c59cfSmydeveloperday Tok.isNot(TT_AttributeSquare) &&
1262a04e5e21SAlexander Kornienko // Tokens that can only be used as binary operators and a part of
1263a04e5e21SAlexander Kornienko // overloaded operator names.
1264a04e5e21SAlexander Kornienko Tok.isNot(tok::period) && Tok.isNot(tok::periodstar) &&
1265a04e5e21SAlexander Kornienko Tok.isNot(tok::arrow) && Tok.isNot(tok::arrowstar) &&
1266a04e5e21SAlexander Kornienko Tok.isNot(tok::less) && Tok.isNot(tok::greater) &&
1267a04e5e21SAlexander Kornienko Tok.isNot(tok::slash) && Tok.isNot(tok::percent) &&
1268a04e5e21SAlexander Kornienko Tok.isNot(tok::lessless) && Tok.isNot(tok::greatergreater) &&
1269a04e5e21SAlexander Kornienko Tok.isNot(tok::equal) && Tok.isNot(tok::plusequal) &&
1270a04e5e21SAlexander Kornienko Tok.isNot(tok::minusequal) && Tok.isNot(tok::starequal) &&
1271a04e5e21SAlexander Kornienko Tok.isNot(tok::slashequal) && Tok.isNot(tok::percentequal) &&
1272a04e5e21SAlexander Kornienko Tok.isNot(tok::ampequal) && Tok.isNot(tok::pipeequal) &&
1273a04e5e21SAlexander Kornienko Tok.isNot(tok::caretequal) && Tok.isNot(tok::greatergreaterequal) &&
1274a04e5e21SAlexander Kornienko Tok.isNot(tok::lesslessequal) &&
1275a04e5e21SAlexander Kornienko // Colon is used in labels, base class lists, initializer lists,
1276a04e5e21SAlexander Kornienko // range-based for loops, ternary operator, but should never be the
1277a04e5e21SAlexander Kornienko // first token in an unwrapped line.
12785ebb2f36SDaniel Jasper Tok.isNot(tok::colon) &&
12795ebb2f36SDaniel Jasper // 'noexcept' is a trailing annotation.
12805ebb2f36SDaniel Jasper Tok.isNot(tok::kw_noexcept);
1281a04e5e21SAlexander Kornienko }
1282a04e5e21SAlexander Kornienko
mustBeJSIdent(const AdditionalKeywords & Keywords,const FormatToken * FormatTok)1283533965c1SMartin Probst static bool mustBeJSIdent(const AdditionalKeywords &Keywords,
12841dcbbcfcSDaniel Jasper const FormatToken *FormatTok) {
12851dcbbcfcSDaniel Jasper // FIXME: This returns true for C/C++ keywords like 'struct'.
12861dcbbcfcSDaniel Jasper return FormatTok->is(tok::identifier) &&
12871dcbbcfcSDaniel Jasper (FormatTok->Tok.getIdentifierInfo() == nullptr ||
12883dbbefaeSMartin Probst !FormatTok->isOneOf(
12893dbbefaeSMartin Probst Keywords.kw_in, Keywords.kw_of, Keywords.kw_as, Keywords.kw_async,
12903dbbefaeSMartin Probst Keywords.kw_await, Keywords.kw_yield, Keywords.kw_finally,
12913dbbefaeSMartin Probst Keywords.kw_function, Keywords.kw_import, Keywords.kw_is,
12923dbbefaeSMartin Probst Keywords.kw_let, Keywords.kw_var, tok::kw_const,
12933dbbefaeSMartin Probst Keywords.kw_abstract, Keywords.kw_extends, Keywords.kw_implements,
1294e708808fSJan Kuehle Keywords.kw_instanceof, Keywords.kw_interface,
1295e708808fSJan Kuehle Keywords.kw_override, Keywords.kw_throws, Keywords.kw_from));
12961dcbbcfcSDaniel Jasper }
12971dcbbcfcSDaniel Jasper
mustBeJSIdentOrValue(const AdditionalKeywords & Keywords,const FormatToken * FormatTok)1298533965c1SMartin Probst static bool mustBeJSIdentOrValue(const AdditionalKeywords &Keywords,
1299533965c1SMartin Probst const FormatToken *FormatTok) {
1300b9316ff8SMartin Probst return FormatTok->Tok.isLiteral() ||
1301b9316ff8SMartin Probst FormatTok->isOneOf(tok::kw_true, tok::kw_false) ||
1302b9316ff8SMartin Probst mustBeJSIdent(Keywords, FormatTok);
1303533965c1SMartin Probst }
1304533965c1SMartin Probst
13051dcbbcfcSDaniel Jasper // isJSDeclOrStmt returns true if |FormatTok| starts a declaration or statement
13061dcbbcfcSDaniel Jasper // when encountered after a value (see mustBeJSIdentOrValue).
isJSDeclOrStmt(const AdditionalKeywords & Keywords,const FormatToken * FormatTok)13071dcbbcfcSDaniel Jasper static bool isJSDeclOrStmt(const AdditionalKeywords &Keywords,
13081dcbbcfcSDaniel Jasper const FormatToken *FormatTok) {
13091dcbbcfcSDaniel Jasper return FormatTok->isOneOf(
13105f8445b3SMartin Probst tok::kw_return, Keywords.kw_yield,
13111dcbbcfcSDaniel Jasper // conditionals
13121dcbbcfcSDaniel Jasper tok::kw_if, tok::kw_else,
13131dcbbcfcSDaniel Jasper // loops
13141dcbbcfcSDaniel Jasper tok::kw_for, tok::kw_while, tok::kw_do, tok::kw_continue, tok::kw_break,
13151dcbbcfcSDaniel Jasper // switch/case
13161dcbbcfcSDaniel Jasper tok::kw_switch, tok::kw_case,
13171dcbbcfcSDaniel Jasper // exceptions
13181dcbbcfcSDaniel Jasper tok::kw_throw, tok::kw_try, tok::kw_catch, Keywords.kw_finally,
13191dcbbcfcSDaniel Jasper // declaration
13201dcbbcfcSDaniel Jasper tok::kw_const, tok::kw_class, Keywords.kw_var, Keywords.kw_let,
13215f8445b3SMartin Probst Keywords.kw_async, Keywords.kw_function,
13225f8445b3SMartin Probst // import/export
13235f8445b3SMartin Probst Keywords.kw_import, tok::kw_export);
13241dcbbcfcSDaniel Jasper }
13251dcbbcfcSDaniel Jasper
1326f6928cf4SOwen // Checks whether a token is a type in K&R C (aka C78).
isC78Type(const FormatToken & Tok)1327f6928cf4SOwen static bool isC78Type(const FormatToken &Tok) {
1328f6928cf4SOwen return Tok.isOneOf(tok::kw_char, tok::kw_short, tok::kw_int, tok::kw_long,
1329f6928cf4SOwen tok::kw_unsigned, tok::kw_float, tok::kw_double,
1330f6928cf4SOwen tok::identifier);
1331f6928cf4SOwen }
1332f6928cf4SOwen
13339da70ab3Sowenca // This function checks whether a token starts the first parameter declaration
13349da70ab3Sowenca // in a K&R C (aka C78) function definition, e.g.:
13359da70ab3Sowenca // int f(a, b)
13369da70ab3Sowenca // short a, b;
13379da70ab3Sowenca // {
13389da70ab3Sowenca // return a + b;
13399da70ab3Sowenca // }
isC78ParameterDecl(const FormatToken * Tok,const FormatToken * Next,const FormatToken * FuncName)1340643f2be7Sowenca static bool isC78ParameterDecl(const FormatToken *Tok, const FormatToken *Next,
1341643f2be7Sowenca const FormatToken *FuncName) {
1342643f2be7Sowenca assert(Tok);
1343643f2be7Sowenca assert(Next);
1344643f2be7Sowenca assert(FuncName);
1345643f2be7Sowenca
1346643f2be7Sowenca if (FuncName->isNot(tok::identifier))
1347643f2be7Sowenca return false;
1348643f2be7Sowenca
1349643f2be7Sowenca const FormatToken *Prev = FuncName->Previous;
1350643f2be7Sowenca if (!Prev || (Prev->isNot(tok::star) && !isC78Type(*Prev)))
13519da70ab3Sowenca return false;
13529da70ab3Sowenca
1353f6928cf4SOwen if (!isC78Type(*Tok) &&
1354bebf7bdfSowenca !Tok->isOneOf(tok::kw_register, tok::kw_struct, tok::kw_union)) {
13559da70ab3Sowenca return false;
1356bebf7bdfSowenca }
13579da70ab3Sowenca
1358643f2be7Sowenca if (Next->isNot(tok::star) && !Next->Tok.getIdentifierInfo())
1359643f2be7Sowenca return false;
1360643f2be7Sowenca
13619da70ab3Sowenca Tok = Tok->Previous;
13629da70ab3Sowenca if (!Tok || Tok->isNot(tok::r_paren))
13639da70ab3Sowenca return false;
13649da70ab3Sowenca
13659da70ab3Sowenca Tok = Tok->Previous;
13669da70ab3Sowenca if (!Tok || Tok->isNot(tok::identifier))
13679da70ab3Sowenca return false;
13689da70ab3Sowenca
13699da70ab3Sowenca return Tok->Previous && Tok->Previous->isOneOf(tok::l_paren, tok::comma);
13709da70ab3Sowenca }
13719da70ab3Sowenca
parseModuleImport()1372c2fe2b5aSmydeveloperday void UnwrappedLineParser::parseModuleImport() {
1373c2fe2b5aSmydeveloperday nextToken();
1374c2fe2b5aSmydeveloperday while (!eof()) {
1375c2fe2b5aSmydeveloperday if (FormatTok->is(tok::colon)) {
13761e7cc72aSBjörn Schäpers FormatTok->setFinalizedType(TT_ModulePartitionColon);
1377c2fe2b5aSmydeveloperday }
1378c2fe2b5aSmydeveloperday // Handle import <foo/bar.h> as we would an include statement.
1379c2fe2b5aSmydeveloperday else if (FormatTok->is(tok::less)) {
1380c2fe2b5aSmydeveloperday nextToken();
1381c2fe2b5aSmydeveloperday while (!FormatTok->isOneOf(tok::semi, tok::greater, tok::eof)) {
1382c2fe2b5aSmydeveloperday // Mark tokens up to the trailing line comments as implicit string
1383c2fe2b5aSmydeveloperday // literals.
1384c2fe2b5aSmydeveloperday if (FormatTok->isNot(tok::comment) &&
1385bebf7bdfSowenca !FormatTok->TokenText.startswith("//")) {
13861e7cc72aSBjörn Schäpers FormatTok->setFinalizedType(TT_ImplicitStringLiteral);
1387bebf7bdfSowenca }
1388c2fe2b5aSmydeveloperday nextToken();
1389c2fe2b5aSmydeveloperday }
1390c2fe2b5aSmydeveloperday }
1391c2fe2b5aSmydeveloperday if (FormatTok->is(tok::semi)) {
1392c2fe2b5aSmydeveloperday nextToken();
1393c2fe2b5aSmydeveloperday break;
1394c2fe2b5aSmydeveloperday }
1395c2fe2b5aSmydeveloperday nextToken();
1396c2fe2b5aSmydeveloperday }
1397c2fe2b5aSmydeveloperday
1398c2fe2b5aSmydeveloperday addUnwrappedLine();
1399c2fe2b5aSmydeveloperday }
1400c2fe2b5aSmydeveloperday
14011dcbbcfcSDaniel Jasper // readTokenWithJavaScriptASI reads the next token and terminates the current
14021dcbbcfcSDaniel Jasper // line if JavaScript Automatic Semicolon Insertion must
14031dcbbcfcSDaniel Jasper // happen between the current token and the next token.
14041dcbbcfcSDaniel Jasper //
14051dcbbcfcSDaniel Jasper // This method is conservative - it cannot cover all edge cases of JavaScript,
14061dcbbcfcSDaniel Jasper // but only aims to correctly handle certain well known cases. It *must not*
14071dcbbcfcSDaniel Jasper // return true in speculative cases.
readTokenWithJavaScriptASI()14081dcbbcfcSDaniel Jasper void UnwrappedLineParser::readTokenWithJavaScriptASI() {
14091dcbbcfcSDaniel Jasper FormatToken *Previous = FormatTok;
14101dcbbcfcSDaniel Jasper readToken();
14111dcbbcfcSDaniel Jasper FormatToken *Next = FormatTok;
14121dcbbcfcSDaniel Jasper
14131dcbbcfcSDaniel Jasper bool IsOnSameLine =
14141dcbbcfcSDaniel Jasper CommentsBeforeNextToken.empty()
14151dcbbcfcSDaniel Jasper ? Next->NewlinesBefore == 0
14161dcbbcfcSDaniel Jasper : CommentsBeforeNextToken.front()->NewlinesBefore == 0;
14171dcbbcfcSDaniel Jasper if (IsOnSameLine)
14181dcbbcfcSDaniel Jasper return;
14191dcbbcfcSDaniel Jasper
14201dcbbcfcSDaniel Jasper bool PreviousMustBeValue = mustBeJSIdentOrValue(Keywords, Previous);
1421717f6dcdSMartin Probst bool PreviousStartsTemplateExpr =
1422717f6dcdSMartin Probst Previous->is(TT_TemplateString) && Previous->TokenText.endswith("${");
14237e0f25b2SMartin Probst if (PreviousMustBeValue || Previous->is(tok::r_paren)) {
14247e0f25b2SMartin Probst // If the line contains an '@' sign, the previous token might be an
14257e0f25b2SMartin Probst // annotation, which can precede another identifier/value.
14264bd46501SKazu Hirata bool HasAt = llvm::any_of(Line->Tokens, [](UnwrappedLineNode &LineNode) {
14277e0f25b2SMartin Probst return LineNode.Tok->is(tok::at);
14284bd46501SKazu Hirata });
14297e0f25b2SMartin Probst if (HasAt)
1430bbffeac5SMartin Probst return;
1431bbffeac5SMartin Probst }
14321dcbbcfcSDaniel Jasper if (Next->is(tok::exclaim) && PreviousMustBeValue)
1433d40bca43SMartin Probst return addUnwrappedLine();
14341dcbbcfcSDaniel Jasper bool NextMustBeValue = mustBeJSIdentOrValue(Keywords, Next);
1435717f6dcdSMartin Probst bool NextEndsTemplateExpr =
1436717f6dcdSMartin Probst Next->is(TT_TemplateString) && Next->TokenText.startswith("}");
1437717f6dcdSMartin Probst if (NextMustBeValue && !NextEndsTemplateExpr && !PreviousStartsTemplateExpr &&
1438717f6dcdSMartin Probst (PreviousMustBeValue ||
1439717f6dcdSMartin Probst Previous->isOneOf(tok::r_square, tok::r_paren, tok::plusplus,
1440bebf7bdfSowenca tok::minusminus))) {
1441d40bca43SMartin Probst return addUnwrappedLine();
1442bebf7bdfSowenca }
14430a19d433SMartin Probst if ((PreviousMustBeValue || Previous->is(tok::r_paren)) &&
1444bebf7bdfSowenca isJSDeclOrStmt(Keywords, Next)) {
1445d40bca43SMartin Probst return addUnwrappedLine();
14461dcbbcfcSDaniel Jasper }
1447bebf7bdfSowenca }
14481dcbbcfcSDaniel Jasper
parseStructuralElement(bool IsTopLevel,TokenType NextLBracesType,IfStmtKind * IfKind,FormatToken ** IfLeftBrace,bool * HasDoWhile,bool * HasLabel)14495ead1f13Sowenca void UnwrappedLineParser::parseStructuralElement(
14505ead1f13Sowenca bool IsTopLevel, TokenType NextLBracesType, IfStmtKind *IfKind,
14515ead1f13Sowenca FormatToken **IfLeftBrace, bool *HasDoWhile, bool *HasLabel) {
1452498f558fSDaniel Jasper if (Style.Language == FormatStyle::LK_TableGen &&
1453498f558fSDaniel Jasper FormatTok->is(tok::pp_include)) {
1454498f558fSDaniel Jasper nextToken();
1455498f558fSDaniel Jasper if (FormatTok->is(tok::string_literal))
1456498f558fSDaniel Jasper nextToken();
1457498f558fSDaniel Jasper addUnwrappedLine();
1458498f558fSDaniel Jasper return;
1459498f558fSDaniel Jasper }
146015dfe7acSManuel Klimek switch (FormatTok->Tok.getKind()) {
14618f463654SDaniel Jasper case tok::kw_asm:
14628f463654SDaniel Jasper nextToken();
14638f463654SDaniel Jasper if (FormatTok->is(tok::l_brace)) {
14641e7cc72aSBjörn Schäpers FormatTok->setFinalizedType(TT_InlineASMBrace);
14652337f280SDaniel Jasper nextToken();
14664429f149SDaniel Jasper while (FormatTok && FormatTok->isNot(tok::eof)) {
14678f463654SDaniel Jasper if (FormatTok->is(tok::r_brace)) {
14681e7cc72aSBjörn Schäpers FormatTok->setFinalizedType(TT_InlineASMBrace);
14698f463654SDaniel Jasper nextToken();
1470790d4f97SDaniel Jasper addUnwrappedLine();
14718f463654SDaniel Jasper break;
14728f463654SDaniel Jasper }
14732337f280SDaniel Jasper FormatTok->Finalized = true;
14748f463654SDaniel Jasper nextToken();
14758f463654SDaniel Jasper }
14768f463654SDaniel Jasper }
14778f463654SDaniel Jasper break;
1478578fdd89SAlexander Kornienko case tok::kw_namespace:
1479578fdd89SAlexander Kornienko parseNamespace();
1480578fdd89SAlexander Kornienko return;
1481b7076a23SAlexander Kornienko case tok::kw_public:
1482b7076a23SAlexander Kornienko case tok::kw_protected:
1483b7076a23SAlexander Kornienko case tok::kw_private:
1484142e79b8Smydeveloperday if (Style.Language == FormatStyle::LK_Java || Style.isJavaScript() ||
1485bebf7bdfSowenca Style.isCSharp()) {
1486c58c70e2SDaniel Jasper nextToken();
1487bebf7bdfSowenca } else {
1488b7076a23SAlexander Kornienko parseAccessSpecifier();
1489bebf7bdfSowenca }
1490f7935115SDaniel Jasper return;
14915ead1f13Sowenca case tok::kw_if: {
1492bebf7bdfSowenca if (Style.isJavaScript() && Line->MustBeDeclaration) {
14930734fb21SMartin Probst // field/method declaration.
14940734fb21SMartin Probst break;
1495bebf7bdfSowenca }
14965ead1f13Sowenca FormatToken *Tok = parseIfThenElse(IfKind);
14975ead1f13Sowenca if (IfLeftBrace)
14985ead1f13Sowenca *IfLeftBrace = Tok;
1499f7935115SDaniel Jasper return;
15005ead1f13Sowenca }
150137d6c94eSAlexander Kornienko case tok::kw_for:
150237d6c94eSAlexander Kornienko case tok::kw_while:
1503bebf7bdfSowenca if (Style.isJavaScript() && Line->MustBeDeclaration) {
15040734fb21SMartin Probst // field/method declaration.
15050734fb21SMartin Probst break;
1506bebf7bdfSowenca }
150737d6c94eSAlexander Kornienko parseForOrWhileLoop();
150837d6c94eSAlexander Kornienko return;
1509f7935115SDaniel Jasper case tok::kw_do:
1510bebf7bdfSowenca if (Style.isJavaScript() && Line->MustBeDeclaration) {
15110734fb21SMartin Probst // field/method declaration.
15120734fb21SMartin Probst break;
1513bebf7bdfSowenca }
1514f7935115SDaniel Jasper parseDoWhile();
1515db15e312Sowenca if (HasDoWhile)
1516db15e312Sowenca *HasDoWhile = true;
1517f7935115SDaniel Jasper return;
1518f7935115SDaniel Jasper case tok::kw_switch:
1519bebf7bdfSowenca if (Style.isJavaScript() && Line->MustBeDeclaration) {
1520f785fd94SMartin Probst // 'switch: string' field declaration.
1521f785fd94SMartin Probst break;
1522bebf7bdfSowenca }
1523f7935115SDaniel Jasper parseSwitch();
1524f7935115SDaniel Jasper return;
1525f7935115SDaniel Jasper case tok::kw_default:
1526bebf7bdfSowenca if (Style.isJavaScript() && Line->MustBeDeclaration) {
1527f785fd94SMartin Probst // 'default: string' field declaration.
1528f785fd94SMartin Probst break;
1529bebf7bdfSowenca }
1530f7935115SDaniel Jasper nextToken();
1531c29f83b7SNico Weber if (FormatTok->is(tok::colon)) {
1532f7935115SDaniel Jasper parseLabel();
1533f7935115SDaniel Jasper return;
1534c29f83b7SNico Weber }
1535c29f83b7SNico Weber // e.g. "default void f() {}" in a Java interface.
1536c29f83b7SNico Weber break;
1537f7935115SDaniel Jasper case tok::kw_case:
15384e88cb68SMarek Kurdej if (Style.isJavaScript() && Line->MustBeDeclaration) {
1539f785fd94SMartin Probst // 'case: string' field declaration.
15404e88cb68SMarek Kurdej nextToken();
1541f785fd94SMartin Probst break;
15424e88cb68SMarek Kurdej }
1543f7935115SDaniel Jasper parseCaseLabel();
1544f7935115SDaniel Jasper return;
154504a71a45SDaniel Jasper case tok::kw_try:
1546fac2371bSNico Weber case tok::kw___try:
1547bebf7bdfSowenca if (Style.isJavaScript() && Line->MustBeDeclaration) {
15480734fb21SMartin Probst // field/method declaration.
15490734fb21SMartin Probst break;
1550bebf7bdfSowenca }
155104a71a45SDaniel Jasper parseTryCatch();
155204a71a45SDaniel Jasper return;
1553ae610d17SManuel Klimek case tok::kw_extern:
1554ae610d17SManuel Klimek nextToken();
1555fee4a971SMarek Kurdej if (FormatTok->is(tok::string_literal)) {
1556ae610d17SManuel Klimek nextToken();
1557fee4a971SMarek Kurdej if (FormatTok->is(tok::l_brace)) {
15583362fa59Smydeveloperday if (Style.BraceWrapping.AfterExternBlock)
1559d6ce937fSKrasimir Georgiev addUnwrappedLine();
15603362fa59Smydeveloperday // Either we indent or for backwards compatibility we follow the
15613362fa59Smydeveloperday // AfterExternBlock style.
15622a42c759SJakub Budiský unsigned AddLevels =
15633362fa59Smydeveloperday (Style.IndentExternBlock == FormatStyle::IEBS_Indent) ||
15643362fa59Smydeveloperday (Style.BraceWrapping.AfterExternBlock &&
15653362fa59Smydeveloperday Style.IndentExternBlock ==
15663362fa59Smydeveloperday FormatStyle::IEBS_AfterExternBlock)
15673362fa59Smydeveloperday ? 1u
15683362fa59Smydeveloperday : 0u;
15692a42c759SJakub Budiský parseBlock(/*MustBeDeclaration=*/true, AddLevels);
1570ae610d17SManuel Klimek addUnwrappedLine();
1571ae610d17SManuel Klimek return;
1572ae610d17SManuel Klimek }
1573ae610d17SManuel Klimek }
1574e1e4319aSDaniel Jasper break;
1575fca735cdSDaniel Jasper case tok::kw_export:
1576142e79b8Smydeveloperday if (Style.isJavaScript()) {
1577fca735cdSDaniel Jasper parseJavaScriptEs6ImportExport();
1578fca735cdSDaniel Jasper return;
1579fca735cdSDaniel Jasper }
15806f3778c3SSam McCall if (!Style.isCpp())
15816f3778c3SSam McCall break;
15826f3778c3SSam McCall // Handle C++ "(inline|export) namespace".
15836f3778c3SSam McCall LLVM_FALLTHROUGH;
15846f3778c3SSam McCall case tok::kw_inline:
15856f3778c3SSam McCall nextToken();
1586fee4a971SMarek Kurdej if (FormatTok->is(tok::kw_namespace)) {
15876f3778c3SSam McCall parseNamespace();
15886f3778c3SSam McCall return;
15896f3778c3SSam McCall }
1590fca735cdSDaniel Jasper break;
1591e1e4319aSDaniel Jasper case tok::identifier:
159266cb8c50SDaniel Jasper if (FormatTok->is(TT_ForEachMacro)) {
1593e1e4319aSDaniel Jasper parseForOrWhileLoop();
1594e1e4319aSDaniel Jasper return;
1595e1e4319aSDaniel Jasper }
1596b001a0baSBirunthan Mohanathas if (FormatTok->is(TT_MacroBlockBegin)) {
15972a42c759SJakub Budiský parseBlock(/*MustBeDeclaration=*/false, /*AddLevels=*/1u,
1598b001a0baSBirunthan Mohanathas /*MunchSemi=*/false);
1599b001a0baSBirunthan Mohanathas return;
1600b001a0baSBirunthan Mohanathas }
16013d5a7d6bSDaniel Jasper if (FormatTok->is(Keywords.kw_import)) {
1602142e79b8Smydeveloperday if (Style.isJavaScript()) {
1603fca735cdSDaniel Jasper parseJavaScriptEs6ImportExport();
1604354aa515SDaniel Jasper return;
1605354aa515SDaniel Jasper }
16063d5a7d6bSDaniel Jasper if (Style.Language == FormatStyle::LK_Proto) {
16073d5a7d6bSDaniel Jasper nextToken();
16088b61d14dSDaniel Jasper if (FormatTok->is(tok::kw_public))
16098b61d14dSDaniel Jasper nextToken();
16103d5a7d6bSDaniel Jasper if (!FormatTok->is(tok::string_literal))
16113d5a7d6bSDaniel Jasper return;
16123d5a7d6bSDaniel Jasper nextToken();
16133d5a7d6bSDaniel Jasper if (FormatTok->is(tok::semi))
16143d5a7d6bSDaniel Jasper nextToken();
16153d5a7d6bSDaniel Jasper addUnwrappedLine();
16163d5a7d6bSDaniel Jasper return;
16173d5a7d6bSDaniel Jasper }
1618c2fe2b5aSmydeveloperday if (Style.isCpp()) {
1619c2fe2b5aSmydeveloperday parseModuleImport();
1620c2fe2b5aSmydeveloperday return;
1621c2fe2b5aSmydeveloperday }
16223d5a7d6bSDaniel Jasper }
16231dbc2105SDaniel Jasper if (Style.isCpp() &&
162472b3357fSDaniel Jasper FormatTok->isOneOf(Keywords.kw_signals, Keywords.kw_qsignals,
1625a00de636SDaniel Jasper Keywords.kw_slots, Keywords.kw_qslots)) {
1626de0d1f3cSDaniel Jasper nextToken();
1627de0d1f3cSDaniel Jasper if (FormatTok->is(tok::colon)) {
1628de0d1f3cSDaniel Jasper nextToken();
1629de0d1f3cSDaniel Jasper addUnwrappedLine();
163053395406SDaniel Jasper return;
163153395406SDaniel Jasper }
163231343832SDaniel Jasper }
16336f40e21aSFrancois Ferrand if (Style.isCpp() && FormatTok->is(TT_StatementMacro)) {
16346f40e21aSFrancois Ferrand parseStatementMacro();
16356f40e21aSFrancois Ferrand return;
16366f40e21aSFrancois Ferrand }
1637e8a301f8SFrancois Ferrand if (Style.isCpp() && FormatTok->is(TT_NamespaceMacro)) {
1638e8a301f8SFrancois Ferrand parseNamespace();
1639e8a301f8SFrancois Ferrand return;
1640e8a301f8SFrancois Ferrand }
1641ae610d17SManuel Klimek // In all other cases, parse the declaration.
1642ae610d17SManuel Klimek break;
1643f7935115SDaniel Jasper default:
1644b7076a23SAlexander Kornienko break;
1645b7076a23SAlexander Kornienko }
1646b7076a23SAlexander Kornienko do {
1647e411aa85SManuel Klimek const FormatToken *Previous = FormatTok->Previous;
164815dfe7acSManuel Klimek switch (FormatTok->Tok.getKind()) {
1649372d8dcfSNico Weber case tok::at:
1650372d8dcfSNico Weber nextToken();
1651fee4a971SMarek Kurdej if (FormatTok->is(tok::l_brace)) {
165226b144ccSKrasimir Georgiev nextToken();
1653372d8dcfSNico Weber parseBracedList();
1654c068ff72SNico Weber break;
1655749c1b59SHans Wennborg } else if (Style.Language == FormatStyle::LK_Java &&
1656749c1b59SHans Wennborg FormatTok->is(Keywords.kw_interface)) {
1657749c1b59SHans Wennborg nextToken();
1658749c1b59SHans Wennborg break;
1659c068ff72SNico Weber }
1660c068ff72SNico Weber switch (FormatTok->Tok.getObjCKeywordID()) {
1661c068ff72SNico Weber case tok::objc_public:
1662c068ff72SNico Weber case tok::objc_protected:
1663c068ff72SNico Weber case tok::objc_package:
1664c068ff72SNico Weber case tok::objc_private:
1665c068ff72SNico Weber return parseAccessSpecifier();
1666c068ff72SNico Weber case tok::objc_interface:
1667c068ff72SNico Weber case tok::objc_implementation:
1668c068ff72SNico Weber return parseObjCInterfaceOrImplementation();
1669c068ff72SNico Weber case tok::objc_protocol:
1670c068ff72SNico Weber if (parseObjCProtocol())
1671c068ff72SNico Weber return;
1672c068ff72SNico Weber break;
1673c068ff72SNico Weber case tok::objc_end:
1674c068ff72SNico Weber return; // Handled by the caller.
1675c068ff72SNico Weber case tok::objc_optional:
1676c068ff72SNico Weber case tok::objc_required:
1677c068ff72SNico Weber nextToken();
1678c068ff72SNico Weber addUnwrappedLine();
1679c068ff72SNico Weber return;
1680c068ff72SNico Weber case tok::objc_autoreleasepool:
1681c068ff72SNico Weber nextToken();
1682fee4a971SMarek Kurdej if (FormatTok->is(tok::l_brace)) {
1683fb13e65aSPaul Hoad if (Style.BraceWrapping.AfterControlStatement ==
1684bebf7bdfSowenca FormatStyle::BWACS_Always) {
1685c068ff72SNico Weber addUnwrappedLine();
1686bebf7bdfSowenca }
1687e852cc0dSowenca parseBlock();
1688c068ff72SNico Weber }
1689c068ff72SNico Weber addUnwrappedLine();
1690c068ff72SNico Weber return;
1691ba91c3deSFrancois Ferrand case tok::objc_synchronized:
1692ba91c3deSFrancois Ferrand nextToken();
1693bebf7bdfSowenca if (FormatTok->is(tok::l_paren)) {
1694ba91c3deSFrancois Ferrand // Skip synchronization object
1695ba91c3deSFrancois Ferrand parseParens();
1696bebf7bdfSowenca }
1697fee4a971SMarek Kurdej if (FormatTok->is(tok::l_brace)) {
1698fb13e65aSPaul Hoad if (Style.BraceWrapping.AfterControlStatement ==
1699bebf7bdfSowenca FormatStyle::BWACS_Always) {
1700ba91c3deSFrancois Ferrand addUnwrappedLine();
1701bebf7bdfSowenca }
1702e852cc0dSowenca parseBlock();
1703ba91c3deSFrancois Ferrand }
1704ba91c3deSFrancois Ferrand addUnwrappedLine();
1705ba91c3deSFrancois Ferrand return;
1706c068ff72SNico Weber case tok::objc_try:
1707c068ff72SNico Weber // This branch isn't strictly necessary (the kw_try case below would
1708c068ff72SNico Weber // do this too after the tok::at is parsed above). But be explicit.
1709c068ff72SNico Weber parseTryCatch();
1710c068ff72SNico Weber return;
1711c068ff72SNico Weber default:
1712c068ff72SNico Weber break;
171326b144ccSKrasimir Georgiev }
1714372d8dcfSNico Weber break;
1715840e651dSmydeveloperday case tok::kw_concept:
1716840e651dSmydeveloperday parseConcept();
1717960712ccSMarek Kurdej return;
1718bcd1e461SBjörn Schäpers case tok::kw_requires: {
1719071f870eSMarek Kurdej if (Style.isCpp()) {
1720bcd1e461SBjörn Schäpers bool ParsedClause = parseRequires();
1721bcd1e461SBjörn Schäpers if (ParsedClause)
1722f66d602cSMarek Kurdej return;
1723071f870eSMarek Kurdej } else {
1724071f870eSMarek Kurdej nextToken();
1725071f870eSMarek Kurdej }
1726bcd1e461SBjörn Schäpers break;
1727bcd1e461SBjörn Schäpers }
1728b7076a23SAlexander Kornienko case tok::kw_enum:
1729a7900adfSDaniel Jasper // Ignore if this is part of "template <enum ...".
1730a7900adfSDaniel Jasper if (Previous && Previous->is(tok::less)) {
1731a7900adfSDaniel Jasper nextToken();
1732a7900adfSDaniel Jasper break;
1733a7900adfSDaniel Jasper }
1734a7900adfSDaniel Jasper
173590cf380eSDaniel Jasper // parseEnum falls through and does not yet add an unwrapped line as an
173690cf380eSDaniel Jasper // enum definition can start a structural element.
17376f5a1933SDaniel Jasper if (!parseEnum())
17386f5a1933SDaniel Jasper break;
1739c6dd273aSDaniel Jasper // This only applies for C++.
17401dbc2105SDaniel Jasper if (!Style.isCpp()) {
174190cf380eSDaniel Jasper addUnwrappedLine();
174290cf380eSDaniel Jasper return;
174390cf380eSDaniel Jasper }
17442cec0191SManuel Klimek break;
1745a88f80a1SDaniel Jasper case tok::kw_typedef:
1746a88f80a1SDaniel Jasper nextToken();
174731f6c547SDaniel Jasper if (FormatTok->isOneOf(Keywords.kw_NS_ENUM, Keywords.kw_NS_OPTIONS,
1748d9212ef7SBen Hamilton Keywords.kw_CF_ENUM, Keywords.kw_CF_OPTIONS,
1749ff9f4b54SNico Weber Keywords.kw_CF_CLOSED_ENUM,
1750bebf7bdfSowenca Keywords.kw_NS_CLOSED_ENUM)) {
1751a88f80a1SDaniel Jasper parseEnum();
1752bebf7bdfSowenca }
1753a88f80a1SDaniel Jasper break;
17541231e066SAlexander Kornienko case tok::kw_struct:
17551231e066SAlexander Kornienko case tok::kw_union:
175628cacc74SManuel Klimek case tok::kw_class:
1757d079995dSMarek Kurdej if (parseStructLike())
1758910807d4SDaniel Jasper return;
1759e01bab58SManuel Klimek break;
1760e5d74867SDaniel Jasper case tok::period:
1761e5d74867SDaniel Jasper nextToken();
1762e5d74867SDaniel Jasper // In Java, classes have an implicit static member "class".
1763e5d74867SDaniel Jasper if (Style.Language == FormatStyle::LK_Java && FormatTok &&
1764bebf7bdfSowenca FormatTok->is(tok::kw_class)) {
1765e5d74867SDaniel Jasper nextToken();
1766bebf7bdfSowenca }
1767142e79b8Smydeveloperday if (Style.isJavaScript() && FormatTok &&
1768bebf7bdfSowenca FormatTok->Tok.getIdentifierInfo()) {
1769ba52fcb7SDaniel Jasper // JavaScript only has pseudo keywords, all keywords are allowed to
1770ba52fcb7SDaniel Jasper // appear in "IdentifierName" positions. See http://es5.github.io/#x7.6
1771ba52fcb7SDaniel Jasper nextToken();
1772bebf7bdfSowenca }
1773e5d74867SDaniel Jasper break;
1774b7076a23SAlexander Kornienko case tok::semi:
1775b7076a23SAlexander Kornienko nextToken();
1776b7076a23SAlexander Kornienko addUnwrappedLine();
1777b7076a23SAlexander Kornienko return;
17781231e066SAlexander Kornienko case tok::r_brace:
17791231e066SAlexander Kornienko addUnwrappedLine();
17801231e066SAlexander Kornienko return;
1781f6928cf4SOwen case tok::l_paren: {
1782b7076a23SAlexander Kornienko parseParens();
17839da70ab3Sowenca // Break the unwrapped line if a K&R C function definition has a parameter
17849da70ab3Sowenca // declaration.
1785643f2be7Sowenca if (!IsTopLevel || !Style.isCpp() || !Previous || FormatTok->is(tok::eof))
17869da70ab3Sowenca break;
17871b5a43acSManuel Klimek if (isC78ParameterDecl(FormatTok, Tokens->peekNextToken(), Previous)) {
17889da70ab3Sowenca addUnwrappedLine();
17899da70ab3Sowenca return;
17909da70ab3Sowenca }
1791b7076a23SAlexander Kornienko break;
1792f6928cf4SOwen }
17935af04a4dSDaniel Jasper case tok::kw_operator:
17945af04a4dSDaniel Jasper nextToken();
17955af04a4dSDaniel Jasper if (FormatTok->isBinaryOperator())
17965af04a4dSDaniel Jasper nextToken();
17975af04a4dSDaniel Jasper break;
1798516e054cSManuel Klimek case tok::caret:
1799516e054cSManuel Klimek nextToken();
1800395193c7SDaniel Jasper if (FormatTok->Tok.isAnyIdentifier() ||
1801bebf7bdfSowenca FormatTok->isSimpleTypeSpecifier()) {
1802395193c7SDaniel Jasper nextToken();
1803bebf7bdfSowenca }
1804395193c7SDaniel Jasper if (FormatTok->is(tok::l_paren))
1805395193c7SDaniel Jasper parseParens();
1806395193c7SDaniel Jasper if (FormatTok->is(tok::l_brace))
1807516e054cSManuel Klimek parseChildBlock();
1808516e054cSManuel Klimek break;
1809b7076a23SAlexander Kornienko case tok::l_brace:
18109aab0db1SBjörn Schäpers if (NextLBracesType != TT_Unknown)
18111e7cc72aSBjörn Schäpers FormatTok->setFinalizedType(NextLBracesType);
18122f9fc8d9SJonathan Coe if (!tryToParsePropertyAccessor() && !tryToParseBracedList()) {
18138e07a1b6SManuel Klimek // A block outside of parentheses must be the last part of a
18148e07a1b6SManuel Klimek // structural element.
1815ab41991cSManuel Klimek // FIXME: Figure out cases where this is not true, and add projections
1816ab41991cSManuel Klimek // for them (the one we know is missing are lambdas).
181791b9e672SMarek Kurdej if (Style.Language == FormatStyle::LK_Java &&
181891b9e672SMarek Kurdej Line->Tokens.front().Tok->is(Keywords.kw_synchronized)) {
181991b9e672SMarek Kurdej // If necessary, we could set the type to something different than
182091b9e672SMarek Kurdej // TT_FunctionLBrace.
182191b9e672SMarek Kurdej if (Style.BraceWrapping.AfterControlStatement ==
1822bebf7bdfSowenca FormatStyle::BWACS_Always) {
1823a8eb9149SManuel Klimek addUnwrappedLine();
1824bebf7bdfSowenca }
182591b9e672SMarek Kurdej } else if (Style.BraceWrapping.AfterFunction) {
182691b9e672SMarek Kurdej addUnwrappedLine();
182791b9e672SMarek Kurdej }
182835f7dd60SOwen Pan if (!Line->InPPDirective)
18291e7cc72aSBjörn Schäpers FormatTok->setFinalizedType(TT_FunctionLBrace);
1830e852cc0dSowenca parseBlock();
1831b7076a23SAlexander Kornienko addUnwrappedLine();
1832b7076a23SAlexander Kornienko return;
1833ab41991cSManuel Klimek }
1834ab41991cSManuel Klimek // Otherwise this was a braced init list, and the structural
1835ab41991cSManuel Klimek // element continues.
1836ab41991cSManuel Klimek break;
183704a71a45SDaniel Jasper case tok::kw_try:
1838142e79b8Smydeveloperday if (Style.isJavaScript() && Line->MustBeDeclaration) {
18390734fb21SMartin Probst // field/method declaration.
18400734fb21SMartin Probst nextToken();
18410734fb21SMartin Probst break;
18420734fb21SMartin Probst }
184304a71a45SDaniel Jasper // We arrive here when parsing function-try blocks.
1844cb5ffbedSOwen Pan if (Style.BraceWrapping.AfterFunction)
1845cb5ffbedSOwen Pan addUnwrappedLine();
184604a71a45SDaniel Jasper parseTryCatch();
184704a71a45SDaniel Jasper return;
184840e1921fSDaniel Jasper case tok::identifier: {
1849dcbcec48SJonathan Coe if (Style.isCSharp() && FormatTok->is(Keywords.kw_where) &&
1850dcbcec48SJonathan Coe Line->MustBeDeclaration) {
1851dcbcec48SJonathan Coe addUnwrappedLine();
1852dcbcec48SJonathan Coe parseCSharpGenericTypeConstraint();
1853dcbcec48SJonathan Coe break;
1854dcbcec48SJonathan Coe }
1855b001a0baSBirunthan Mohanathas if (FormatTok->is(TT_MacroBlockEnd)) {
1856b001a0baSBirunthan Mohanathas addUnwrappedLine();
1857b001a0baSBirunthan Mohanathas return;
1858b001a0baSBirunthan Mohanathas }
1859b001a0baSBirunthan Mohanathas
1860973ff79eSMartin Probst // Function declarations (as opposed to function expressions) are parsed
1861973ff79eSMartin Probst // on their own unwrapped line by continuing this loop. Function
1862973ff79eSMartin Probst // expressions (functions that are not on their own line) must not create
1863973ff79eSMartin Probst // a new unwrapped line, so they are special cased below.
1864973ff79eSMartin Probst size_t TokenCount = Line->Tokens.size();
1865142e79b8Smydeveloperday if (Style.isJavaScript() && FormatTok->is(Keywords.kw_function) &&
1866973ff79eSMartin Probst (TokenCount > 1 || (TokenCount == 1 && !Line->Tokens.front().Tok->is(
1867973ff79eSMartin Probst Keywords.kw_async)))) {
1868069e5f48SDaniel Jasper tryToParseJSFunction();
1869069e5f48SDaniel Jasper break;
1870069e5f48SDaniel Jasper }
1871142e79b8Smydeveloperday if ((Style.isJavaScript() || Style.Language == FormatStyle::LK_Java) &&
18729326f919SDaniel Jasper FormatTok->is(Keywords.kw_interface)) {
1873142e79b8Smydeveloperday if (Style.isJavaScript()) {
18741e8261eaSMartin Probst // In JavaScript/TypeScript, "interface" can be used as a standalone
18751e8261eaSMartin Probst // identifier, e.g. in `var interface = 1;`. If "interface" is
18761e8261eaSMartin Probst // followed by another identifier, it is very like to be an actual
18771e8261eaSMartin Probst // interface declaration.
18781e8261eaSMartin Probst unsigned StoredPosition = Tokens->getPosition();
18791e8261eaSMartin Probst FormatToken *Next = Tokens->getNextToken();
18801e8261eaSMartin Probst FormatTok = Tokens->setPosition(StoredPosition);
188184bf5e32SManuel Klimek if (!mustBeJSIdent(Keywords, Next)) {
18821e8261eaSMartin Probst nextToken();
18831e8261eaSMartin Probst break;
18841e8261eaSMartin Probst }
18851e8261eaSMartin Probst }
18869326f919SDaniel Jasper parseRecord();
1887259188b1SDaniel Jasper addUnwrappedLine();
18885c235c09SDaniel Jasper return;
18899326f919SDaniel Jasper }
18909326f919SDaniel Jasper
1891ec725b30SEliza Velasquez if (FormatTok->is(Keywords.kw_interface)) {
1892d079995dSMarek Kurdej if (parseStructLike())
1893ec725b30SEliza Velasquez return;
1894ec725b30SEliza Velasquez break;
1895ec725b30SEliza Velasquez }
1896ec725b30SEliza Velasquez
18976f40e21aSFrancois Ferrand if (Style.isCpp() && FormatTok->is(TT_StatementMacro)) {
18986f40e21aSFrancois Ferrand parseStatementMacro();
18996f40e21aSFrancois Ferrand return;
19006f40e21aSFrancois Ferrand }
19016f40e21aSFrancois Ferrand
19021dcbbcfcSDaniel Jasper // See if the following token should start a new unwrapped line.
19039326f919SDaniel Jasper StringRef Text = FormatTok->TokenText;
19045e5efd8aSksyx
19055e5efd8aSksyx FormatToken *PreviousToken = FormatTok;
1906f7935115SDaniel Jasper nextToken();
1907945890a6SOwen Pan
1908945890a6SOwen Pan // JS doesn't have macros, and within classes colons indicate fields, not
1909945890a6SOwen Pan // labels.
1910142e79b8Smydeveloperday if (Style.isJavaScript())
1911945890a6SOwen Pan break;
1912945890a6SOwen Pan
19132e32ff10Ssstwcw auto OneTokenSoFar = [&]() {
19144de0680fSManuel Klimek auto I = Line->Tokens.begin(), E = Line->Tokens.end();
19154de0680fSManuel Klimek while (I != E && I->Tok->is(tok::comment))
19164de0680fSManuel Klimek ++I;
19174de0680fSManuel Klimek while (I != E && Style.isVerilog() && I->Tok->is(tok::hash))
19184de0680fSManuel Klimek ++I;
19194de0680fSManuel Klimek return I != E && (++I == E);
19202e32ff10Ssstwcw };
19212e32ff10Ssstwcw if (OneTokenSoFar()) {
1922fee4a971SMarek Kurdej if (FormatTok->is(tok::colon) && !Line->MustBeDeclaration) {
192340609472SDaniel Jasper Line->Tokens.begin()->Tok->MustBreakBefore = true;
19243867a2d5SPaul Hoad parseLabel(!Style.IndentGotoLabels);
192528b76b1eSowenca if (HasLabel)
192628b76b1eSowenca *HasLabel = true;
1927f7935115SDaniel Jasper return;
1928f7935115SDaniel Jasper }
1929680b09baSDaniel Jasper // Recognize function-like macro usages without trailing semicolon as
193083709086SDaniel Jasper // well as free-standing macros like Q_OBJECT.
1931680b09baSDaniel Jasper bool FunctionLike = FormatTok->is(tok::l_paren);
1932680b09baSDaniel Jasper if (FunctionLike)
1933de64427aSAlexander Kornienko parseParens();
1934e60cba13SDaniel Jasper
1935e60cba13SDaniel Jasper bool FollowedByNewline =
1936e60cba13SDaniel Jasper CommentsBeforeNextToken.empty()
1937e60cba13SDaniel Jasper ? FormatTok->NewlinesBefore > 0
1938e60cba13SDaniel Jasper : CommentsBeforeNextToken.front()->NewlinesBefore > 0;
1939e60cba13SDaniel Jasper
1940e6fcf7d3SDaniel Jasper if (FollowedByNewline && (Text.size() >= 5 || FunctionLike) &&
1941573a5b58SMarek Kurdej tokenCanStartNewLine(*FormatTok) && Text == Text.upper()) {
19421e7cc72aSBjörn Schäpers PreviousToken->setFinalizedType(TT_FunctionLikeOrFreestandingMacro);
1943de64427aSAlexander Kornienko addUnwrappedLine();
1944de64427aSAlexander Kornienko return;
1945de64427aSAlexander Kornienko }
1946de64427aSAlexander Kornienko }
1947f7935115SDaniel Jasper break;
194840e1921fSDaniel Jasper }
1949e25509f8SDaniel Jasper case tok::equal:
1950b9f6e09bSOwen Pan if ((Style.isJavaScript() || Style.isCSharp()) &&
1951b9f6e09bSOwen Pan FormatTok->is(TT_FatArrow)) {
1952b9f6e09bSOwen Pan tryToParseChildBlock();
195379e06081SManuel Klimek break;
195479e06081SManuel Klimek }
195579e06081SManuel Klimek
1956e25509f8SDaniel Jasper nextToken();
1957fee4a971SMarek Kurdej if (FormatTok->is(tok::l_brace)) {
19585e1a026cSJonathan Coe // Block kind should probably be set to BK_BracedInit for any language.
19595e1a026cSJonathan Coe // C# needs this change to ensure that array initialisers and object
19605e1a026cSJonathan Coe // initialisers are indented the same way.
19615e1a026cSJonathan Coe if (Style.isCSharp())
1962f5acd11dSBruno Ricci FormatTok->setBlockKind(BK_BracedInit);
196326b144ccSKrasimir Georgiev nextToken();
19648e07a1b6SManuel Klimek parseBracedList();
196526b144ccSKrasimir Georgiev } else if (Style.Language == FormatStyle::LK_Proto &&
1966fee4a971SMarek Kurdej FormatTok->is(tok::less)) {
196726b144ccSKrasimir Georgiev nextToken();
1968f3a3db86SMichael Liao parseBracedList(/*ContinueOnSemicolons=*/false, /*IsEnum=*/false,
19690b41fcb6SKrasimir Georgiev /*ClosingBraceKind=*/tok::greater);
197026b144ccSKrasimir Georgiev }
19718e07a1b6SManuel Klimek break;
1972ffdeb595SManuel Klimek case tok::l_square:
1973b88b25feSDaniel Jasper parseSquare();
1974ffdeb595SManuel Klimek break;
19756acf5130SDaniel Jasper case tok::kw_new:
19766acf5130SDaniel Jasper parseNew();
19776acf5130SDaniel Jasper break;
19784e88cb68SMarek Kurdej case tok::kw_case:
19794e88cb68SMarek Kurdej if (Style.isJavaScript() && Line->MustBeDeclaration) {
19804e88cb68SMarek Kurdej // 'case: string' field declaration.
19814e88cb68SMarek Kurdej nextToken();
19824e88cb68SMarek Kurdej break;
19834e88cb68SMarek Kurdej }
19844e88cb68SMarek Kurdej parseCaseLabel();
19854e88cb68SMarek Kurdej break;
19868e07a1b6SManuel Klimek default:
1987e25509f8SDaniel Jasper nextToken();
1988e25509f8SDaniel Jasper break;
19898e07a1b6SManuel Klimek }
19908e07a1b6SManuel Klimek } while (!eof());
19918e07a1b6SManuel Klimek }
19928e07a1b6SManuel Klimek
tryToParsePropertyAccessor()19932f9fc8d9SJonathan Coe bool UnwrappedLineParser::tryToParsePropertyAccessor() {
19942f9fc8d9SJonathan Coe assert(FormatTok->is(tok::l_brace));
19952f9fc8d9SJonathan Coe if (!Style.isCSharp())
19962f9fc8d9SJonathan Coe return false;
19972f9fc8d9SJonathan Coe // See if it's a property accessor.
19982f9fc8d9SJonathan Coe if (FormatTok->Previous->isNot(tok::identifier))
19992f9fc8d9SJonathan Coe return false;
20002f9fc8d9SJonathan Coe
200144ad58b9SJonathan Coe // See if we are inside a property accessor.
20022f9fc8d9SJonathan Coe //
20032f9fc8d9SJonathan Coe // Record the current tokenPosition so that we can advance and
20042f9fc8d9SJonathan Coe // reset the current token. `Next` is not set yet so we need
20052f9fc8d9SJonathan Coe // another way to advance along the token stream.
20062f9fc8d9SJonathan Coe unsigned int StoredPosition = Tokens->getPosition();
20072f9fc8d9SJonathan Coe FormatToken *Tok = Tokens->getNextToken();
20082f9fc8d9SJonathan Coe
200944ad58b9SJonathan Coe // A trivial property accessor is of the form:
20107a54fcebSMarek Kurdej // { [ACCESS_SPECIFIER] [get]; [ACCESS_SPECIFIER] [set|init] }
201144ad58b9SJonathan Coe // Track these as they do not require line breaks to be introduced.
20127a54fcebSMarek Kurdej bool HasSpecialAccessor = false;
201344ad58b9SJonathan Coe bool IsTrivialPropertyAccessor = true;
20142f9fc8d9SJonathan Coe while (!eof()) {
20152f9fc8d9SJonathan Coe if (Tok->isOneOf(tok::semi, tok::kw_public, tok::kw_private,
20162f9fc8d9SJonathan Coe tok::kw_protected, Keywords.kw_internal, Keywords.kw_get,
20177a54fcebSMarek Kurdej Keywords.kw_init, Keywords.kw_set)) {
20187a54fcebSMarek Kurdej if (Tok->isOneOf(Keywords.kw_get, Keywords.kw_init, Keywords.kw_set))
20197a54fcebSMarek Kurdej HasSpecialAccessor = true;
20202f9fc8d9SJonathan Coe Tok = Tokens->getNextToken();
20212f9fc8d9SJonathan Coe continue;
20222f9fc8d9SJonathan Coe }
202344ad58b9SJonathan Coe if (Tok->isNot(tok::r_brace))
202444ad58b9SJonathan Coe IsTrivialPropertyAccessor = false;
20252f9fc8d9SJonathan Coe break;
20262f9fc8d9SJonathan Coe }
20272f9fc8d9SJonathan Coe
20287a54fcebSMarek Kurdej if (!HasSpecialAccessor) {
20292f9fc8d9SJonathan Coe Tokens->setPosition(StoredPosition);
20302f9fc8d9SJonathan Coe return false;
20312f9fc8d9SJonathan Coe }
20322f9fc8d9SJonathan Coe
203344ad58b9SJonathan Coe // Try to parse the property accessor:
203444ad58b9SJonathan Coe // https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/properties
20352f9fc8d9SJonathan Coe Tokens->setPosition(StoredPosition);
2036b9f6e09bSOwen Pan if (!IsTrivialPropertyAccessor && Style.BraceWrapping.AfterFunction)
20378fa743abSJonathan Coe addUnwrappedLine();
203844ad58b9SJonathan Coe nextToken();
203944ad58b9SJonathan Coe do {
204044ad58b9SJonathan Coe switch (FormatTok->Tok.getKind()) {
204144ad58b9SJonathan Coe case tok::r_brace:
204244ad58b9SJonathan Coe nextToken();
204344ad58b9SJonathan Coe if (FormatTok->is(tok::equal)) {
204444ad58b9SJonathan Coe while (!eof() && FormatTok->isNot(tok::semi))
204544ad58b9SJonathan Coe nextToken();
20462f9fc8d9SJonathan Coe nextToken();
20472f9fc8d9SJonathan Coe }
204844ad58b9SJonathan Coe addUnwrappedLine();
204944ad58b9SJonathan Coe return true;
205044ad58b9SJonathan Coe case tok::l_brace:
205144ad58b9SJonathan Coe ++Line->Level;
205244ad58b9SJonathan Coe parseBlock(/*MustBeDeclaration=*/true);
205344ad58b9SJonathan Coe addUnwrappedLine();
205444ad58b9SJonathan Coe --Line->Level;
205544ad58b9SJonathan Coe break;
205644ad58b9SJonathan Coe case tok::equal:
2057cdf33962SEliza Velasquez if (FormatTok->is(TT_FatArrow)) {
205844ad58b9SJonathan Coe ++Line->Level;
20592f9fc8d9SJonathan Coe do {
20602f9fc8d9SJonathan Coe nextToken();
206144ad58b9SJonathan Coe } while (!eof() && FormatTok->isNot(tok::semi));
20622f9fc8d9SJonathan Coe nextToken();
20632f9fc8d9SJonathan Coe addUnwrappedLine();
206444ad58b9SJonathan Coe --Line->Level;
206544ad58b9SJonathan Coe break;
206644ad58b9SJonathan Coe }
206744ad58b9SJonathan Coe nextToken();
206844ad58b9SJonathan Coe break;
206944ad58b9SJonathan Coe default:
20707a54fcebSMarek Kurdej if (FormatTok->isOneOf(Keywords.kw_get, Keywords.kw_init,
20717a54fcebSMarek Kurdej Keywords.kw_set) &&
207244ad58b9SJonathan Coe !IsTrivialPropertyAccessor) {
207344ad58b9SJonathan Coe // Non-trivial get/set needs to be on its own line.
207444ad58b9SJonathan Coe addUnwrappedLine();
207544ad58b9SJonathan Coe }
207644ad58b9SJonathan Coe nextToken();
207744ad58b9SJonathan Coe }
207844ad58b9SJonathan Coe } while (!eof());
207944ad58b9SJonathan Coe
208044ad58b9SJonathan Coe // Unreachable for well-formed code (paired '{' and '}').
20812f9fc8d9SJonathan Coe return true;
20822f9fc8d9SJonathan Coe }
20832f9fc8d9SJonathan Coe
tryToParseLambda()2084b88b25feSDaniel Jasper bool UnwrappedLineParser::tryToParseLambda() {
208539718803Sowenca assert(FormatTok->is(tok::l_square));
20861dbc2105SDaniel Jasper if (!Style.isCpp()) {
20871feab0f9SDaniel Jasper nextToken();
20881feab0f9SDaniel Jasper return false;
20891feab0f9SDaniel Jasper }
20909fe0e8daSDaniel Jasper FormatToken &LSquare = *FormatTok;
20919a8d48b5SDaniel Jasper if (!tryToParseLambdaIntroducer())
2092b88b25feSDaniel Jasper return false;
2093ffdeb595SManuel Klimek
2094c416c52bSKrasimir Georgiev bool SeenArrow = false;
209593948c52SMarek Kurdej bool InTemplateParameterList = false;
2096c416c52bSKrasimir Georgiev
2097c2ee9cf8SAlexander Kornienko while (FormatTok->isNot(tok::l_brace)) {
2098cb51cf40SDaniel Jasper if (FormatTok->isSimpleTypeSpecifier()) {
2099cb51cf40SDaniel Jasper nextToken();
2100cb51cf40SDaniel Jasper continue;
2101cb51cf40SDaniel Jasper }
2102ffdeb595SManuel Klimek switch (FormatTok->Tok.getKind()) {
2103ffdeb595SManuel Klimek case tok::l_brace:
2104ffdeb595SManuel Klimek break;
2105ffdeb595SManuel Klimek case tok::l_paren:
2106ffdeb595SManuel Klimek parseParens();
2107ffdeb595SManuel Klimek break;
2108e2b6e21fSMarek Kurdej case tok::l_square:
2109e2b6e21fSMarek Kurdej parseSquare();
2110e2b6e21fSMarek Kurdej break;
211193948c52SMarek Kurdej case tok::kw_class:
211293948c52SMarek Kurdej case tok::kw_template:
211393948c52SMarek Kurdej case tok::kw_typename:
211493948c52SMarek Kurdej assert(FormatTok->Previous);
211593948c52SMarek Kurdej if (FormatTok->Previous->is(tok::less))
211693948c52SMarek Kurdej InTemplateParameterList = true;
211793948c52SMarek Kurdej nextToken();
211893948c52SMarek Kurdej break;
2119bcb55eecSDaniel Jasper case tok::amp:
2120bcb55eecSDaniel Jasper case tok::star:
2121bcb55eecSDaniel Jasper case tok::kw_const:
2122*d2eda492SBjörn Schäpers case tok::kw_constexpr:
21233431b750SDaniel Jasper case tok::comma:
2124cb51cf40SDaniel Jasper case tok::less:
2125cb51cf40SDaniel Jasper case tok::greater:
21269a8d48b5SDaniel Jasper case tok::identifier:
21275eaa009eSDaniel Jasper case tok::numeric_constant:
21281067ab0aSDaniel Jasper case tok::coloncolon:
21299a8d48b5SDaniel Jasper case tok::kw_mutable:
21304e442bb8SBen Hamilton case tok::kw_noexcept:
2131c416c52bSKrasimir Georgiev nextToken();
2132c416c52bSKrasimir Georgiev break;
213388e15140SJan Korous // Specialization of a template with an integer parameter can contain
213488e15140SJan Korous // arithmetic, logical, comparison and ternary operators.
2135c416c52bSKrasimir Georgiev //
2136c416c52bSKrasimir Georgiev // FIXME: This also accepts sequences of operators that are not in the scope
2137c416c52bSKrasimir Georgiev // of a template argument list.
2138c416c52bSKrasimir Georgiev //
2139c416c52bSKrasimir Georgiev // In a C++ lambda a template type can only occur after an arrow. We use
2140c416c52bSKrasimir Georgiev // this as an heuristic to distinguish between Objective-C expressions
2141c416c52bSKrasimir Georgiev // followed by an `a->b` expression, such as:
2142c416c52bSKrasimir Georgiev // ([obj func:arg] + a->b)
2143c416c52bSKrasimir Georgiev // Otherwise the code below would parse as a lambda.
214441f4d68aSNico Weber //
214541f4d68aSNico Weber // FIXME: This heuristic is incorrect for C++20 generic lambdas with
214641f4d68aSNico Weber // explicit template lists: []<bool b = true && false>(U &&u){}
214788e15140SJan Korous case tok::plus:
214888e15140SJan Korous case tok::minus:
214988e15140SJan Korous case tok::exclaim:
215088e15140SJan Korous case tok::tilde:
215188e15140SJan Korous case tok::slash:
215288e15140SJan Korous case tok::percent:
215388e15140SJan Korous case tok::lessless:
215488e15140SJan Korous case tok::pipe:
215588e15140SJan Korous case tok::pipepipe:
215688e15140SJan Korous case tok::ampamp:
215788e15140SJan Korous case tok::caret:
215888e15140SJan Korous case tok::equalequal:
215988e15140SJan Korous case tok::exclaimequal:
216088e15140SJan Korous case tok::greaterequal:
216188e15140SJan Korous case tok::lessequal:
216288e15140SJan Korous case tok::question:
216388e15140SJan Korous case tok::colon:
216414198ccfSmydeveloperday case tok::ellipsis:
216510de3954SPaul Hoad case tok::kw_true:
216610de3954SPaul Hoad case tok::kw_false:
216793948c52SMarek Kurdej if (SeenArrow || InTemplateParameterList) {
216881a20787SDaniel Jasper nextToken();
216981a20787SDaniel Jasper break;
2170c416c52bSKrasimir Georgiev }
2171c416c52bSKrasimir Georgiev return true;
2172cb51cf40SDaniel Jasper case tok::arrow:
217330b7d09dSBen Hamilton // This might or might not actually be a lambda arrow (this could be an
217430b7d09dSBen Hamilton // ObjC method invocation followed by a dereferencing arrow). We might
217530b7d09dSBen Hamilton // reset this back to TT_Unknown in TokenAnnotator.
21761e7cc72aSBjörn Schäpers FormatTok->setFinalizedType(TT_LambdaArrow);
2177c416c52bSKrasimir Georgiev SeenArrow = true;
2178ffdeb595SManuel Klimek nextToken();
2179ffdeb595SManuel Klimek break;
21809a8d48b5SDaniel Jasper default:
2181b88b25feSDaniel Jasper return true;
2182ffdeb595SManuel Klimek }
2183ffdeb595SManuel Klimek }
21841e7cc72aSBjörn Schäpers FormatTok->setFinalizedType(TT_LambdaLBrace);
21851e7cc72aSBjörn Schäpers LSquare.setFinalizedType(TT_LambdaLSquare);
2186516e054cSManuel Klimek parseChildBlock();
2187b88b25feSDaniel Jasper return true;
2188ffdeb595SManuel Klimek }
2189ffdeb595SManuel Klimek
tryToParseLambdaIntroducer()2190ffdeb595SManuel Klimek bool UnwrappedLineParser::tryToParseLambdaIntroducer() {
2191e411aa85SManuel Klimek const FormatToken *Previous = FormatTok->Previous;
219239718803Sowenca const FormatToken *LeftSquare = FormatTok;
219339718803Sowenca nextToken();
21949f0a4e50SManuel Klimek if (Previous &&
21959f0a4e50SManuel Klimek (Previous->isOneOf(tok::identifier, tok::kw_operator, tok::kw_new,
2196d0f3fe55SManuel Klimek tok::kw_delete, tok::l_square) ||
219739718803Sowenca LeftSquare->isCppStructuredBinding(Style) || Previous->closesScope() ||
219889628f64SManuel Klimek Previous->isSimpleTypeSpecifier())) {
21999f0a4e50SManuel Klimek return false;
22009f0a4e50SManuel Klimek }
2201d079995dSMarek Kurdej if (FormatTok->is(tok::l_square))
2202d0f3fe55SManuel Klimek return false;
2203c8603db0Sowenca if (FormatTok->is(tok::r_square)) {
2204c8603db0Sowenca const FormatToken *Next = Tokens->peekNextToken();
220539718803Sowenca if (Next->is(tok::greater))
2206c8603db0Sowenca return false;
2207c8603db0Sowenca }
22089f0a4e50SManuel Klimek parseSquare(/*LambdaIntroducer=*/true);
22099a8d48b5SDaniel Jasper return true;
22109a8d48b5SDaniel Jasper }
2211ffdeb595SManuel Klimek
tryToParseJSFunction()2212c03e16a7SDaniel Jasper void UnwrappedLineParser::tryToParseJSFunction() {
2213409697ecSMartin Probst assert(FormatTok->is(Keywords.kw_function) ||
2214409697ecSMartin Probst FormatTok->startsSequence(Keywords.kw_async, Keywords.kw_function));
22155f8445b3SMartin Probst if (FormatTok->is(Keywords.kw_async))
22165f8445b3SMartin Probst nextToken();
22175f8445b3SMartin Probst // Consume "function".
22185f8445b3SMartin Probst nextToken();
22195f8445b3SMartin Probst
222071e50af6SDaniel Jasper // Consume * (generator function). Treat it like C++'s overloaded operators.
222171e50af6SDaniel Jasper if (FormatTok->is(tok::star)) {
22221e7cc72aSBjörn Schäpers FormatTok->setFinalizedType(TT_OverloadedOperator);
2223c03e16a7SDaniel Jasper nextToken();
222471e50af6SDaniel Jasper }
22255217a8b8SDaniel Jasper
22265217a8b8SDaniel Jasper // Consume function name.
22275217a8b8SDaniel Jasper if (FormatTok->is(tok::identifier))
22285217a8b8SDaniel Jasper nextToken();
22295217a8b8SDaniel Jasper
2230c03e16a7SDaniel Jasper if (FormatTok->isNot(tok::l_paren))
2231c03e16a7SDaniel Jasper return;
223279e06081SManuel Klimek
223379e06081SManuel Klimek // Parse formal parameter list.
2234be520bd1SDaniel Jasper parseParens();
223579e06081SManuel Klimek
223679e06081SManuel Klimek if (FormatTok->is(tok::colon)) {
223779e06081SManuel Klimek // Parse a type definition.
2238c03e16a7SDaniel Jasper nextToken();
223979e06081SManuel Klimek
224079e06081SManuel Klimek // Eat the type declaration. For braced inline object types, balance braces,
224179e06081SManuel Klimek // otherwise just parse until finding an l_brace for the function body.
2242be520bd1SDaniel Jasper if (FormatTok->is(tok::l_brace))
2243be520bd1SDaniel Jasper tryToParseBracedList();
2244be520bd1SDaniel Jasper else
2245af16c506SMartin Probst while (!FormatTok->isOneOf(tok::l_brace, tok::semi) && !eof())
2246c03e16a7SDaniel Jasper nextToken();
2247c03e16a7SDaniel Jasper }
224879e06081SManuel Klimek
2249af16c506SMartin Probst if (FormatTok->is(tok::semi))
2250af16c506SMartin Probst return;
2251af16c506SMartin Probst
2252c03e16a7SDaniel Jasper parseChildBlock();
2253c03e16a7SDaniel Jasper }
2254c03e16a7SDaniel Jasper
tryToParseBracedList()22553c883d1dSDaniel Jasper bool UnwrappedLineParser::tryToParseBracedList() {
2256f5acd11dSBruno Ricci if (FormatTok->is(BK_Unknown))
22573c883d1dSDaniel Jasper calculateBraceTypes();
2258f5acd11dSBruno Ricci assert(FormatTok->isNot(BK_Unknown));
2259f5acd11dSBruno Ricci if (FormatTok->is(BK_Block))
2260ab41991cSManuel Klimek return false;
226126b144ccSKrasimir Georgiev nextToken();
2262ab41991cSManuel Klimek parseBracedList();
2263ab41991cSManuel Klimek return true;
2264ab41991cSManuel Klimek }
2265ab41991cSManuel Klimek
tryToParseChildBlock()2266b9f6e09bSOwen Pan bool UnwrappedLineParser::tryToParseChildBlock() {
2267b9f6e09bSOwen Pan assert(Style.isJavaScript() || Style.isCSharp());
2268b9f6e09bSOwen Pan assert(FormatTok->is(TT_FatArrow));
2269b9f6e09bSOwen Pan // Fat arrows (=>) have tok::TokenKind tok::equal but TokenType TT_FatArrow.
2270b9f6e09bSOwen Pan // They always start an expression or a child block if followed by a curly
2271b9f6e09bSOwen Pan // brace.
2272163c13feSPeter Stys nextToken();
2273163c13feSPeter Stys if (FormatTok->isNot(tok::l_brace))
2274163c13feSPeter Stys return false;
2275163c13feSPeter Stys parseChildBlock();
2276163c13feSPeter Stys return true;
2277163c13feSPeter Stys }
2278163c13feSPeter Stys
parseBracedList(bool ContinueOnSemicolons,bool IsEnum,tok::TokenKind ClosingBraceKind)2279ff747be4SKrasimir Georgiev bool UnwrappedLineParser::parseBracedList(bool ContinueOnSemicolons,
2280292058a5SAaron Smith bool IsEnum,
2281ff747be4SKrasimir Georgiev tok::TokenKind ClosingBraceKind) {
2282015ed028SDaniel Jasper bool HasError = false;
22838e07a1b6SManuel Klimek
2284a3ff45ebSManuel Klimek // FIXME: Once we have an expression parser in the UnwrappedLineParser,
2285f9937106Smydeveloperday // replace this by using parseAssignmentExpression() inside.
22868e07a1b6SManuel Klimek do {
2287b9f6e09bSOwen Pan if (Style.isCSharp() && FormatTok->is(TT_FatArrow) &&
2288bebf7bdfSowenca tryToParseChildBlock()) {
22897d2fdd3fSJonathan Coe continue;
2290bebf7bdfSowenca }
2291142e79b8Smydeveloperday if (Style.isJavaScript()) {
2292409697ecSMartin Probst if (FormatTok->is(Keywords.kw_function) ||
2293409697ecSMartin Probst FormatTok->startsSequence(Keywords.kw_async, Keywords.kw_function)) {
2294c03e16a7SDaniel Jasper tryToParseJSFunction();
2295c03e16a7SDaniel Jasper continue;
2296be520bd1SDaniel Jasper }
22978e3eba03SMartin Probst if (FormatTok->is(tok::l_brace)) {
22988e3eba03SMartin Probst // Could be a method inside of a braced list `{a() { return 1; }}`.
22998e3eba03SMartin Probst if (tryToParseBracedList())
23008e3eba03SMartin Probst continue;
23018e3eba03SMartin Probst parseChildBlock();
23028e3eba03SMartin Probst }
2303c03e16a7SDaniel Jasper }
2304ff747be4SKrasimir Georgiev if (FormatTok->Tok.getKind() == ClosingBraceKind) {
2305292058a5SAaron Smith if (IsEnum && !Style.AllowShortEnumsOnASingleLine)
2306292058a5SAaron Smith addUnwrappedLine();
2307ff747be4SKrasimir Georgiev nextToken();
2308ff747be4SKrasimir Georgiev return !HasError;
2309ff747be4SKrasimir Georgiev }
231015dfe7acSManuel Klimek switch (FormatTok->Tok.getKind()) {
2311ffdeb595SManuel Klimek case tok::l_square:
2312eb682b80SJonathan Coe if (Style.isCSharp())
2313eb682b80SJonathan Coe parseSquare();
2314eb682b80SJonathan Coe else
2315ffdeb595SManuel Klimek tryToParseLambda();
2316ffdeb595SManuel Klimek break;
2317a87af7a3SDaniel Jasper case tok::l_paren:
2318a87af7a3SDaniel Jasper parseParens();
2319f46dec86SDaniel Jasper // JavaScript can just have free standing methods and getters/setters in
2320f46dec86SDaniel Jasper // object literals. Detect them by a "{" following ")".
2321142e79b8Smydeveloperday if (Style.isJavaScript()) {
2322f46dec86SDaniel Jasper if (FormatTok->is(tok::l_brace))
2323f46dec86SDaniel Jasper parseChildBlock();
2324f46dec86SDaniel Jasper break;
2325f46dec86SDaniel Jasper }
2326f46dec86SDaniel Jasper break;
23278e3eba03SMartin Probst case tok::l_brace:
23288e3eba03SMartin Probst // Assume there are no blocks inside a braced init list apart
23298e3eba03SMartin Probst // from the ones we explicitly parse out (like lambdas).
2330f5acd11dSBruno Ricci FormatTok->setBlockKind(BK_BracedInit);
233126b144ccSKrasimir Georgiev nextToken();
23328e3eba03SMartin Probst parseBracedList();
23338e3eba03SMartin Probst break;
2334fa4dbb68SKrasimir Georgiev case tok::less:
2335dab5e10eSSergey Semushin if (Style.Language == FormatStyle::LK_Proto ||
2336dab5e10eSSergey Semushin ClosingBraceKind == tok::greater) {
2337fa4dbb68SKrasimir Georgiev nextToken();
2338f3a3db86SMichael Liao parseBracedList(/*ContinueOnSemicolons=*/false, /*IsEnum=*/false,
2339fa4dbb68SKrasimir Georgiev /*ClosingBraceKind=*/tok::greater);
2340fa4dbb68SKrasimir Georgiev } else {
2341fa4dbb68SKrasimir Georgiev nextToken();
2342fa4dbb68SKrasimir Georgiev }
2343fa4dbb68SKrasimir Georgiev break;
2344a3ff45ebSManuel Klimek case tok::semi:
2345b9a4990aSDaniel Jasper // JavaScript (or more precisely TypeScript) can have semicolons in braced
2346b9a4990aSDaniel Jasper // lists (in so-called TypeMemberLists). Thus, the semicolon cannot be
2347b9a4990aSDaniel Jasper // used for error recovery if we have otherwise determined that this is
2348b9a4990aSDaniel Jasper // a braced list.
2349142e79b8Smydeveloperday if (Style.isJavaScript()) {
2350b9a4990aSDaniel Jasper nextToken();
2351b9a4990aSDaniel Jasper break;
2352b9a4990aSDaniel Jasper }
2353015ed028SDaniel Jasper HasError = true;
2354015ed028SDaniel Jasper if (!ContinueOnSemicolons)
2355015ed028SDaniel Jasper return !HasError;
2356015ed028SDaniel Jasper nextToken();
2357015ed028SDaniel Jasper break;
2358a3ff45ebSManuel Klimek case tok::comma:
2359a3ff45ebSManuel Klimek nextToken();
2360292058a5SAaron Smith if (IsEnum && !Style.AllowShortEnumsOnASingleLine)
2361292058a5SAaron Smith addUnwrappedLine();
2362a3ff45ebSManuel Klimek break;
2363b7076a23SAlexander Kornienko default:
2364b7076a23SAlexander Kornienko nextToken();
2365b7076a23SAlexander Kornienko break;
2366f7935115SDaniel Jasper }
2367f7935115SDaniel Jasper } while (!eof());
2368015ed028SDaniel Jasper return false;
2369f7935115SDaniel Jasper }
2370f7935115SDaniel Jasper
23719aab0db1SBjörn Schäpers /// \brief Parses a pair of parentheses (and everything between them).
23729aab0db1SBjörn Schäpers /// \param AmpAmpTokenType If different than TT_Unknown sets this type for all
23739aab0db1SBjörn Schäpers /// double ampersands. This only counts for the current parens scope.
parseParens(TokenType AmpAmpTokenType)23749aab0db1SBjörn Schäpers void UnwrappedLineParser::parseParens(TokenType AmpAmpTokenType) {
2375fee4a971SMarek Kurdej assert(FormatTok->is(tok::l_paren) && "'(' expected.");
2376f7935115SDaniel Jasper nextToken();
2377f7935115SDaniel Jasper do {
237815dfe7acSManuel Klimek switch (FormatTok->Tok.getKind()) {
2379f7935115SDaniel Jasper case tok::l_paren:
2380f7935115SDaniel Jasper parseParens();
23815f1fa85eSDaniel Jasper if (Style.Language == FormatStyle::LK_Java && FormatTok->is(tok::l_brace))
23825f1fa85eSDaniel Jasper parseChildBlock();
2383f7935115SDaniel Jasper break;
2384f7935115SDaniel Jasper case tok::r_paren:
2385f7935115SDaniel Jasper nextToken();
2386f7935115SDaniel Jasper return;
2387393564fdSDaniel Jasper case tok::r_brace:
2388393564fdSDaniel Jasper // A "}" inside parenthesis is an error if there wasn't a matching "{".
2389393564fdSDaniel Jasper return;
23909a8d48b5SDaniel Jasper case tok::l_square:
23919a8d48b5SDaniel Jasper tryToParseLambda();
23929a8d48b5SDaniel Jasper break;
23935f1fa85eSDaniel Jasper case tok::l_brace:
2394adba2aadSDaniel Jasper if (!tryToParseBracedList())
2395f017dc01SManuel Klimek parseChildBlock();
23968e07a1b6SManuel Klimek break;
2397372d8dcfSNico Weber case tok::at:
2398372d8dcfSNico Weber nextToken();
2399fee4a971SMarek Kurdej if (FormatTok->is(tok::l_brace)) {
240026b144ccSKrasimir Georgiev nextToken();
2401372d8dcfSNico Weber parseBracedList();
240226b144ccSKrasimir Georgiev }
2403372d8dcfSNico Weber break;
2404f9937106Smydeveloperday case tok::equal:
2405f9937106Smydeveloperday if (Style.isCSharp() && FormatTok->is(TT_FatArrow))
2406b9f6e09bSOwen Pan tryToParseChildBlock();
2407f9937106Smydeveloperday else
2408f9937106Smydeveloperday nextToken();
2409f9937106Smydeveloperday break;
24101027fb8aSMartin Probst case tok::kw_class:
2411142e79b8Smydeveloperday if (Style.isJavaScript())
24121027fb8aSMartin Probst parseRecord(/*ParseAsExpr=*/true);
24131027fb8aSMartin Probst else
24141027fb8aSMartin Probst nextToken();
24151027fb8aSMartin Probst break;
24163f69ba10SDaniel Jasper case tok::identifier:
2417142e79b8Smydeveloperday if (Style.isJavaScript() &&
2418409697ecSMartin Probst (FormatTok->is(Keywords.kw_function) ||
2419bebf7bdfSowenca FormatTok->startsSequence(Keywords.kw_async,
2420bebf7bdfSowenca Keywords.kw_function))) {
24213f69ba10SDaniel Jasper tryToParseJSFunction();
2422bebf7bdfSowenca } else {
24233f69ba10SDaniel Jasper nextToken();
2424bebf7bdfSowenca }
24253f69ba10SDaniel Jasper break;
2426bcd1e461SBjörn Schäpers case tok::kw_requires: {
2427bcd1e461SBjörn Schäpers auto RequiresToken = FormatTok;
2428bcd1e461SBjörn Schäpers nextToken();
2429bcd1e461SBjörn Schäpers parseRequiresExpression(RequiresToken);
24309aab0db1SBjörn Schäpers break;
2431bcd1e461SBjörn Schäpers }
24329aab0db1SBjörn Schäpers case tok::ampamp:
24339aab0db1SBjörn Schäpers if (AmpAmpTokenType != TT_Unknown)
24341e7cc72aSBjörn Schäpers FormatTok->setFinalizedType(AmpAmpTokenType);
24359aab0db1SBjörn Schäpers LLVM_FALLTHROUGH;
2436f7935115SDaniel Jasper default:
2437f7935115SDaniel Jasper nextToken();
2438f7935115SDaniel Jasper break;
2439f7935115SDaniel Jasper }
2440f7935115SDaniel Jasper } while (!eof());
2441f7935115SDaniel Jasper }
2442f7935115SDaniel Jasper
parseSquare(bool LambdaIntroducer)24439f0a4e50SManuel Klimek void UnwrappedLineParser::parseSquare(bool LambdaIntroducer) {
24449f0a4e50SManuel Klimek if (!LambdaIntroducer) {
2445fee4a971SMarek Kurdej assert(FormatTok->is(tok::l_square) && "'[' expected.");
2446b88b25feSDaniel Jasper if (tryToParseLambda())
2447b88b25feSDaniel Jasper return;
24489f0a4e50SManuel Klimek }
2449b88b25feSDaniel Jasper do {
2450b88b25feSDaniel Jasper switch (FormatTok->Tok.getKind()) {
2451b88b25feSDaniel Jasper case tok::l_paren:
2452b88b25feSDaniel Jasper parseParens();
2453b88b25feSDaniel Jasper break;
2454b88b25feSDaniel Jasper case tok::r_square:
2455b88b25feSDaniel Jasper nextToken();
2456b88b25feSDaniel Jasper return;
2457b88b25feSDaniel Jasper case tok::r_brace:
2458b88b25feSDaniel Jasper // A "}" inside parenthesis is an error if there wasn't a matching "{".
2459b88b25feSDaniel Jasper return;
2460b88b25feSDaniel Jasper case tok::l_square:
2461b88b25feSDaniel Jasper parseSquare();
2462b88b25feSDaniel Jasper break;
2463b88b25feSDaniel Jasper case tok::l_brace: {
2464adba2aadSDaniel Jasper if (!tryToParseBracedList())
2465b88b25feSDaniel Jasper parseChildBlock();
2466b88b25feSDaniel Jasper break;
2467b88b25feSDaniel Jasper }
2468b88b25feSDaniel Jasper case tok::at:
2469b88b25feSDaniel Jasper nextToken();
2470fee4a971SMarek Kurdej if (FormatTok->is(tok::l_brace)) {
247126b144ccSKrasimir Georgiev nextToken();
2472b88b25feSDaniel Jasper parseBracedList();
247326b144ccSKrasimir Georgiev }
2474b88b25feSDaniel Jasper break;
2475b88b25feSDaniel Jasper default:
2476b88b25feSDaniel Jasper nextToken();
2477b88b25feSDaniel Jasper break;
2478b88b25feSDaniel Jasper }
2479b88b25feSDaniel Jasper } while (!eof());
2480b88b25feSDaniel Jasper }
2481b88b25feSDaniel Jasper
keepAncestorBraces()2482533fbae8SOwen Pan void UnwrappedLineParser::keepAncestorBraces() {
2483533fbae8SOwen Pan if (!Style.RemoveBracesLLVM)
2484533fbae8SOwen Pan return;
2485533fbae8SOwen Pan
2486533fbae8SOwen Pan const int MaxNestingLevels = 2;
2487533fbae8SOwen Pan const int Size = NestedTooDeep.size();
2488533fbae8SOwen Pan if (Size >= MaxNestingLevels)
2489533fbae8SOwen Pan NestedTooDeep[Size - MaxNestingLevels] = true;
2490533fbae8SOwen Pan NestedTooDeep.push_back(false);
2491533fbae8SOwen Pan }
2492533fbae8SOwen Pan
getLastNonComment(const UnwrappedLine & Line)249377e60bc4Sowenca static FormatToken *getLastNonComment(const UnwrappedLine &Line) {
249477e60bc4Sowenca for (const auto &Token : llvm::reverse(Line.Tokens))
249577e60bc4Sowenca if (Token.Tok->isNot(tok::comment))
249677e60bc4Sowenca return Token.Tok;
249777e60bc4Sowenca
249877e60bc4Sowenca return nullptr;
249977e60bc4Sowenca }
250077e60bc4Sowenca
parseUnbracedBody(bool CheckEOF)250177e60bc4Sowenca void UnwrappedLineParser::parseUnbracedBody(bool CheckEOF) {
250277e60bc4Sowenca FormatToken *Tok = nullptr;
250377e60bc4Sowenca
250477e60bc4Sowenca if (Style.InsertBraces && !Line->InPPDirective && !Line->Tokens.empty() &&
250577e60bc4Sowenca PreprocessorDirectives.empty()) {
250677e60bc4Sowenca Tok = getLastNonComment(*Line);
250777e60bc4Sowenca assert(Tok);
250877e60bc4Sowenca if (Tok->BraceCount < 0) {
250977e60bc4Sowenca assert(Tok->BraceCount == -1);
251077e60bc4Sowenca Tok = nullptr;
251177e60bc4Sowenca } else {
251277e60bc4Sowenca Tok->BraceCount = -1;
251377e60bc4Sowenca }
251477e60bc4Sowenca }
251577e60bc4Sowenca
251677e60bc4Sowenca addUnwrappedLine();
251777e60bc4Sowenca ++Line->Level;
251877e60bc4Sowenca parseStructuralElement();
251977e60bc4Sowenca
252077e60bc4Sowenca if (Tok) {
252177e60bc4Sowenca assert(!Line->InPPDirective);
252277e60bc4Sowenca Tok = nullptr;
252377e60bc4Sowenca for (const auto &L : llvm::reverse(*CurrentLines)) {
2524c05da55bSowenca if (!L.InPPDirective && getLastNonComment(L)) {
2525c05da55bSowenca Tok = L.Tokens.back().Tok;
252677e60bc4Sowenca break;
252777e60bc4Sowenca }
252877e60bc4Sowenca }
252977e60bc4Sowenca assert(Tok);
253077e60bc4Sowenca ++Tok->BraceCount;
253177e60bc4Sowenca }
253277e60bc4Sowenca
253377e60bc4Sowenca if (CheckEOF && FormatTok->is(tok::eof))
253477e60bc4Sowenca addUnwrappedLine();
253577e60bc4Sowenca
253677e60bc4Sowenca --Line->Level;
253777e60bc4Sowenca }
253877e60bc4Sowenca
markOptionalBraces(FormatToken * LeftBrace)2539533fbae8SOwen Pan static void markOptionalBraces(FormatToken *LeftBrace) {
2540533fbae8SOwen Pan if (!LeftBrace)
2541533fbae8SOwen Pan return;
2542533fbae8SOwen Pan
2543533fbae8SOwen Pan assert(LeftBrace->is(tok::l_brace));
2544533fbae8SOwen Pan
2545533fbae8SOwen Pan FormatToken *RightBrace = LeftBrace->MatchingParen;
2546533fbae8SOwen Pan if (!RightBrace) {
2547533fbae8SOwen Pan assert(!LeftBrace->Optional);
2548533fbae8SOwen Pan return;
2549533fbae8SOwen Pan }
2550533fbae8SOwen Pan
2551533fbae8SOwen Pan assert(RightBrace->is(tok::r_brace));
2552533fbae8SOwen Pan assert(RightBrace->MatchingParen == LeftBrace);
2553533fbae8SOwen Pan assert(LeftBrace->Optional == RightBrace->Optional);
2554533fbae8SOwen Pan
2555533fbae8SOwen Pan LeftBrace->Optional = true;
2556533fbae8SOwen Pan RightBrace->Optional = true;
2557533fbae8SOwen Pan }
2558533fbae8SOwen Pan
handleAttributes()25594e88cb68SMarek Kurdej void UnwrappedLineParser::handleAttributes() {
25609cf4b726SMarek Kurdej // Handle AttributeMacro, e.g. `if (x) UNLIKELY`.
25619cf4b726SMarek Kurdej if (FormatTok->is(TT_AttributeMacro))
25629cf4b726SMarek Kurdej nextToken();
25634e88cb68SMarek Kurdej handleCppAttributes();
25644e88cb68SMarek Kurdej }
2565596fa2d9SMarek Kurdej
handleCppAttributes()25664e88cb68SMarek Kurdej bool UnwrappedLineParser::handleCppAttributes() {
25674e88cb68SMarek Kurdej // Handle [[likely]] / [[unlikely]] attributes.
25684e88cb68SMarek Kurdej if (FormatTok->is(tok::l_square) && tryToParseSimpleAttribute()) {
25694e88cb68SMarek Kurdej parseSquare();
25704e88cb68SMarek Kurdej return true;
25714e88cb68SMarek Kurdej }
25724e88cb68SMarek Kurdej return false;
25734e88cb68SMarek Kurdej }
25744e88cb68SMarek Kurdej
parseIfThenElse(IfStmtKind * IfKind,bool KeepBraces)25754e88cb68SMarek Kurdej FormatToken *UnwrappedLineParser::parseIfThenElse(IfStmtKind *IfKind,
25764e88cb68SMarek Kurdej bool KeepBraces) {
2577fee4a971SMarek Kurdej assert(FormatTok->is(tok::kw_if) && "'if' expected");
2578f7935115SDaniel Jasper nextToken();
257913351fdfSMarek Kurdej if (FormatTok->is(tok::exclaim))
258013351fdfSMarek Kurdej nextToken();
25812cdabc03Sowenca
25829dffab9dSowenca bool KeepIfBraces = true;
258313351fdfSMarek Kurdej if (FormatTok->is(tok::kw_consteval)) {
258413351fdfSMarek Kurdej nextToken();
258513351fdfSMarek Kurdej } else {
2586ec90bc0eSowenca KeepIfBraces = !Style.RemoveBracesLLVM || KeepBraces;
2587fee4a971SMarek Kurdej if (FormatTok->isOneOf(tok::kw_constexpr, tok::identifier))
25886a7d5a7aSDaniel Jasper nextToken();
2589fee4a971SMarek Kurdej if (FormatTok->is(tok::l_paren))
2590f7935115SDaniel Jasper parseParens();
259113351fdfSMarek Kurdej }
25924e88cb68SMarek Kurdej handleAttributes();
2593533fbae8SOwen Pan
2594f7935115SDaniel Jasper bool NeedsUnwrappedLine = false;
2595533fbae8SOwen Pan keepAncestorBraces();
2596533fbae8SOwen Pan
2597533fbae8SOwen Pan FormatToken *IfLeftBrace = nullptr;
2598533fbae8SOwen Pan IfStmtKind IfBlockKind = IfStmtKind::NotIf;
2599533fbae8SOwen Pan
26009ed2e68cSsstwcw if (Keywords.isBlockBegin(*FormatTok, Style)) {
26019dffab9dSowenca FormatTok->setFinalizedType(TT_ControlStatementLBrace);
2602533fbae8SOwen Pan IfLeftBrace = FormatTok;
26033a33f029SAlexander Kornienko CompoundStatementIndenter Indenter(this, Style, Line->Level);
2604ec90bc0eSowenca parseBlock(/*MustBeDeclaration=*/false, /*AddLevels=*/1u,
2605ec90bc0eSowenca /*MunchSemi=*/true, KeepIfBraces, &IfBlockKind);
2606c1bc38edSDaniel Jasper if (Style.BraceWrapping.BeforeElse)
2607d3ed59aeSManuel Klimek addUnwrappedLine();
2608c1bc38edSDaniel Jasper else
2609f7935115SDaniel Jasper NeedsUnwrappedLine = true;
2610f7935115SDaniel Jasper } else {
261177e60bc4Sowenca parseUnbracedBody();
2612f7935115SDaniel Jasper }
2613533fbae8SOwen Pan
2614533fbae8SOwen Pan if (Style.RemoveBracesLLVM) {
2615533fbae8SOwen Pan assert(!NestedTooDeep.empty());
26162cdabc03Sowenca KeepIfBraces = KeepIfBraces ||
26172cdabc03Sowenca (IfLeftBrace && !IfLeftBrace->MatchingParen) ||
2618533fbae8SOwen Pan NestedTooDeep.back() || IfBlockKind == IfStmtKind::IfOnly ||
2619533fbae8SOwen Pan IfBlockKind == IfStmtKind::IfElseIf;
2620533fbae8SOwen Pan }
2621533fbae8SOwen Pan
26229dffab9dSowenca bool KeepElseBraces = KeepIfBraces;
2623533fbae8SOwen Pan FormatToken *ElseLeftBrace = nullptr;
2624533fbae8SOwen Pan IfStmtKind Kind = IfStmtKind::IfOnly;
2625533fbae8SOwen Pan
2626fee4a971SMarek Kurdej if (FormatTok->is(tok::kw_else)) {
2627533fbae8SOwen Pan if (Style.RemoveBracesLLVM) {
2628533fbae8SOwen Pan NestedTooDeep.back() = false;
2629533fbae8SOwen Pan Kind = IfStmtKind::IfElse;
2630533fbae8SOwen Pan }
2631f7935115SDaniel Jasper nextToken();
26324e88cb68SMarek Kurdej handleAttributes();
26339ed2e68cSsstwcw if (Keywords.isBlockBegin(*FormatTok, Style)) {
263405d77102Sowenca const bool FollowedByIf = Tokens->peekNextToken()->is(tok::kw_if);
26359dffab9dSowenca FormatTok->setFinalizedType(TT_ElseLBrace);
2636533fbae8SOwen Pan ElseLeftBrace = FormatTok;
26373a33f029SAlexander Kornienko CompoundStatementIndenter Indenter(this, Style, Line->Level);
26381fd6f06bSBenjamin Kramer IfStmtKind ElseBlockKind = IfStmtKind::NotIf;
26395ead1f13Sowenca FormatToken *IfLBrace =
26405221875aSowenca parseBlock(/*MustBeDeclaration=*/false, /*AddLevels=*/1u,
2641ec90bc0eSowenca /*MunchSemi=*/true, KeepElseBraces, &ElseBlockKind);
26425ead1f13Sowenca if (FormatTok->is(tok::kw_else)) {
26435ead1f13Sowenca KeepElseBraces = KeepElseBraces ||
26445ead1f13Sowenca ElseBlockKind == IfStmtKind::IfOnly ||
26455ead1f13Sowenca ElseBlockKind == IfStmtKind::IfElseIf;
264605d77102Sowenca } else if (FollowedByIf && IfLBrace && !IfLBrace->Optional) {
26475221875aSowenca KeepElseBraces = true;
26485ead1f13Sowenca assert(ElseLeftBrace->MatchingParen);
26495ead1f13Sowenca markOptionalBraces(ElseLeftBrace);
2650bebf7bdfSowenca }
2651f7935115SDaniel Jasper addUnwrappedLine();
2652fee4a971SMarek Kurdej } else if (FormatTok->is(tok::kw_if)) {
2653c9e7eec7Sowenca const FormatToken *Previous = Tokens->getPreviousToken();
2654c9e7eec7Sowenca assert(Previous);
2655c9e7eec7Sowenca const bool IsPrecededByComment = Previous->is(tok::comment);
2656533fbae8SOwen Pan if (IsPrecededByComment) {
2657ca7f4715Sowenca addUnwrappedLine();
2658ca7f4715Sowenca ++Line->Level;
2659ca7f4715Sowenca }
2660533fbae8SOwen Pan bool TooDeep = true;
2661533fbae8SOwen Pan if (Style.RemoveBracesLLVM) {
2662533fbae8SOwen Pan Kind = IfStmtKind::IfElseIf;
2663533fbae8SOwen Pan TooDeep = NestedTooDeep.pop_back_val();
2664533fbae8SOwen Pan }
26659dffab9dSowenca ElseLeftBrace = parseIfThenElse(/*IfKind=*/nullptr, KeepIfBraces);
2666533fbae8SOwen Pan if (Style.RemoveBracesLLVM)
2667533fbae8SOwen Pan NestedTooDeep.push_back(TooDeep);
2668533fbae8SOwen Pan if (IsPrecededByComment)
2669ca7f4715Sowenca --Line->Level;
2670f7935115SDaniel Jasper } else {
267177e60bc4Sowenca parseUnbracedBody(/*CheckEOF=*/true);
2672f7935115SDaniel Jasper }
2673533fbae8SOwen Pan } else {
2674533fbae8SOwen Pan KeepIfBraces = KeepIfBraces || IfBlockKind == IfStmtKind::IfElse;
2675533fbae8SOwen Pan if (NeedsUnwrappedLine)
2676f7935115SDaniel Jasper addUnwrappedLine();
2677f7935115SDaniel Jasper }
2678533fbae8SOwen Pan
2679533fbae8SOwen Pan if (!Style.RemoveBracesLLVM)
2680533fbae8SOwen Pan return nullptr;
2681533fbae8SOwen Pan
2682533fbae8SOwen Pan assert(!NestedTooDeep.empty());
26832cdabc03Sowenca KeepElseBraces = KeepElseBraces ||
26842cdabc03Sowenca (ElseLeftBrace && !ElseLeftBrace->MatchingParen) ||
26852cdabc03Sowenca NestedTooDeep.back();
2686533fbae8SOwen Pan
2687533fbae8SOwen Pan NestedTooDeep.pop_back();
2688533fbae8SOwen Pan
26899dffab9dSowenca if (!KeepIfBraces && !KeepElseBraces) {
2690533fbae8SOwen Pan markOptionalBraces(IfLeftBrace);
2691533fbae8SOwen Pan markOptionalBraces(ElseLeftBrace);
2692533fbae8SOwen Pan } else if (IfLeftBrace) {
2693533fbae8SOwen Pan FormatToken *IfRightBrace = IfLeftBrace->MatchingParen;
2694533fbae8SOwen Pan if (IfRightBrace) {
2695533fbae8SOwen Pan assert(IfRightBrace->MatchingParen == IfLeftBrace);
2696533fbae8SOwen Pan assert(!IfLeftBrace->Optional);
2697533fbae8SOwen Pan assert(!IfRightBrace->Optional);
2698533fbae8SOwen Pan IfLeftBrace->MatchingParen = nullptr;
2699533fbae8SOwen Pan IfRightBrace->MatchingParen = nullptr;
2700533fbae8SOwen Pan }
2701533fbae8SOwen Pan }
2702533fbae8SOwen Pan
2703533fbae8SOwen Pan if (IfKind)
2704533fbae8SOwen Pan *IfKind = Kind;
2705533fbae8SOwen Pan
2706533fbae8SOwen Pan return IfLeftBrace;
2707f7935115SDaniel Jasper }
2708f7935115SDaniel Jasper
parseTryCatch()270904a71a45SDaniel Jasper void UnwrappedLineParser::parseTryCatch() {
2710fac2371bSNico Weber assert(FormatTok->isOneOf(tok::kw_try, tok::kw___try) && "'try' expected");
271104a71a45SDaniel Jasper nextToken();
271204a71a45SDaniel Jasper bool NeedsUnwrappedLine = false;
271304a71a45SDaniel Jasper if (FormatTok->is(tok::colon)) {
271404a71a45SDaniel Jasper // We are in a function try block, what comes is an initializer list.
271504a71a45SDaniel Jasper nextToken();
2716709fd989SAlexander Lanin
2717709fd989SAlexander Lanin // In case identifiers were removed by clang-tidy, what might follow is
2718709fd989SAlexander Lanin // multiple commas in sequence - before the first identifier.
2719709fd989SAlexander Lanin while (FormatTok->is(tok::comma))
2720709fd989SAlexander Lanin nextToken();
2721709fd989SAlexander Lanin
272204a71a45SDaniel Jasper while (FormatTok->is(tok::identifier)) {
272304a71a45SDaniel Jasper nextToken();
272404a71a45SDaniel Jasper if (FormatTok->is(tok::l_paren))
272504a71a45SDaniel Jasper parseParens();
2726db41c0b3Smydeveloperday if (FormatTok->Previous && FormatTok->Previous->is(tok::identifier) &&
2727db41c0b3Smydeveloperday FormatTok->is(tok::l_brace)) {
2728db41c0b3Smydeveloperday do {
2729db41c0b3Smydeveloperday nextToken();
2730db41c0b3Smydeveloperday } while (!FormatTok->is(tok::r_brace));
2731db41c0b3Smydeveloperday nextToken();
2732db41c0b3Smydeveloperday }
2733709fd989SAlexander Lanin
2734709fd989SAlexander Lanin // In case identifiers were removed by clang-tidy, what might follow is
2735709fd989SAlexander Lanin // multiple commas in sequence - after the first identifier.
2736709fd989SAlexander Lanin while (FormatTok->is(tok::comma))
273704a71a45SDaniel Jasper nextToken();
273804a71a45SDaniel Jasper }
273904a71a45SDaniel Jasper }
2740e189d465SDaniel Jasper // Parse try with resource.
2741d079995dSMarek Kurdej if (Style.Language == FormatStyle::LK_Java && FormatTok->is(tok::l_paren))
2742e189d465SDaniel Jasper parseParens();
2743533fbae8SOwen Pan
2744533fbae8SOwen Pan keepAncestorBraces();
2745533fbae8SOwen Pan
274604a71a45SDaniel Jasper if (FormatTok->is(tok::l_brace)) {
274704a71a45SDaniel Jasper CompoundStatementIndenter Indenter(this, Style, Line->Level);
2748e852cc0dSowenca parseBlock();
2749d079995dSMarek Kurdej if (Style.BraceWrapping.BeforeCatch)
275004a71a45SDaniel Jasper addUnwrappedLine();
2751d079995dSMarek Kurdej else
275204a71a45SDaniel Jasper NeedsUnwrappedLine = true;
275304a71a45SDaniel Jasper } else if (!FormatTok->is(tok::kw_catch)) {
275404a71a45SDaniel Jasper // The C++ standard requires a compound-statement after a try.
275504a71a45SDaniel Jasper // If there's none, we try to assume there's a structuralElement
275604a71a45SDaniel Jasper // and try to continue.
275704a71a45SDaniel Jasper addUnwrappedLine();
275804a71a45SDaniel Jasper ++Line->Level;
275904a71a45SDaniel Jasper parseStructuralElement();
276004a71a45SDaniel Jasper --Line->Level;
276104a71a45SDaniel Jasper }
276240446663SKazu Hirata while (true) {
276333381f5eSNico Weber if (FormatTok->is(tok::at))
276433381f5eSNico Weber nextToken();
276533381f5eSNico Weber if (!(FormatTok->isOneOf(tok::kw_catch, Keywords.kw___except,
2766fac2371bSNico Weber tok::kw___finally) ||
2767142e79b8Smydeveloperday ((Style.Language == FormatStyle::LK_Java || Style.isJavaScript()) &&
276833381f5eSNico Weber FormatTok->is(Keywords.kw_finally)) ||
2769fee4a971SMarek Kurdej (FormatTok->isObjCAtKeyword(tok::objc_catch) ||
2770bebf7bdfSowenca FormatTok->isObjCAtKeyword(tok::objc_finally)))) {
277133381f5eSNico Weber break;
2772bebf7bdfSowenca }
277304a71a45SDaniel Jasper nextToken();
277404a71a45SDaniel Jasper while (FormatTok->isNot(tok::l_brace)) {
277504a71a45SDaniel Jasper if (FormatTok->is(tok::l_paren)) {
277604a71a45SDaniel Jasper parseParens();
277704a71a45SDaniel Jasper continue;
277804a71a45SDaniel Jasper }
2779533fbae8SOwen Pan if (FormatTok->isOneOf(tok::semi, tok::r_brace, tok::eof)) {
2780533fbae8SOwen Pan if (Style.RemoveBracesLLVM)
2781533fbae8SOwen Pan NestedTooDeep.pop_back();
278204a71a45SDaniel Jasper return;
2783533fbae8SOwen Pan }
278404a71a45SDaniel Jasper nextToken();
278504a71a45SDaniel Jasper }
278604a71a45SDaniel Jasper NeedsUnwrappedLine = false;
2787b58616c2SMarek Kurdej Line->MustBeDeclaration = false;
278804a71a45SDaniel Jasper CompoundStatementIndenter Indenter(this, Style, Line->Level);
2789e852cc0dSowenca parseBlock();
2790c1bc38edSDaniel Jasper if (Style.BraceWrapping.BeforeCatch)
279104a71a45SDaniel Jasper addUnwrappedLine();
2792c1bc38edSDaniel Jasper else
279304a71a45SDaniel Jasper NeedsUnwrappedLine = true;
279404a71a45SDaniel Jasper }
2795533fbae8SOwen Pan
2796533fbae8SOwen Pan if (Style.RemoveBracesLLVM)
2797533fbae8SOwen Pan NestedTooDeep.pop_back();
2798533fbae8SOwen Pan
2799c1bc38edSDaniel Jasper if (NeedsUnwrappedLine)
280004a71a45SDaniel Jasper addUnwrappedLine();
280104a71a45SDaniel Jasper }
280204a71a45SDaniel Jasper
parseNamespace()2803578fdd89SAlexander Kornienko void UnwrappedLineParser::parseNamespace() {
2804e8a301f8SFrancois Ferrand assert(FormatTok->isOneOf(tok::kw_namespace, TT_NamespaceMacro) &&
2805e8a301f8SFrancois Ferrand "'namespace' expected");
2806a043cedfSRoman Kashitsyn
2807a043cedfSRoman Kashitsyn const FormatToken &InitialToken = *FormatTok;
2808578fdd89SAlexander Kornienko nextToken();
2809e8a301f8SFrancois Ferrand if (InitialToken.is(TT_NamespaceMacro)) {
2810e8a301f8SFrancois Ferrand parseParens();
2811e8a301f8SFrancois Ferrand } else {
281237944130SNico Weber while (FormatTok->isOneOf(tok::identifier, tok::coloncolon, tok::kw_inline,
2813be570576SZequan Wu tok::l_square, tok::period, tok::l_paren) ||
2814bebf7bdfSowenca (Style.isCSharp() && FormatTok->is(tok::kw_union))) {
281537944130SNico Weber if (FormatTok->is(tok::l_square))
281637944130SNico Weber parseSquare();
2817be570576SZequan Wu else if (FormatTok->is(tok::l_paren))
2818be570576SZequan Wu parseParens();
281937944130SNico Weber else
2820578fdd89SAlexander Kornienko nextToken();
2821e8a301f8SFrancois Ferrand }
2822bebf7bdfSowenca }
2823fee4a971SMarek Kurdej if (FormatTok->is(tok::l_brace)) {
2824a043cedfSRoman Kashitsyn if (ShouldBreakBeforeBrace(Style, InitialToken))
2825a8eb9149SManuel Klimek addUnwrappedLine();
2826a8eb9149SManuel Klimek
28272a42c759SJakub Budiský unsigned AddLevels =
28282a42c759SJakub Budiský Style.NamespaceIndentation == FormatStyle::NI_All ||
282965ee3472SDaniel Jasper (Style.NamespaceIndentation == FormatStyle::NI_Inner &&
28302a42c759SJakub Budiský DeclarationScopeStack.size() > 1)
28312a42c759SJakub Budiský ? 1u
28322a42c759SJakub Budiský : 0u;
2833f7f9f94bSTim Wojtulewicz bool ManageWhitesmithsBraces =
2834f7f9f94bSTim Wojtulewicz AddLevels == 0u &&
2835f7f9f94bSTim Wojtulewicz Style.BreakBeforeBraces == FormatStyle::BS_Whitesmiths;
2836f7f9f94bSTim Wojtulewicz
2837f7f9f94bSTim Wojtulewicz // If we're in Whitesmiths mode, indent the brace if we're not indenting
2838f7f9f94bSTim Wojtulewicz // the whole block.
2839f7f9f94bSTim Wojtulewicz if (ManageWhitesmithsBraces)
2840f7f9f94bSTim Wojtulewicz ++Line->Level;
2841f7f9f94bSTim Wojtulewicz
28429dffab9dSowenca parseBlock(/*MustBeDeclaration=*/true, AddLevels, /*MunchSemi=*/true,
2843ec90bc0eSowenca /*KeepBraces=*/true, /*IfKind=*/nullptr,
2844ec90bc0eSowenca ManageWhitesmithsBraces);
2845f7f9f94bSTim Wojtulewicz
2846046b9306SManuel Klimek // Munch the semicolon after a namespace. This is more common than one would
28477d2fdd3fSJonathan Coe // think. Putting the semicolon into its own line is very ugly.
2848fee4a971SMarek Kurdej if (FormatTok->is(tok::semi))
2849046b9306SManuel Klimek nextToken();
2850f7f9f94bSTim Wojtulewicz
2851f7f9f94bSTim Wojtulewicz addUnwrappedLine(AddLevels > 0 ? LineLevel::Remove : LineLevel::Keep);
2852f7f9f94bSTim Wojtulewicz
2853f7f9f94bSTim Wojtulewicz if (ManageWhitesmithsBraces)
2854f7f9f94bSTim Wojtulewicz --Line->Level;
2855578fdd89SAlexander Kornienko }
2856578fdd89SAlexander Kornienko // FIXME: Add error handling.
2857578fdd89SAlexander Kornienko }
2858578fdd89SAlexander Kornienko
parseNew()28596acf5130SDaniel Jasper void UnwrappedLineParser::parseNew() {
28606acf5130SDaniel Jasper assert(FormatTok->is(tok::kw_new) && "'new' expected");
28616acf5130SDaniel Jasper nextToken();
28627d2fdd3fSJonathan Coe
28637d2fdd3fSJonathan Coe if (Style.isCSharp()) {
28647d2fdd3fSJonathan Coe do {
28657d2fdd3fSJonathan Coe if (FormatTok->is(tok::l_brace))
28667d2fdd3fSJonathan Coe parseBracedList();
28677d2fdd3fSJonathan Coe
28687d2fdd3fSJonathan Coe if (FormatTok->isOneOf(tok::semi, tok::comma))
28697d2fdd3fSJonathan Coe return;
28707d2fdd3fSJonathan Coe
28717d2fdd3fSJonathan Coe nextToken();
28727d2fdd3fSJonathan Coe } while (!eof());
28737d2fdd3fSJonathan Coe }
28747d2fdd3fSJonathan Coe
28756acf5130SDaniel Jasper if (Style.Language != FormatStyle::LK_Java)
28766acf5130SDaniel Jasper return;
28776acf5130SDaniel Jasper
28786acf5130SDaniel Jasper // In Java, we can parse everything up to the parens, which aren't optional.
28796acf5130SDaniel Jasper do {
28806acf5130SDaniel Jasper // There should not be a ;, { or } before the new's open paren.
28816acf5130SDaniel Jasper if (FormatTok->isOneOf(tok::semi, tok::l_brace, tok::r_brace))
28826acf5130SDaniel Jasper return;
28836acf5130SDaniel Jasper
28846acf5130SDaniel Jasper // Consume the parens.
28856acf5130SDaniel Jasper if (FormatTok->is(tok::l_paren)) {
28866acf5130SDaniel Jasper parseParens();
28876acf5130SDaniel Jasper
28886acf5130SDaniel Jasper // If there is a class body of an anonymous class, consume that as child.
28896acf5130SDaniel Jasper if (FormatTok->is(tok::l_brace))
28906acf5130SDaniel Jasper parseChildBlock();
28916acf5130SDaniel Jasper return;
28926acf5130SDaniel Jasper }
28936acf5130SDaniel Jasper nextToken();
28946acf5130SDaniel Jasper } while (!eof());
28956acf5130SDaniel Jasper }
28966acf5130SDaniel Jasper
parseLoopBody(bool KeepBraces,bool WrapRightBrace)28979dffab9dSowenca void UnwrappedLineParser::parseLoopBody(bool KeepBraces, bool WrapRightBrace) {
289843c146c9Ssstwcw keepAncestorBraces();
289943c146c9Ssstwcw
29009ed2e68cSsstwcw if (Keywords.isBlockBegin(*FormatTok, Style)) {
29019dffab9dSowenca if (!KeepBraces)
29029dffab9dSowenca FormatTok->setFinalizedType(TT_ControlStatementLBrace);
290343c146c9Ssstwcw FormatToken *LeftBrace = FormatTok;
290443c146c9Ssstwcw CompoundStatementIndenter Indenter(this, Style, Line->Level);
29059dffab9dSowenca parseBlock(/*MustBeDeclaration=*/false, /*AddLevels=*/1u,
29069dffab9dSowenca /*MunchSemi=*/true, KeepBraces);
29079dffab9dSowenca if (!KeepBraces) {
290843c146c9Ssstwcw assert(!NestedTooDeep.empty());
290943c146c9Ssstwcw if (!NestedTooDeep.back())
291043c146c9Ssstwcw markOptionalBraces(LeftBrace);
291143c146c9Ssstwcw }
291243c146c9Ssstwcw if (WrapRightBrace)
291343c146c9Ssstwcw addUnwrappedLine();
291443c146c9Ssstwcw } else {
291543c146c9Ssstwcw parseUnbracedBody();
291643c146c9Ssstwcw }
291743c146c9Ssstwcw
29189dffab9dSowenca if (!KeepBraces)
291943c146c9Ssstwcw NestedTooDeep.pop_back();
292043c146c9Ssstwcw }
292143c146c9Ssstwcw
parseForOrWhileLoop()292237d6c94eSAlexander Kornienko void UnwrappedLineParser::parseForOrWhileLoop() {
292366cb8c50SDaniel Jasper assert(FormatTok->isOneOf(tok::kw_for, tok::kw_while, TT_ForEachMacro) &&
2924e1e4319aSDaniel Jasper "'for', 'while' or foreach macro expected");
29259dffab9dSowenca const bool KeepBraces = !Style.RemoveBracesLLVM ||
29269dffab9dSowenca !FormatTok->isOneOf(tok::kw_for, tok::kw_while);
29279dffab9dSowenca
292837d6c94eSAlexander Kornienko nextToken();
2929a050f41cSMartin Probst // JS' for await ( ...
2930142e79b8Smydeveloperday if (Style.isJavaScript() && FormatTok->is(Keywords.kw_await))
2931bd49e321SMartin Probst nextToken();
293257b95aedSmydeveloperday if (Style.isCpp() && FormatTok->is(tok::kw_co_await))
293357b95aedSmydeveloperday nextToken();
2934fee4a971SMarek Kurdej if (FormatTok->is(tok::l_paren))
293537d6c94eSAlexander Kornienko parseParens();
2936533fbae8SOwen Pan
2937fc1c160fSowenca handleAttributes();
29389dffab9dSowenca parseLoopBody(KeepBraces, /*WrapRightBrace=*/true);
293937d6c94eSAlexander Kornienko }
294037d6c94eSAlexander Kornienko
parseDoWhile()2941f7935115SDaniel Jasper void UnwrappedLineParser::parseDoWhile() {
2942fee4a971SMarek Kurdej assert(FormatTok->is(tok::kw_do) && "'do' expected");
2943f7935115SDaniel Jasper nextToken();
2944533fbae8SOwen Pan
29459dffab9dSowenca parseLoopBody(/*KeepBraces=*/true, Style.BraceWrapping.BeforeWhile);
2946533fbae8SOwen Pan
29470ea8e107SAlexander Kornienko // FIXME: Add error handling.
2948fee4a971SMarek Kurdej if (!FormatTok->is(tok::kw_while)) {
29490ea8e107SAlexander Kornienko addUnwrappedLine();
29500ea8e107SAlexander Kornienko return;
29510ea8e107SAlexander Kornienko }
29520ea8e107SAlexander Kornienko
2953f7f9f94bSTim Wojtulewicz // If in Whitesmiths mode, the line with the while() needs to be indented
2954f7f9f94bSTim Wojtulewicz // to the same level as the block.
2955f7f9f94bSTim Wojtulewicz if (Style.BreakBeforeBraces == FormatStyle::BS_Whitesmiths)
2956f7f9f94bSTim Wojtulewicz ++Line->Level;
2957f7f9f94bSTim Wojtulewicz
2958f7935115SDaniel Jasper nextToken();
29596b9eeba0SManuel Klimek parseStructuralElement();
2960f7935115SDaniel Jasper }
2961f7935115SDaniel Jasper
parseLabel(bool LeftAlignLabel)29623867a2d5SPaul Hoad void UnwrappedLineParser::parseLabel(bool LeftAlignLabel) {
2963f7935115SDaniel Jasper nextToken();
296452b15154SManuel Klimek unsigned OldLineLevel = Line->Level;
2965a127512cSDaniel Jasper if (Line->Level > 1 || (!Line->InPPDirective && Line->Level > 0))
296652b15154SManuel Klimek --Line->Level;
29673867a2d5SPaul Hoad if (LeftAlignLabel)
29683867a2d5SPaul Hoad Line->Level = 0;
2969c7dcc4c7Smydeveloperday
297014c04475Smydeveloperday if (!Style.IndentCaseBlocks && CommentsBeforeNextToken.empty() &&
2971fee4a971SMarek Kurdej FormatTok->is(tok::l_brace)) {
2972c7dcc4c7Smydeveloperday
2973f7f9f94bSTim Wojtulewicz CompoundStatementIndenter Indenter(this, Line->Level,
2974f7f9f94bSTim Wojtulewicz Style.BraceWrapping.AfterCaseLabel,
2975f7f9f94bSTim Wojtulewicz Style.BraceWrapping.IndentBraces);
2976e852cc0dSowenca parseBlock();
2977fee4a971SMarek Kurdej if (FormatTok->is(tok::kw_break)) {
2978fb13e65aSPaul Hoad if (Style.BraceWrapping.AfterControlStatement ==
2979eb50838bSmydeveloperday FormatStyle::BWACS_Always) {
2980d3ed59aeSManuel Klimek addUnwrappedLine();
2981f7f9f94bSTim Wojtulewicz if (!Style.IndentCaseBlocks &&
2982bebf7bdfSowenca Style.BreakBeforeBraces == FormatStyle::BS_Whitesmiths) {
2983359b4e6cSMarek Kurdej ++Line->Level;
2984eb50838bSmydeveloperday }
2985bebf7bdfSowenca }
2986d3ed59aeSManuel Klimek parseStructuralElement();
2987d3ed59aeSManuel Klimek }
2988f7935115SDaniel Jasper addUnwrappedLine();
29893a33f029SAlexander Kornienko } else {
29901fe0d5caSDaniel Jasper if (FormatTok->is(tok::semi))
29911fe0d5caSDaniel Jasper nextToken();
29923a33f029SAlexander Kornienko addUnwrappedLine();
29933a33f029SAlexander Kornienko }
299452b15154SManuel Klimek Line->Level = OldLineLevel;
29952cce7b72SDaniel Jasper if (FormatTok->isNot(tok::l_brace)) {
299640609472SDaniel Jasper parseStructuralElement();
29972cce7b72SDaniel Jasper addUnwrappedLine();
29982cce7b72SDaniel Jasper }
2999f7935115SDaniel Jasper }
3000f7935115SDaniel Jasper
parseCaseLabel()3001f7935115SDaniel Jasper void UnwrappedLineParser::parseCaseLabel() {
3002fee4a971SMarek Kurdej assert(FormatTok->is(tok::kw_case) && "'case' expected");
3003c7dcc4c7Smydeveloperday
3004f7935115SDaniel Jasper // FIXME: fix handling of complex expressions here.
3005f7935115SDaniel Jasper do {
3006f7935115SDaniel Jasper nextToken();
3007fee4a971SMarek Kurdej } while (!eof() && !FormatTok->is(tok::colon));
3008f7935115SDaniel Jasper parseLabel();
3009f7935115SDaniel Jasper }
3010f7935115SDaniel Jasper
parseSwitch()3011f7935115SDaniel Jasper void UnwrappedLineParser::parseSwitch() {
3012fee4a971SMarek Kurdej assert(FormatTok->is(tok::kw_switch) && "'switch' expected");
3013f7935115SDaniel Jasper nextToken();
3014fee4a971SMarek Kurdej if (FormatTok->is(tok::l_paren))
3015f7935115SDaniel Jasper parseParens();
3016533fbae8SOwen Pan
3017533fbae8SOwen Pan keepAncestorBraces();
3018533fbae8SOwen Pan
3019fee4a971SMarek Kurdej if (FormatTok->is(tok::l_brace)) {
30203a33f029SAlexander Kornienko CompoundStatementIndenter Indenter(this, Style, Line->Level);
3021e852cc0dSowenca parseBlock();
3022f7935115SDaniel Jasper addUnwrappedLine();
3023f7935115SDaniel Jasper } else {
3024f7935115SDaniel Jasper addUnwrappedLine();
3025516d7971SDaniel Jasper ++Line->Level;
30266b9eeba0SManuel Klimek parseStructuralElement();
3027516d7971SDaniel Jasper --Line->Level;
3028f7935115SDaniel Jasper }
3029533fbae8SOwen Pan
3030533fbae8SOwen Pan if (Style.RemoveBracesLLVM)
3031533fbae8SOwen Pan NestedTooDeep.pop_back();
3032f7935115SDaniel Jasper }
3033f7935115SDaniel Jasper
3034a887b95eSBenjamin Kramer // Operators that can follow a C variable.
isCOperatorFollowingVar(tok::TokenKind kind)3035a887b95eSBenjamin Kramer static bool isCOperatorFollowingVar(tok::TokenKind kind) {
3036a887b95eSBenjamin Kramer switch (kind) {
3037a887b95eSBenjamin Kramer case tok::ampamp:
3038a887b95eSBenjamin Kramer case tok::ampequal:
3039a887b95eSBenjamin Kramer case tok::arrow:
3040a887b95eSBenjamin Kramer case tok::caret:
3041a887b95eSBenjamin Kramer case tok::caretequal:
3042a887b95eSBenjamin Kramer case tok::comma:
3043a887b95eSBenjamin Kramer case tok::ellipsis:
3044a887b95eSBenjamin Kramer case tok::equal:
3045a887b95eSBenjamin Kramer case tok::equalequal:
3046a887b95eSBenjamin Kramer case tok::exclaim:
3047a887b95eSBenjamin Kramer case tok::exclaimequal:
3048a887b95eSBenjamin Kramer case tok::greater:
3049a887b95eSBenjamin Kramer case tok::greaterequal:
3050a887b95eSBenjamin Kramer case tok::greatergreater:
3051a887b95eSBenjamin Kramer case tok::greatergreaterequal:
3052a887b95eSBenjamin Kramer case tok::l_paren:
3053a887b95eSBenjamin Kramer case tok::l_square:
3054a887b95eSBenjamin Kramer case tok::less:
3055a887b95eSBenjamin Kramer case tok::lessequal:
3056a887b95eSBenjamin Kramer case tok::lessless:
3057a887b95eSBenjamin Kramer case tok::lesslessequal:
3058a887b95eSBenjamin Kramer case tok::minus:
3059a887b95eSBenjamin Kramer case tok::minusequal:
3060a887b95eSBenjamin Kramer case tok::minusminus:
3061a887b95eSBenjamin Kramer case tok::percent:
3062a887b95eSBenjamin Kramer case tok::percentequal:
3063a887b95eSBenjamin Kramer case tok::period:
3064a887b95eSBenjamin Kramer case tok::pipe:
3065a887b95eSBenjamin Kramer case tok::pipeequal:
3066a887b95eSBenjamin Kramer case tok::pipepipe:
3067a887b95eSBenjamin Kramer case tok::plus:
3068a887b95eSBenjamin Kramer case tok::plusequal:
3069a887b95eSBenjamin Kramer case tok::plusplus:
3070a887b95eSBenjamin Kramer case tok::question:
3071a887b95eSBenjamin Kramer case tok::r_brace:
3072a887b95eSBenjamin Kramer case tok::r_paren:
3073a887b95eSBenjamin Kramer case tok::r_square:
3074a887b95eSBenjamin Kramer case tok::semi:
3075a887b95eSBenjamin Kramer case tok::slash:
3076a887b95eSBenjamin Kramer case tok::slashequal:
3077a887b95eSBenjamin Kramer case tok::star:
3078a887b95eSBenjamin Kramer case tok::starequal:
3079a887b95eSBenjamin Kramer return true;
3080a887b95eSBenjamin Kramer default:
3081a887b95eSBenjamin Kramer return false;
3082a887b95eSBenjamin Kramer }
3083a887b95eSBenjamin Kramer }
3084a887b95eSBenjamin Kramer
parseAccessSpecifier()3085f7935115SDaniel Jasper void UnwrappedLineParser::parseAccessSpecifier() {
3086d1aed486SPhilip Sigillito FormatToken *AccessSpecifierCandidate = FormatTok;
3087f7935115SDaniel Jasper nextToken();
308884c47a10SDaniel Jasper // Understand Qt's slots.
308953395406SDaniel Jasper if (FormatTok->isOneOf(Keywords.kw_slots, Keywords.kw_qslots))
309084c47a10SDaniel Jasper nextToken();
30912ca766f3SAlexander Kornienko // Otherwise, we don't know what it is, and we'd better keep the next token.
3092fee4a971SMarek Kurdej if (FormatTok->is(tok::colon)) {
3093f7935115SDaniel Jasper nextToken();
3094f7935115SDaniel Jasper addUnwrappedLine();
3095fee4a971SMarek Kurdej } else if (!FormatTok->is(tok::coloncolon) &&
3096a887b95eSBenjamin Kramer !isCOperatorFollowingVar(FormatTok->Tok.getKind())) {
3097d1aed486SPhilip Sigillito // Not a variable name nor namespace name.
3098d1aed486SPhilip Sigillito addUnwrappedLine();
3099d1aed486SPhilip Sigillito } else if (AccessSpecifierCandidate) {
3100d1aed486SPhilip Sigillito // Consider the access specifier to be a C identifier.
3101d1aed486SPhilip Sigillito AccessSpecifierCandidate->Tok.setKind(tok::identifier);
3102d1aed486SPhilip Sigillito }
3103f7935115SDaniel Jasper }
3104f7935115SDaniel Jasper
31059aab0db1SBjörn Schäpers /// \brief Parses a concept definition.
31069aab0db1SBjörn Schäpers /// \pre The current token has to be the concept keyword.
31079aab0db1SBjörn Schäpers ///
31089aab0db1SBjörn Schäpers /// Returns if either the concept has been completely parsed, or if it detects
31099aab0db1SBjörn Schäpers /// that the concept definition is incorrect.
parseConcept()3110840e651dSmydeveloperday void UnwrappedLineParser::parseConcept() {
3111fee4a971SMarek Kurdej assert(FormatTok->is(tok::kw_concept) && "'concept' expected");
3112840e651dSmydeveloperday nextToken();
3113fee4a971SMarek Kurdej if (!FormatTok->is(tok::identifier))
3114840e651dSmydeveloperday return;
3115840e651dSmydeveloperday nextToken();
3116fee4a971SMarek Kurdej if (!FormatTok->is(tok::equal))
3117840e651dSmydeveloperday return;
3118840e651dSmydeveloperday nextToken();
31199aab0db1SBjörn Schäpers parseConstraintExpression();
3120fee4a971SMarek Kurdej if (FormatTok->is(tok::semi))
3121840e651dSmydeveloperday nextToken();
3122840e651dSmydeveloperday addUnwrappedLine();
3123840e651dSmydeveloperday }
3124840e651dSmydeveloperday
3125bcd1e461SBjörn Schäpers /// \brief Parses a requires, decides if it is a clause or an expression.
3126bcd1e461SBjörn Schäpers /// \pre The current token has to be the requires keyword.
3127bcd1e461SBjörn Schäpers /// \returns true if it parsed a clause.
parseRequires()3128bcd1e461SBjörn Schäpers bool clang::format::UnwrappedLineParser::parseRequires() {
3129fee4a971SMarek Kurdej assert(FormatTok->is(tok::kw_requires) && "'requires' expected");
3130bcd1e461SBjörn Schäpers auto RequiresToken = FormatTok;
3131bcd1e461SBjörn Schäpers
3132bcd1e461SBjörn Schäpers // We try to guess if it is a requires clause, or a requires expression. For
3133bcd1e461SBjörn Schäpers // that we first consume the keyword and check the next token.
3134bcd1e461SBjörn Schäpers nextToken();
3135bcd1e461SBjörn Schäpers
3136bcd1e461SBjörn Schäpers switch (FormatTok->Tok.getKind()) {
3137bcd1e461SBjörn Schäpers case tok::l_brace:
3138bcd1e461SBjörn Schäpers // This can only be an expression, never a clause.
3139bcd1e461SBjörn Schäpers parseRequiresExpression(RequiresToken);
3140bcd1e461SBjörn Schäpers return false;
3141bcd1e461SBjörn Schäpers case tok::l_paren:
3142bcd1e461SBjörn Schäpers // Clauses and expression can start with a paren, it's unclear what we have.
3143bcd1e461SBjörn Schäpers break;
3144bcd1e461SBjörn Schäpers default:
3145bcd1e461SBjörn Schäpers // All other tokens can only be a clause.
3146bcd1e461SBjörn Schäpers parseRequiresClause(RequiresToken);
3147bcd1e461SBjörn Schäpers return true;
3148bcd1e461SBjörn Schäpers }
3149bcd1e461SBjörn Schäpers
3150bcd1e461SBjörn Schäpers // Looking forward we would have to decide if there are function declaration
3151bcd1e461SBjörn Schäpers // like arguments to the requires expression:
3152bcd1e461SBjörn Schäpers // requires (T t) {
3153bcd1e461SBjörn Schäpers // Or there is a constraint expression for the requires clause:
3154bcd1e461SBjörn Schäpers // requires (C<T> && ...
3155bcd1e461SBjörn Schäpers
3156bcd1e461SBjörn Schäpers // But first let's look behind.
3157bcd1e461SBjörn Schäpers auto *PreviousNonComment = RequiresToken->getPreviousNonComment();
3158bcd1e461SBjörn Schäpers
3159bcd1e461SBjörn Schäpers if (!PreviousNonComment ||
3160bcd1e461SBjörn Schäpers PreviousNonComment->is(TT_RequiresExpressionLBrace)) {
3161bcd1e461SBjörn Schäpers // If there is no token, or an expression left brace, we are a requires
3162bcd1e461SBjörn Schäpers // clause within a requires expression.
3163bcd1e461SBjörn Schäpers parseRequiresClause(RequiresToken);
3164bcd1e461SBjörn Schäpers return true;
3165bcd1e461SBjörn Schäpers }
3166bcd1e461SBjörn Schäpers
3167bcd1e461SBjörn Schäpers switch (PreviousNonComment->Tok.getKind()) {
3168bcd1e461SBjörn Schäpers case tok::greater:
3169bcd1e461SBjörn Schäpers case tok::r_paren:
3170bcd1e461SBjörn Schäpers case tok::kw_noexcept:
3171bcd1e461SBjörn Schäpers case tok::kw_const:
3172bcd1e461SBjörn Schäpers // This is a requires clause.
3173bcd1e461SBjörn Schäpers parseRequiresClause(RequiresToken);
3174bcd1e461SBjörn Schäpers return true;
3175bcd1e461SBjörn Schäpers case tok::amp:
3176bcd1e461SBjörn Schäpers case tok::ampamp: {
3177bcd1e461SBjörn Schäpers // This can be either:
3178bcd1e461SBjörn Schäpers // if (... && requires (T t) ...)
3179bcd1e461SBjörn Schäpers // Or
3180bcd1e461SBjörn Schäpers // void member(...) && requires (C<T> ...
3181bcd1e461SBjörn Schäpers // We check the one token before that for a const:
3182bcd1e461SBjörn Schäpers // void member(...) const && requires (C<T> ...
3183bcd1e461SBjörn Schäpers auto PrevPrev = PreviousNonComment->getPreviousNonComment();
3184bcd1e461SBjörn Schäpers if (PrevPrev && PrevPrev->is(tok::kw_const)) {
3185bcd1e461SBjörn Schäpers parseRequiresClause(RequiresToken);
3186bcd1e461SBjörn Schäpers return true;
3187bcd1e461SBjörn Schäpers }
3188bcd1e461SBjörn Schäpers break;
3189bcd1e461SBjörn Schäpers }
3190bcd1e461SBjörn Schäpers default:
3191b3aeca39SBjörn Schäpers if (PreviousNonComment->isTypeOrIdentifier()) {
3192b3aeca39SBjörn Schäpers // This is a requires clause.
3193b3aeca39SBjörn Schäpers parseRequiresClause(RequiresToken);
3194b3aeca39SBjörn Schäpers return true;
3195b3aeca39SBjörn Schäpers }
3196bcd1e461SBjörn Schäpers // It's an expression.
3197bcd1e461SBjörn Schäpers parseRequiresExpression(RequiresToken);
3198bcd1e461SBjörn Schäpers return false;
3199bcd1e461SBjörn Schäpers }
3200bcd1e461SBjörn Schäpers
3201bcd1e461SBjörn Schäpers // Now we look forward and try to check if the paren content is a parameter
3202bcd1e461SBjörn Schäpers // list. The parameters can be cv-qualified and contain references or
3203bcd1e461SBjörn Schäpers // pointers.
3204bcd1e461SBjörn Schäpers // So we want basically to check for TYPE NAME, but TYPE can contain all kinds
3205bcd1e461SBjörn Schäpers // of stuff: typename, const, *, &, &&, ::, identifiers.
3206bcd1e461SBjörn Schäpers
3207bcd1e461SBjörn Schäpers int NextTokenOffset = 1;
3208bcd1e461SBjörn Schäpers auto NextToken = Tokens->peekNextToken(NextTokenOffset);
3209bcd1e461SBjörn Schäpers auto PeekNext = [&NextTokenOffset, &NextToken, this] {
3210bcd1e461SBjörn Schäpers ++NextTokenOffset;
3211bcd1e461SBjörn Schäpers NextToken = Tokens->peekNextToken(NextTokenOffset);
3212bcd1e461SBjörn Schäpers };
3213bcd1e461SBjörn Schäpers
3214bcd1e461SBjörn Schäpers bool FoundType = false;
3215bcd1e461SBjörn Schäpers bool LastWasColonColon = false;
3216bcd1e461SBjörn Schäpers int OpenAngles = 0;
3217bcd1e461SBjörn Schäpers
3218bcd1e461SBjörn Schäpers for (; NextTokenOffset < 50; PeekNext()) {
3219bcd1e461SBjörn Schäpers switch (NextToken->Tok.getKind()) {
3220bcd1e461SBjörn Schäpers case tok::kw_volatile:
3221bcd1e461SBjörn Schäpers case tok::kw_const:
3222bcd1e461SBjörn Schäpers case tok::comma:
3223bcd1e461SBjörn Schäpers parseRequiresExpression(RequiresToken);
3224bcd1e461SBjörn Schäpers return false;
3225bcd1e461SBjörn Schäpers case tok::r_paren:
3226bcd1e461SBjörn Schäpers case tok::pipepipe:
3227bcd1e461SBjörn Schäpers parseRequiresClause(RequiresToken);
3228bcd1e461SBjörn Schäpers return true;
3229bcd1e461SBjörn Schäpers case tok::eof:
3230bcd1e461SBjörn Schäpers // Break out of the loop.
3231bcd1e461SBjörn Schäpers NextTokenOffset = 50;
3232bcd1e461SBjörn Schäpers break;
3233bcd1e461SBjörn Schäpers case tok::coloncolon:
3234bcd1e461SBjörn Schäpers LastWasColonColon = true;
3235bcd1e461SBjörn Schäpers break;
3236bcd1e461SBjörn Schäpers case tok::identifier:
3237bcd1e461SBjörn Schäpers if (FoundType && !LastWasColonColon && OpenAngles == 0) {
3238bcd1e461SBjörn Schäpers parseRequiresExpression(RequiresToken);
3239bcd1e461SBjörn Schäpers return false;
3240bcd1e461SBjörn Schäpers }
3241bcd1e461SBjörn Schäpers FoundType = true;
3242bcd1e461SBjörn Schäpers LastWasColonColon = false;
3243bcd1e461SBjörn Schäpers break;
3244bcd1e461SBjörn Schäpers case tok::less:
3245bcd1e461SBjörn Schäpers ++OpenAngles;
3246bcd1e461SBjörn Schäpers break;
3247bcd1e461SBjörn Schäpers case tok::greater:
3248bcd1e461SBjörn Schäpers --OpenAngles;
3249bcd1e461SBjörn Schäpers break;
3250bcd1e461SBjörn Schäpers default:
3251bcd1e461SBjörn Schäpers if (NextToken->isSimpleTypeSpecifier()) {
3252bcd1e461SBjörn Schäpers parseRequiresExpression(RequiresToken);
3253bcd1e461SBjörn Schäpers return false;
3254bcd1e461SBjörn Schäpers }
3255bcd1e461SBjörn Schäpers break;
3256bcd1e461SBjörn Schäpers }
3257bcd1e461SBjörn Schäpers }
3258bcd1e461SBjörn Schäpers
3259bcd1e461SBjörn Schäpers // This seems to be a complicated expression, just assume it's a clause.
3260bcd1e461SBjörn Schäpers parseRequiresClause(RequiresToken);
3261bcd1e461SBjörn Schäpers return true;
3262bcd1e461SBjörn Schäpers }
3263bcd1e461SBjörn Schäpers
32649aab0db1SBjörn Schäpers /// \brief Parses a requires clause.
3265bcd1e461SBjörn Schäpers /// \param RequiresToken The requires keyword token, which starts this clause.
3266bcd1e461SBjörn Schäpers /// \pre We need to be on the next token after the requires keyword.
32679aab0db1SBjörn Schäpers /// \sa parseRequiresExpression
32689aab0db1SBjörn Schäpers ///
32699aab0db1SBjörn Schäpers /// Returns if it either has finished parsing the clause, or it detects, that
32709aab0db1SBjörn Schäpers /// the clause is incorrect.
parseRequiresClause(FormatToken * RequiresToken)3271bcd1e461SBjörn Schäpers void UnwrappedLineParser::parseRequiresClause(FormatToken *RequiresToken) {
3272bcd1e461SBjörn Schäpers assert(FormatTok->getPreviousNonComment() == RequiresToken);
3273fee4a971SMarek Kurdej assert(RequiresToken->is(tok::kw_requires) && "'requires' expected");
3274840e651dSmydeveloperday
32759aab0db1SBjörn Schäpers // If there is no previous token, we are within a requires expression,
32769aab0db1SBjörn Schäpers // otherwise we will always have the template or function declaration in front
32779aab0db1SBjörn Schäpers // of it.
32789aab0db1SBjörn Schäpers bool InRequiresExpression =
3279bcd1e461SBjörn Schäpers !RequiresToken->Previous ||
3280bcd1e461SBjörn Schäpers RequiresToken->Previous->is(TT_RequiresExpressionLBrace);
32819aab0db1SBjörn Schäpers
32821e7cc72aSBjörn Schäpers RequiresToken->setFinalizedType(InRequiresExpression
32839aab0db1SBjörn Schäpers ? TT_RequiresClauseInARequiresExpression
32849aab0db1SBjörn Schäpers : TT_RequiresClause);
32859aab0db1SBjörn Schäpers
32869aab0db1SBjörn Schäpers parseConstraintExpression();
32879aab0db1SBjörn Schäpers
32889aab0db1SBjörn Schäpers if (!InRequiresExpression)
32899aab0db1SBjörn Schäpers FormatTok->Previous->ClosesRequiresClause = true;
3290840e651dSmydeveloperday }
32919aab0db1SBjörn Schäpers
32929aab0db1SBjörn Schäpers /// \brief Parses a requires expression.
3293bcd1e461SBjörn Schäpers /// \param RequiresToken The requires keyword token, which starts this clause.
3294bcd1e461SBjörn Schäpers /// \pre We need to be on the next token after the requires keyword.
32959aab0db1SBjörn Schäpers /// \sa parseRequiresClause
32969aab0db1SBjörn Schäpers ///
32979aab0db1SBjörn Schäpers /// Returns if it either has finished parsing the expression, or it detects,
32989aab0db1SBjörn Schäpers /// that the expression is incorrect.
parseRequiresExpression(FormatToken * RequiresToken)3299bcd1e461SBjörn Schäpers void UnwrappedLineParser::parseRequiresExpression(FormatToken *RequiresToken) {
3300bcd1e461SBjörn Schäpers assert(FormatTok->getPreviousNonComment() == RequiresToken);
3301fee4a971SMarek Kurdej assert(RequiresToken->is(tok::kw_requires) && "'requires' expected");
33029aab0db1SBjörn Schäpers
33031e7cc72aSBjörn Schäpers RequiresToken->setFinalizedType(TT_RequiresExpression);
3304840e651dSmydeveloperday
33059aab0db1SBjörn Schäpers if (FormatTok->is(tok::l_paren)) {
33061e7cc72aSBjörn Schäpers FormatTok->setFinalizedType(TT_RequiresExpressionLParen);
33079aab0db1SBjörn Schäpers parseParens();
33089aab0db1SBjörn Schäpers }
33099aab0db1SBjörn Schäpers
33109aab0db1SBjörn Schäpers if (FormatTok->is(tok::l_brace)) {
33111e7cc72aSBjörn Schäpers FormatTok->setFinalizedType(TT_RequiresExpressionLBrace);
33129aab0db1SBjörn Schäpers parseChildBlock(/*CanContainBracedList=*/false,
33139aab0db1SBjörn Schäpers /*NextLBracesType=*/TT_CompoundRequirementLBrace);
33149aab0db1SBjörn Schäpers }
33159aab0db1SBjörn Schäpers }
33169aab0db1SBjörn Schäpers
33179aab0db1SBjörn Schäpers /// \brief Parses a constraint expression.
33189aab0db1SBjörn Schäpers ///
33199aab0db1SBjörn Schäpers /// This is either the definition of a concept, or the body of a requires
33209aab0db1SBjörn Schäpers /// clause. It returns, when the parsing is complete, or the expression is
33219aab0db1SBjörn Schäpers /// incorrect.
parseConstraintExpression()33229aab0db1SBjörn Schäpers void UnwrappedLineParser::parseConstraintExpression() {
3323be9a7fddSBjörn Schäpers // The special handling for lambdas is needed since tryToParseLambda() eats a
3324be9a7fddSBjörn Schäpers // token and if a requires expression is the last part of a requires clause
3325be9a7fddSBjörn Schäpers // and followed by an attribute like [[nodiscard]] the ClosesRequiresClause is
3326be9a7fddSBjörn Schäpers // not set on the correct token. Thus we need to be aware if we even expect a
3327be9a7fddSBjörn Schäpers // lambda to be possible.
3328be9a7fddSBjörn Schäpers // template <typename T> requires requires { ... } [[nodiscard]] ...;
3329be9a7fddSBjörn Schäpers bool LambdaNextTimeAllowed = true;
33309aab0db1SBjörn Schäpers do {
3331be9a7fddSBjörn Schäpers bool LambdaThisTimeAllowed = std::exchange(LambdaNextTimeAllowed, false);
3332be9a7fddSBjörn Schäpers
33339aab0db1SBjörn Schäpers switch (FormatTok->Tok.getKind()) {
3334bcd1e461SBjörn Schäpers case tok::kw_requires: {
3335bcd1e461SBjörn Schäpers auto RequiresToken = FormatTok;
3336bcd1e461SBjörn Schäpers nextToken();
3337bcd1e461SBjörn Schäpers parseRequiresExpression(RequiresToken);
33389aab0db1SBjörn Schäpers break;
3339bcd1e461SBjörn Schäpers }
33409aab0db1SBjörn Schäpers
33419aab0db1SBjörn Schäpers case tok::l_paren:
33429aab0db1SBjörn Schäpers parseParens(/*AmpAmpTokenType=*/TT_BinaryOperator);
33439aab0db1SBjörn Schäpers break;
33449aab0db1SBjörn Schäpers
33459aab0db1SBjörn Schäpers case tok::l_square:
3346be9a7fddSBjörn Schäpers if (!LambdaThisTimeAllowed || !tryToParseLambda())
33479aab0db1SBjörn Schäpers return;
33489aab0db1SBjörn Schäpers break;
33499aab0db1SBjörn Schäpers
33509aab0db1SBjörn Schäpers case tok::kw_const:
33519aab0db1SBjörn Schäpers case tok::semi:
33529aab0db1SBjörn Schäpers case tok::kw_class:
33539aab0db1SBjörn Schäpers case tok::kw_struct:
33549aab0db1SBjörn Schäpers case tok::kw_union:
33559aab0db1SBjörn Schäpers return;
33569aab0db1SBjörn Schäpers
33579aab0db1SBjörn Schäpers case tok::l_brace:
33589aab0db1SBjörn Schäpers // Potential function body.
33599aab0db1SBjörn Schäpers return;
33609aab0db1SBjörn Schäpers
33619aab0db1SBjörn Schäpers case tok::ampamp:
33629aab0db1SBjörn Schäpers case tok::pipepipe:
33631e7cc72aSBjörn Schäpers FormatTok->setFinalizedType(TT_BinaryOperator);
33649aab0db1SBjörn Schäpers nextToken();
3365be9a7fddSBjörn Schäpers LambdaNextTimeAllowed = true;
33669aab0db1SBjörn Schäpers break;
33679aab0db1SBjörn Schäpers
3368be9a7fddSBjörn Schäpers case tok::comma:
3369be9a7fddSBjörn Schäpers case tok::comment:
3370be9a7fddSBjörn Schäpers LambdaNextTimeAllowed = LambdaThisTimeAllowed;
3371be9a7fddSBjörn Schäpers nextToken();
3372be9a7fddSBjörn Schäpers break;
3373be9a7fddSBjörn Schäpers
33749aab0db1SBjörn Schäpers case tok::kw_sizeof:
33759aab0db1SBjörn Schäpers case tok::greater:
33769aab0db1SBjörn Schäpers case tok::greaterequal:
33779aab0db1SBjörn Schäpers case tok::greatergreater:
33789aab0db1SBjörn Schäpers case tok::less:
33799aab0db1SBjörn Schäpers case tok::lessequal:
33809aab0db1SBjörn Schäpers case tok::lessless:
33819aab0db1SBjörn Schäpers case tok::equalequal:
33829aab0db1SBjörn Schäpers case tok::exclaim:
33839aab0db1SBjörn Schäpers case tok::exclaimequal:
33849aab0db1SBjörn Schäpers case tok::plus:
33859aab0db1SBjörn Schäpers case tok::minus:
33869aab0db1SBjörn Schäpers case tok::star:
33879aab0db1SBjörn Schäpers case tok::slash:
33889aab0db1SBjörn Schäpers case tok::kw_decltype:
3389be9a7fddSBjörn Schäpers LambdaNextTimeAllowed = true;
3390be9a7fddSBjörn Schäpers // Just eat them.
3391be9a7fddSBjörn Schäpers nextToken();
3392be9a7fddSBjörn Schäpers break;
3393be9a7fddSBjörn Schäpers
3394be9a7fddSBjörn Schäpers case tok::numeric_constant:
33959aab0db1SBjörn Schäpers case tok::coloncolon:
3396be9a7fddSBjörn Schäpers case tok::kw_true:
3397be9a7fddSBjörn Schäpers case tok::kw_false:
33989aab0db1SBjörn Schäpers // Just eat them.
33999aab0db1SBjörn Schäpers nextToken();
34009aab0db1SBjörn Schäpers break;
34019aab0db1SBjörn Schäpers
34029aab0db1SBjörn Schäpers case tok::kw_static_cast:
34039aab0db1SBjörn Schäpers case tok::kw_const_cast:
34049aab0db1SBjörn Schäpers case tok::kw_reinterpret_cast:
34059aab0db1SBjörn Schäpers case tok::kw_dynamic_cast:
34069aab0db1SBjörn Schäpers nextToken();
34079aab0db1SBjörn Schäpers if (!FormatTok->is(tok::less))
34089aab0db1SBjörn Schäpers return;
34099aab0db1SBjörn Schäpers
3410dab5e10eSSergey Semushin nextToken();
34119aab0db1SBjörn Schäpers parseBracedList(/*ContinueOnSemicolons=*/false, /*IsEnum=*/false,
34129aab0db1SBjörn Schäpers /*ClosingBraceKind=*/tok::greater);
34139aab0db1SBjörn Schäpers break;
34149aab0db1SBjörn Schäpers
34159aab0db1SBjörn Schäpers case tok::kw_bool:
34169aab0db1SBjörn Schäpers // bool is only allowed if it is directly followed by a paren for a cast:
34179aab0db1SBjörn Schäpers // concept C = bool(...);
34189aab0db1SBjörn Schäpers // and bool is the only type, all other types as cast must be inside a
34199aab0db1SBjörn Schäpers // cast to bool an thus are handled by the other cases.
34209aab0db1SBjörn Schäpers nextToken();
34219aab0db1SBjörn Schäpers if (FormatTok->isNot(tok::l_paren))
34229aab0db1SBjörn Schäpers return;
34239aab0db1SBjörn Schäpers parseParens();
34249aab0db1SBjörn Schäpers break;
34259aab0db1SBjörn Schäpers
34269aab0db1SBjörn Schäpers default:
34278b4d68bfSBjörn Schäpers if (!FormatTok->Tok.getIdentifierInfo()) {
34288b4d68bfSBjörn Schäpers // Identifiers are part of the default case, we check for more then
34298b4d68bfSBjörn Schäpers // tok::identifier to handle builtin type traits.
34309aab0db1SBjörn Schäpers return;
34319aab0db1SBjörn Schäpers }
34328b4d68bfSBjörn Schäpers
34338b4d68bfSBjörn Schäpers // We need to differentiate identifiers for a template deduction guide,
34348b4d68bfSBjörn Schäpers // variables, or function return types (the constraint expression has
34358b4d68bfSBjörn Schäpers // ended before that), and basically all other cases. But it's easier to
34368b4d68bfSBjörn Schäpers // check the other way around.
34378b4d68bfSBjörn Schäpers assert(FormatTok->Previous);
34388b4d68bfSBjörn Schäpers switch (FormatTok->Previous->Tok.getKind()) {
34398b4d68bfSBjörn Schäpers case tok::coloncolon: // Nested identifier.
34408b4d68bfSBjörn Schäpers case tok::ampamp: // Start of a function or variable for the
34418b4d68bfSBjörn Schäpers case tok::pipepipe: // constraint expression.
34428b4d68bfSBjörn Schäpers case tok::kw_requires: // Initial identifier of a requires clause.
34438b4d68bfSBjörn Schäpers case tok::equal: // Initial identifier of a concept declaration.
34448b4d68bfSBjörn Schäpers break;
34458b4d68bfSBjörn Schäpers default:
34468b4d68bfSBjörn Schäpers return;
34478b4d68bfSBjörn Schäpers }
34488b4d68bfSBjörn Schäpers
34498b4d68bfSBjörn Schäpers // Read identifier with optional template declaration.
34508b4d68bfSBjörn Schäpers nextToken();
3451dab5e10eSSergey Semushin if (FormatTok->is(tok::less)) {
3452dab5e10eSSergey Semushin nextToken();
34538b4d68bfSBjörn Schäpers parseBracedList(/*ContinueOnSemicolons=*/false, /*IsEnum=*/false,
34548b4d68bfSBjörn Schäpers /*ClosingBraceKind=*/tok::greater);
3455dab5e10eSSergey Semushin }
34568b4d68bfSBjörn Schäpers break;
34578b4d68bfSBjörn Schäpers }
34589aab0db1SBjörn Schäpers } while (!eof());
3459840e651dSmydeveloperday }
3460840e651dSmydeveloperday
parseEnum()34616f5a1933SDaniel Jasper bool UnwrappedLineParser::parseEnum() {
34627972b2e4SMichael Zimmermann const FormatToken &InitialToken = *FormatTok;
34637972b2e4SMichael Zimmermann
3464a88f80a1SDaniel Jasper // Won't be 'enum' for NS_ENUMs.
3465fee4a971SMarek Kurdej if (FormatTok->is(tok::kw_enum))
34662cec0191SManuel Klimek nextToken();
34676be0f55dSDaniel Jasper
34686f5a1933SDaniel Jasper // In TypeScript, "enum" can also be used as property name, e.g. in interface
34696f5a1933SDaniel Jasper // declarations. An "enum" keyword followed by a colon would be a syntax
34706f5a1933SDaniel Jasper // error and thus assume it is just an identifier.
3471142e79b8Smydeveloperday if (Style.isJavaScript() && FormatTok->isOneOf(tok::colon, tok::question))
34726f5a1933SDaniel Jasper return false;
34736f5a1933SDaniel Jasper
3474a87ba1c5SPaul Hoad // In protobuf, "enum" can be used as a field name.
3475a87ba1c5SPaul Hoad if (Style.Language == FormatStyle::LK_Proto && FormatTok->is(tok::equal))
3476a87ba1c5SPaul Hoad return false;
3477a87ba1c5SPaul Hoad
34782b41a82eSDaniel Jasper // Eat up enum class ...
3479fee4a971SMarek Kurdej if (FormatTok->isOneOf(tok::kw_class, tok::kw_struct))
34802b41a82eSDaniel Jasper nextToken();
3481b5a0b854SDaniel Jasper
3482786a550bSDaniel Jasper while (FormatTok->Tok.getIdentifierInfo() ||
3483ccb68b48SDaniel Jasper FormatTok->isOneOf(tok::colon, tok::coloncolon, tok::less,
34848f70d16cSTyler Chatow tok::greater, tok::comma, tok::question,
34858f70d16cSTyler Chatow tok::l_square, tok::r_square)) {
34862cec0191SManuel Klimek nextToken();
34872cec0191SManuel Klimek // We can have macros or attributes in between 'enum' and the enum name.
3488ccb68b48SDaniel Jasper if (FormatTok->is(tok::l_paren))
34892cec0191SManuel Klimek parseParens();
34908f70d16cSTyler Chatow if (FormatTok->is(TT_AttributeSquare)) {
34918f70d16cSTyler Chatow parseSquare();
34928f70d16cSTyler Chatow // Consume the closing TT_AttributeSquare.
34938f70d16cSTyler Chatow if (FormatTok->Next && FormatTok->is(TT_AttributeSquare))
34948f70d16cSTyler Chatow nextToken();
34958f70d16cSTyler Chatow }
3496b5a0b854SDaniel Jasper if (FormatTok->is(tok::identifier)) {
34972cec0191SManuel Klimek nextToken();
3498b5a0b854SDaniel Jasper // If there are two identifiers in a row, this is likely an elaborate
3499b5a0b854SDaniel Jasper // return type. In Java, this can be "implements", etc.
35001dbc2105SDaniel Jasper if (Style.isCpp() && FormatTok->is(tok::identifier))
35016f5a1933SDaniel Jasper return false;
3502b5a0b854SDaniel Jasper }
35032cec0191SManuel Klimek }
35046be0f55dSDaniel Jasper
35056be0f55dSDaniel Jasper // Just a declaration or something is wrong.
3506ccb68b48SDaniel Jasper if (FormatTok->isNot(tok::l_brace))
35076f5a1933SDaniel Jasper return true;
35081e7cc72aSBjörn Schäpers FormatTok->setFinalizedType(TT_EnumLBrace);
3509f5acd11dSBruno Ricci FormatTok->setBlockKind(BK_Block);
35106be0f55dSDaniel Jasper
35116be0f55dSDaniel Jasper if (Style.Language == FormatStyle::LK_Java) {
35126be0f55dSDaniel Jasper // Java enums are different.
35136be0f55dSDaniel Jasper parseJavaEnumBody();
35146f5a1933SDaniel Jasper return true;
35156f5a1933SDaniel Jasper }
35166f5a1933SDaniel Jasper if (Style.Language == FormatStyle::LK_Proto) {
3517c6dd273aSDaniel Jasper parseBlock(/*MustBeDeclaration=*/true);
35186f5a1933SDaniel Jasper return true;
35196be0f55dSDaniel Jasper }
35206be0f55dSDaniel Jasper
352171616722SLuna Kirkby if (!Style.AllowShortEnumsOnASingleLine &&
3522bebf7bdfSowenca ShouldBreakBeforeBrace(Style, InitialToken)) {
3523292058a5SAaron Smith addUnwrappedLine();
3524bebf7bdfSowenca }
35256be0f55dSDaniel Jasper // Parse enum body.
352626b144ccSKrasimir Georgiev nextToken();
3527292058a5SAaron Smith if (!Style.AllowShortEnumsOnASingleLine) {
3528292058a5SAaron Smith addUnwrappedLine();
3529292058a5SAaron Smith Line->Level += 1;
3530292058a5SAaron Smith }
3531292058a5SAaron Smith bool HasError = !parseBracedList(/*ContinueOnSemicolons=*/true,
3532292058a5SAaron Smith /*IsEnum=*/true);
3533292058a5SAaron Smith if (!Style.AllowShortEnumsOnASingleLine)
3534292058a5SAaron Smith Line->Level -= 1;
353582f9df9eSDaniel Jasper if (HasError) {
3536b7150872SDaniel Jasper if (FormatTok->is(tok::semi))
3537b7150872SDaniel Jasper nextToken();
3538b7150872SDaniel Jasper addUnwrappedLine();
3539b7150872SDaniel Jasper }
35406f5a1933SDaniel Jasper return true;
35416be0f55dSDaniel Jasper
354290cf380eSDaniel Jasper // There is no addUnwrappedLine() here so that we fall through to parsing a
354390cf380eSDaniel Jasper // structural element afterwards. Thus, in "enum A {} n, m;",
35442cec0191SManuel Klimek // "} n, m;" will end up in one unwrapped line.
35456be0f55dSDaniel Jasper }
35466be0f55dSDaniel Jasper
parseStructLike()3547ec725b30SEliza Velasquez bool UnwrappedLineParser::parseStructLike() {
3548ec725b30SEliza Velasquez // parseRecord falls through and does not yet add an unwrapped line as a
3549ec725b30SEliza Velasquez // record declaration or definition can start a structural element.
3550ec725b30SEliza Velasquez parseRecord();
3551ec725b30SEliza Velasquez // This does not apply to Java, JavaScript and C#.
3552142e79b8Smydeveloperday if (Style.Language == FormatStyle::LK_Java || Style.isJavaScript() ||
3553142e79b8Smydeveloperday Style.isCSharp()) {
3554ec725b30SEliza Velasquez if (FormatTok->is(tok::semi))
3555ec725b30SEliza Velasquez nextToken();
3556ec725b30SEliza Velasquez addUnwrappedLine();
3557ec725b30SEliza Velasquez return true;
3558ec725b30SEliza Velasquez }
3559ec725b30SEliza Velasquez return false;
3560ec725b30SEliza Velasquez }
3561ec725b30SEliza Velasquez
35628f1156a7Smydeveloperday namespace {
35638f1156a7Smydeveloperday // A class used to set and restore the Token position when peeking
35648f1156a7Smydeveloperday // ahead in the token source.
35658f1156a7Smydeveloperday class ScopedTokenPosition {
35668f1156a7Smydeveloperday unsigned StoredPosition;
35678f1156a7Smydeveloperday FormatTokenSource *Tokens;
35688f1156a7Smydeveloperday
35698f1156a7Smydeveloperday public:
ScopedTokenPosition(FormatTokenSource * Tokens)35708f1156a7Smydeveloperday ScopedTokenPosition(FormatTokenSource *Tokens) : Tokens(Tokens) {
35718f1156a7Smydeveloperday assert(Tokens && "Tokens expected to not be null");
35728f1156a7Smydeveloperday StoredPosition = Tokens->getPosition();
35738f1156a7Smydeveloperday }
35748f1156a7Smydeveloperday
~ScopedTokenPosition()35758f1156a7Smydeveloperday ~ScopedTokenPosition() { Tokens->setPosition(StoredPosition); }
35768f1156a7Smydeveloperday };
35778f1156a7Smydeveloperday } // namespace
35788f1156a7Smydeveloperday
35798f1156a7Smydeveloperday // Look to see if we have [[ by looking ahead, if
35808f1156a7Smydeveloperday // its not then rewind to the original position.
tryToParseSimpleAttribute()35818f1156a7Smydeveloperday bool UnwrappedLineParser::tryToParseSimpleAttribute() {
35828f1156a7Smydeveloperday ScopedTokenPosition AutoPosition(Tokens);
35838f1156a7Smydeveloperday FormatToken *Tok = Tokens->getNextToken();
35848f1156a7Smydeveloperday // We already read the first [ check for the second.
3585d079995dSMarek Kurdej if (!Tok->is(tok::l_square))
35868f1156a7Smydeveloperday return false;
35878f1156a7Smydeveloperday // Double check that the attribute is just something
35888f1156a7Smydeveloperday // fairly simple.
358984bf5e32SManuel Klimek while (Tok->isNot(tok::eof)) {
3590d079995dSMarek Kurdej if (Tok->is(tok::r_square))
35918f1156a7Smydeveloperday break;
35928f1156a7Smydeveloperday Tok = Tokens->getNextToken();
35938f1156a7Smydeveloperday }
359484bf5e32SManuel Klimek if (Tok->is(tok::eof))
359584bf5e32SManuel Klimek return false;
35968f1156a7Smydeveloperday Tok = Tokens->getNextToken();
3597d079995dSMarek Kurdej if (!Tok->is(tok::r_square))
35988f1156a7Smydeveloperday return false;
35998f1156a7Smydeveloperday Tok = Tokens->getNextToken();
3600d079995dSMarek Kurdej if (Tok->is(tok::semi))
36018f1156a7Smydeveloperday return false;
36028f1156a7Smydeveloperday return true;
36038f1156a7Smydeveloperday }
36048f1156a7Smydeveloperday
parseJavaEnumBody()36056be0f55dSDaniel Jasper void UnwrappedLineParser::parseJavaEnumBody() {
36069dffab9dSowenca assert(FormatTok->is(tok::l_brace));
36079dffab9dSowenca const FormatToken *OpeningBrace = FormatTok;
36089dffab9dSowenca
36096be0f55dSDaniel Jasper // Determine whether the enum is simple, i.e. does not have a semicolon or
36106be0f55dSDaniel Jasper // constants with class bodies. Simple enums can be formatted like braced
36116be0f55dSDaniel Jasper // lists, contracted to a single line, etc.
36126be0f55dSDaniel Jasper unsigned StoredPosition = Tokens->getPosition();
36136be0f55dSDaniel Jasper bool IsSimple = true;
36146be0f55dSDaniel Jasper FormatToken *Tok = Tokens->getNextToken();
361584bf5e32SManuel Klimek while (!Tok->is(tok::eof)) {
36166be0f55dSDaniel Jasper if (Tok->is(tok::r_brace))
36176be0f55dSDaniel Jasper break;
36186be0f55dSDaniel Jasper if (Tok->isOneOf(tok::l_brace, tok::semi)) {
36196be0f55dSDaniel Jasper IsSimple = false;
36206be0f55dSDaniel Jasper break;
36216be0f55dSDaniel Jasper }
36226be0f55dSDaniel Jasper // FIXME: This will also mark enums with braces in the arguments to enum
36236be0f55dSDaniel Jasper // constants as "not simple". This is probably fine in practice, though.
36246be0f55dSDaniel Jasper Tok = Tokens->getNextToken();
36256be0f55dSDaniel Jasper }
36266be0f55dSDaniel Jasper FormatTok = Tokens->setPosition(StoredPosition);
36276be0f55dSDaniel Jasper
36286be0f55dSDaniel Jasper if (IsSimple) {
362926b144ccSKrasimir Georgiev nextToken();
36306be0f55dSDaniel Jasper parseBracedList();
36316be0f55dSDaniel Jasper addUnwrappedLine();
36326be0f55dSDaniel Jasper return;
36336be0f55dSDaniel Jasper }
36346be0f55dSDaniel Jasper
36356be0f55dSDaniel Jasper // Parse the body of a more complex enum.
36366be0f55dSDaniel Jasper // First add a line for everything up to the "{".
36376be0f55dSDaniel Jasper nextToken();
36386be0f55dSDaniel Jasper addUnwrappedLine();
36396be0f55dSDaniel Jasper ++Line->Level;
36406be0f55dSDaniel Jasper
36416be0f55dSDaniel Jasper // Parse the enum constants.
36428bfccb96Sowenca while (FormatTok->isNot(tok::eof)) {
36436be0f55dSDaniel Jasper if (FormatTok->is(tok::l_brace)) {
36446be0f55dSDaniel Jasper // Parse the constant's class body.
36452a42c759SJakub Budiský parseBlock(/*MustBeDeclaration=*/true, /*AddLevels=*/1u,
36466be0f55dSDaniel Jasper /*MunchSemi=*/false);
36476be0f55dSDaniel Jasper } else if (FormatTok->is(tok::l_paren)) {
36486be0f55dSDaniel Jasper parseParens();
36496be0f55dSDaniel Jasper } else if (FormatTok->is(tok::comma)) {
36506be0f55dSDaniel Jasper nextToken();
36516be0f55dSDaniel Jasper addUnwrappedLine();
36526be0f55dSDaniel Jasper } else if (FormatTok->is(tok::semi)) {
36536be0f55dSDaniel Jasper nextToken();
36546be0f55dSDaniel Jasper addUnwrappedLine();
36556be0f55dSDaniel Jasper break;
36566be0f55dSDaniel Jasper } else if (FormatTok->is(tok::r_brace)) {
36576be0f55dSDaniel Jasper addUnwrappedLine();
36586be0f55dSDaniel Jasper break;
36596be0f55dSDaniel Jasper } else {
36606be0f55dSDaniel Jasper nextToken();
36616be0f55dSDaniel Jasper }
36626be0f55dSDaniel Jasper }
36636be0f55dSDaniel Jasper
36646be0f55dSDaniel Jasper // Parse the class body after the enum's ";" if any.
3665ec90bc0eSowenca parseLevel(OpeningBrace);
36666be0f55dSDaniel Jasper nextToken();
36676be0f55dSDaniel Jasper --Line->Level;
3668df2ff002SDaniel Jasper addUnwrappedLine();
36692cec0191SManuel Klimek }
3670f7935115SDaniel Jasper
parseRecord(bool ParseAsExpr)36711027fb8aSMartin Probst void UnwrappedLineParser::parseRecord(bool ParseAsExpr) {
3672a043cedfSRoman Kashitsyn const FormatToken &InitialToken = *FormatTok;
367328cacc74SManuel Klimek nextToken();
367404785d04SDaniel Jasper
3675d265090cSManuel Klimek // The actual identifier can be a nested name specifier, and in macros
3676d265090cSManuel Klimek // it is often token-pasted.
367731fd12aaSmydeveloperday // An [[attribute]] can be before the identifier.
367804785d04SDaniel Jasper while (FormatTok->isOneOf(tok::identifier, tok::coloncolon, tok::hashhash,
367904785d04SDaniel Jasper tok::kw___attribute, tok::kw___declspec,
36806189dd06Smydeveloperday tok::kw_alignas, tok::l_square, tok::r_square) ||
3681142e79b8Smydeveloperday ((Style.Language == FormatStyle::LK_Java || Style.isJavaScript()) &&
368204785d04SDaniel Jasper FormatTok->isOneOf(tok::period, tok::comma))) {
3683142e79b8Smydeveloperday if (Style.isJavaScript() &&
3684cb870c57SMartin Probst FormatTok->isOneOf(Keywords.kw_extends, Keywords.kw_implements)) {
3685cb870c57SMartin Probst // JavaScript/TypeScript supports inline object types in
3686cb870c57SMartin Probst // extends/implements positions:
3687cb870c57SMartin Probst // class Foo implements {bar: number} { }
3688cb870c57SMartin Probst nextToken();
3689cb870c57SMartin Probst if (FormatTok->is(tok::l_brace)) {
3690d96bf6eaSKrasimir Georgiev tryToParseBracedList();
3691cb870c57SMartin Probst continue;
3692cb870c57SMartin Probst }
3693cb870c57SMartin Probst }
369404785d04SDaniel Jasper bool IsNonMacroIdentifier =
369504785d04SDaniel Jasper FormatTok->is(tok::identifier) &&
369604785d04SDaniel Jasper FormatTok->TokenText != FormatTok->TokenText.upper();
3697e01bab58SManuel Klimek nextToken();
369804785d04SDaniel Jasper // We can have macros or attributes in between 'class' and the class name.
369931fd12aaSmydeveloperday if (!IsNonMacroIdentifier) {
3700fee4a971SMarek Kurdej if (FormatTok->is(tok::l_paren)) {
370104785d04SDaniel Jasper parseParens();
370231fd12aaSmydeveloperday } else if (FormatTok->is(TT_AttributeSquare)) {
370331fd12aaSmydeveloperday parseSquare();
370431fd12aaSmydeveloperday // Consume the closing TT_AttributeSquare.
370531fd12aaSmydeveloperday if (FormatTok->Next && FormatTok->is(TT_AttributeSquare))
370631fd12aaSmydeveloperday nextToken();
370731fd12aaSmydeveloperday }
370831fd12aaSmydeveloperday }
370904785d04SDaniel Jasper }
3710e01bab58SManuel Klimek
3711cdee74dbSManuel Klimek // Note that parsing away template declarations here leads to incorrectly
3712cdee74dbSManuel Klimek // accepting function declarations as record declarations.
3713cdee74dbSManuel Klimek // In general, we cannot solve this problem. Consider:
3714cdee74dbSManuel Klimek // class A<int> B() {}
3715cdee74dbSManuel Klimek // which can be a function definition or a class definition when B() is a
3716cdee74dbSManuel Klimek // macro. If we find enough real-world cases where this is a problem, we
3717cdee74dbSManuel Klimek // can parse for the 'template' keyword in the beginning of the statement,
3718cdee74dbSManuel Klimek // and thus rule out the record production in case there is no template
3719cdee74dbSManuel Klimek // (this would still leave us with an ambiguity between template function
3720cdee74dbSManuel Klimek // and class declarations).
3721adba2aadSDaniel Jasper if (FormatTok->isOneOf(tok::colon, tok::less)) {
37222507e0a2SMarek Kurdej do {
37233c883d1dSDaniel Jasper if (FormatTok->is(tok::l_brace)) {
37243c883d1dSDaniel Jasper calculateBraceTypes(/*ExpectClassBody=*/true);
37253c883d1dSDaniel Jasper if (!tryToParseBracedList())
3726adba2aadSDaniel Jasper break;
37273c883d1dSDaniel Jasper }
372872e29cafSMarek Kurdej if (FormatTok->is(tok::l_square)) {
372972e29cafSMarek Kurdej FormatToken *Previous = FormatTok->Previous;
373023fc20e0Smydeveloperday if (!Previous ||
373123fc20e0Smydeveloperday !(Previous->is(tok::r_paren) || Previous->isTypeOrIdentifier())) {
373272e29cafSMarek Kurdej // Don't try parsing a lambda if we had a closing parenthesis before,
373372e29cafSMarek Kurdej // it was probably a pointer to an array: int (*)[].
373472e29cafSMarek Kurdej if (!tryToParseLambda())
3735be5c3ca7SKrasimir Georgiev break;
37362507e0a2SMarek Kurdej } else {
37372507e0a2SMarek Kurdej parseSquare();
37382507e0a2SMarek Kurdej continue;
373972e29cafSMarek Kurdej }
374072e29cafSMarek Kurdej }
3741fee4a971SMarek Kurdej if (FormatTok->is(tok::semi))
3742e01bab58SManuel Klimek return;
3743d1b412aeSJonathan Coe if (Style.isCSharp() && FormatTok->is(Keywords.kw_where)) {
3744d1b412aeSJonathan Coe addUnwrappedLine();
3745d1b412aeSJonathan Coe nextToken();
3746d1b412aeSJonathan Coe parseCSharpGenericTypeConstraint();
3747d1b412aeSJonathan Coe break;
3748d1b412aeSJonathan Coe }
3749e01bab58SManuel Klimek nextToken();
37502507e0a2SMarek Kurdej } while (!eof());
3751e01bab58SManuel Klimek }
3752d81f003cSMarek Kurdej
3753d81f003cSMarek Kurdej auto GetBraceType = [](const FormatToken &RecordTok) {
3754d81f003cSMarek Kurdej switch (RecordTok.Tok.getKind()) {
3755d81f003cSMarek Kurdej case tok::kw_class:
3756d81f003cSMarek Kurdej return TT_ClassLBrace;
3757d81f003cSMarek Kurdej case tok::kw_struct:
3758d81f003cSMarek Kurdej return TT_StructLBrace;
3759d81f003cSMarek Kurdej case tok::kw_union:
3760d81f003cSMarek Kurdej return TT_UnionLBrace;
3761d81f003cSMarek Kurdej default:
3762d81f003cSMarek Kurdej // Useful for e.g. interface.
3763d81f003cSMarek Kurdej return TT_RecordLBrace;
3764d81f003cSMarek Kurdej }
3765d81f003cSMarek Kurdej };
3766fee4a971SMarek Kurdej if (FormatTok->is(tok::l_brace)) {
37671e7cc72aSBjörn Schäpers FormatTok->setFinalizedType(GetBraceType(InitialToken));
37681027fb8aSMartin Probst if (ParseAsExpr) {
37691027fb8aSMartin Probst parseChildBlock();
37701027fb8aSMartin Probst } else {
3771a043cedfSRoman Kashitsyn if (ShouldBreakBeforeBrace(Style, InitialToken))
3772a8eb9149SManuel Klimek addUnwrappedLine();
3773a8eb9149SManuel Klimek
37742a42c759SJakub Budiský unsigned AddLevels = Style.IndentAccessModifiers ? 2u : 1u;
37752a42c759SJakub Budiský parseBlock(/*MustBeDeclaration=*/true, AddLevels, /*MunchSemi=*/false);
3776a8eb9149SManuel Klimek }
37771027fb8aSMartin Probst }
377890cf380eSDaniel Jasper // There is no addUnwrappedLine() here so that we fall through to parsing a
377990cf380eSDaniel Jasper // structural element afterwards. Thus, in "class A {} n, m;",
378090cf380eSDaniel Jasper // "} n, m;" will end up in one unwrapped line.
378128cacc74SManuel Klimek }
378228cacc74SManuel Klimek
parseObjCMethod()3783707e68fbSBen Hamilton void UnwrappedLineParser::parseObjCMethod() {
3784fee4a971SMarek Kurdej assert(FormatTok->isOneOf(tok::l_paren, tok::identifier) &&
3785707e68fbSBen Hamilton "'(' or identifier expected.");
3786707e68fbSBen Hamilton do {
3787fee4a971SMarek Kurdej if (FormatTok->is(tok::semi)) {
3788707e68fbSBen Hamilton nextToken();
3789707e68fbSBen Hamilton addUnwrappedLine();
3790707e68fbSBen Hamilton return;
3791fee4a971SMarek Kurdej } else if (FormatTok->is(tok::l_brace)) {
379297034a36SBen Hamilton if (Style.BraceWrapping.AfterFunction)
379397034a36SBen Hamilton addUnwrappedLine();
3794e852cc0dSowenca parseBlock();
3795707e68fbSBen Hamilton addUnwrappedLine();
3796707e68fbSBen Hamilton return;
3797707e68fbSBen Hamilton } else {
3798707e68fbSBen Hamilton nextToken();
3799707e68fbSBen Hamilton }
3800707e68fbSBen Hamilton } while (!eof());
3801707e68fbSBen Hamilton }
3802707e68fbSBen Hamilton
parseObjCProtocolList()38038696a8d9SNico Weber void UnwrappedLineParser::parseObjCProtocolList() {
3804fee4a971SMarek Kurdej assert(FormatTok->is(tok::less) && "'<' expected.");
38051462e844SBen Hamilton do {
38068696a8d9SNico Weber nextToken();
38071462e844SBen Hamilton // Early exit in case someone forgot a close angle.
38081462e844SBen Hamilton if (FormatTok->isOneOf(tok::semi, tok::l_brace) ||
3809bebf7bdfSowenca FormatTok->isObjCAtKeyword(tok::objc_end)) {
38101462e844SBen Hamilton return;
3811bebf7bdfSowenca }
3812fee4a971SMarek Kurdej } while (!eof() && FormatTok->isNot(tok::greater));
38138696a8d9SNico Weber nextToken(); // Skip '>'.
38148696a8d9SNico Weber }
38158696a8d9SNico Weber
parseObjCUntilAtEnd()38168696a8d9SNico Weber void UnwrappedLineParser::parseObjCUntilAtEnd() {
38178696a8d9SNico Weber do {
3818fee4a971SMarek Kurdej if (FormatTok->isObjCAtKeyword(tok::objc_end)) {
38198696a8d9SNico Weber nextToken();
38208696a8d9SNico Weber addUnwrappedLine();
38218696a8d9SNico Weber break;
38228696a8d9SNico Weber }
3823a15da306SDaniel Jasper if (FormatTok->is(tok::l_brace)) {
3824e852cc0dSowenca parseBlock();
3825a15da306SDaniel Jasper // In ObjC interfaces, nothing should be following the "}".
3826a15da306SDaniel Jasper addUnwrappedLine();
3827e21cb742SBenjamin Kramer } else if (FormatTok->is(tok::r_brace)) {
3828e21cb742SBenjamin Kramer // Ignore stray "}". parseStructuralElement doesn't consume them.
3829e21cb742SBenjamin Kramer nextToken();
3830e21cb742SBenjamin Kramer addUnwrappedLine();
3831707e68fbSBen Hamilton } else if (FormatTok->isOneOf(tok::minus, tok::plus)) {
3832707e68fbSBen Hamilton nextToken();
3833707e68fbSBen Hamilton parseObjCMethod();
3834a15da306SDaniel Jasper } else {
38358696a8d9SNico Weber parseStructuralElement();
3836a15da306SDaniel Jasper }
38378696a8d9SNico Weber } while (!eof());
38388696a8d9SNico Weber }
38398696a8d9SNico Weber
parseObjCInterfaceOrImplementation()38402ce0ac5aSNico Weber void UnwrappedLineParser::parseObjCInterfaceOrImplementation() {
3841c068ff72SNico Weber assert(FormatTok->Tok.getObjCKeywordID() == tok::objc_interface ||
3842c068ff72SNico Weber FormatTok->Tok.getObjCKeywordID() == tok::objc_implementation);
38437eecf4b6SNico Weber nextToken();
38447eecf4b6SNico Weber nextToken(); // interface name
38457eecf4b6SNico Weber
38461462e844SBen Hamilton // @interface can be followed by a lightweight generic
38471462e844SBen Hamilton // specialization list, then either a base class or a category.
3848fee4a971SMarek Kurdej if (FormatTok->is(tok::less))
384924b52668SBen Hamilton parseObjCLightweightGenerics();
3850fee4a971SMarek Kurdej if (FormatTok->is(tok::colon)) {
385124b52668SBen Hamilton nextToken();
385224b52668SBen Hamilton nextToken(); // base class name
385324b52668SBen Hamilton // The base class can also have lightweight generics applied to it.
3854fee4a971SMarek Kurdej if (FormatTok->is(tok::less))
385524b52668SBen Hamilton parseObjCLightweightGenerics();
3856bebf7bdfSowenca } else if (FormatTok->is(tok::l_paren)) {
385724b52668SBen Hamilton // Skip category, if present.
385824b52668SBen Hamilton parseParens();
3859bebf7bdfSowenca }
386024b52668SBen Hamilton
3861fee4a971SMarek Kurdej if (FormatTok->is(tok::less))
386224b52668SBen Hamilton parseObjCProtocolList();
386324b52668SBen Hamilton
3864fee4a971SMarek Kurdej if (FormatTok->is(tok::l_brace)) {
386524b52668SBen Hamilton if (Style.BraceWrapping.AfterObjCDeclaration)
386624b52668SBen Hamilton addUnwrappedLine();
386724b52668SBen Hamilton parseBlock(/*MustBeDeclaration=*/true);
386824b52668SBen Hamilton }
386924b52668SBen Hamilton
387024b52668SBen Hamilton // With instance variables, this puts '}' on its own line. Without instance
387124b52668SBen Hamilton // variables, this ends the @interface line.
387224b52668SBen Hamilton addUnwrappedLine();
387324b52668SBen Hamilton
387424b52668SBen Hamilton parseObjCUntilAtEnd();
387524b52668SBen Hamilton }
387624b52668SBen Hamilton
parseObjCLightweightGenerics()387724b52668SBen Hamilton void UnwrappedLineParser::parseObjCLightweightGenerics() {
3878fee4a971SMarek Kurdej assert(FormatTok->is(tok::less));
38791462e844SBen Hamilton // Unlike protocol lists, generic parameterizations support
38801462e844SBen Hamilton // nested angles:
38811462e844SBen Hamilton //
38821462e844SBen Hamilton // @interface Foo<ValueType : id <NSCopying, NSSecureCoding>> :
38831462e844SBen Hamilton // NSObject <NSCopying, NSSecureCoding>
38841462e844SBen Hamilton //
38851462e844SBen Hamilton // so we need to count how many open angles we have left.
38861462e844SBen Hamilton unsigned NumOpenAngles = 1;
38871462e844SBen Hamilton do {
38881462e844SBen Hamilton nextToken();
38891462e844SBen Hamilton // Early exit in case someone forgot a close angle.
38901462e844SBen Hamilton if (FormatTok->isOneOf(tok::semi, tok::l_brace) ||
3891bebf7bdfSowenca FormatTok->isObjCAtKeyword(tok::objc_end)) {
38921462e844SBen Hamilton break;
3893bebf7bdfSowenca }
3894bebf7bdfSowenca if (FormatTok->is(tok::less)) {
38951462e844SBen Hamilton ++NumOpenAngles;
3896bebf7bdfSowenca } else if (FormatTok->is(tok::greater)) {
38971462e844SBen Hamilton assert(NumOpenAngles > 0 && "'>' makes NumOpenAngles negative");
38981462e844SBen Hamilton --NumOpenAngles;
38991462e844SBen Hamilton }
39001462e844SBen Hamilton } while (!eof() && NumOpenAngles != 0);
39011462e844SBen Hamilton nextToken(); // Skip '>'.
39021462e844SBen Hamilton }
39037eecf4b6SNico Weber
3904c068ff72SNico Weber // Returns true for the declaration/definition form of @protocol,
3905c068ff72SNico Weber // false for the expression form.
parseObjCProtocol()3906c068ff72SNico Weber bool UnwrappedLineParser::parseObjCProtocol() {
3907c068ff72SNico Weber assert(FormatTok->Tok.getObjCKeywordID() == tok::objc_protocol);
39088696a8d9SNico Weber nextToken();
3909c068ff72SNico Weber
3910bebf7bdfSowenca if (FormatTok->is(tok::l_paren)) {
3911c068ff72SNico Weber // The expression form of @protocol, e.g. "Protocol* p = @protocol(foo);".
3912c068ff72SNico Weber return false;
3913bebf7bdfSowenca }
3914c068ff72SNico Weber
3915c068ff72SNico Weber // The definition/declaration form,
3916c068ff72SNico Weber // @protocol Foo
3917c068ff72SNico Weber // - (int)someMethod;
3918c068ff72SNico Weber // @end
3919c068ff72SNico Weber
39208696a8d9SNico Weber nextToken(); // protocol name
39218696a8d9SNico Weber
3922fee4a971SMarek Kurdej if (FormatTok->is(tok::less))
39238696a8d9SNico Weber parseObjCProtocolList();
39248696a8d9SNico Weber
39258696a8d9SNico Weber // Check for protocol declaration.
3926fee4a971SMarek Kurdej if (FormatTok->is(tok::semi)) {
39278696a8d9SNico Weber nextToken();
3928c068ff72SNico Weber addUnwrappedLine();
3929c068ff72SNico Weber return true;
39308696a8d9SNico Weber }
39318696a8d9SNico Weber
39328696a8d9SNico Weber addUnwrappedLine();
39338696a8d9SNico Weber parseObjCUntilAtEnd();
3934c068ff72SNico Weber return true;
39357eecf4b6SNico Weber }
39367eecf4b6SNico Weber
parseJavaScriptEs6ImportExport()3937fca735cdSDaniel Jasper void UnwrappedLineParser::parseJavaScriptEs6ImportExport() {
3938053f1aa6SMartin Probst bool IsImport = FormatTok->is(Keywords.kw_import);
3939053f1aa6SMartin Probst assert(IsImport || FormatTok->is(tok::kw_export));
3940354aa515SDaniel Jasper nextToken();
3941fca735cdSDaniel Jasper
3942ec05fc7bSDaniel Jasper // Consume the "default" in "export default class/function".
3943668c7bb3SDaniel Jasper if (FormatTok->is(tok::kw_default))
3944668c7bb3SDaniel Jasper nextToken();
3945ec05fc7bSDaniel Jasper
39465f8445b3SMartin Probst // Consume "async function", "function" and "default function", so that these
39475f8445b3SMartin Probst // get parsed as free-standing JS functions, i.e. do not require a trailing
39485f8445b3SMartin Probst // semicolon.
39495f8445b3SMartin Probst if (FormatTok->is(Keywords.kw_async))
39505f8445b3SMartin Probst nextToken();
3951668c7bb3SDaniel Jasper if (FormatTok->is(Keywords.kw_function)) {
3952668c7bb3SDaniel Jasper nextToken();
3953668c7bb3SDaniel Jasper return;
3954668c7bb3SDaniel Jasper }
3955668c7bb3SDaniel Jasper
3956053f1aa6SMartin Probst // For imports, `export *`, `export {...}`, consume the rest of the line up
3957053f1aa6SMartin Probst // to the terminating `;`. For everything else, just return and continue
3958053f1aa6SMartin Probst // parsing the structural element, i.e. the declaration or expression for
3959053f1aa6SMartin Probst // `export default`.
3960053f1aa6SMartin Probst if (!IsImport && !FormatTok->isOneOf(tok::l_brace, tok::star) &&
3961bebf7bdfSowenca !FormatTok->isStringLiteral()) {
3962053f1aa6SMartin Probst return;
3963bebf7bdfSowenca }
3964fca735cdSDaniel Jasper
3965d40bca43SMartin Probst while (!eof()) {
3966d40bca43SMartin Probst if (FormatTok->is(tok::semi))
3967d40bca43SMartin Probst return;
3968112c2e96SKrasimir Georgiev if (Line->Tokens.empty()) {
3969d40bca43SMartin Probst // Common issue: Automatic Semicolon Insertion wrapped the line, so the
3970d40bca43SMartin Probst // import statement should terminate.
3971d40bca43SMartin Probst return;
3972d40bca43SMartin Probst }
3973354aa515SDaniel Jasper if (FormatTok->is(tok::l_brace)) {
3974f5acd11dSBruno Ricci FormatTok->setBlockKind(BK_Block);
397526b144ccSKrasimir Georgiev nextToken();
3976354aa515SDaniel Jasper parseBracedList();
3977efc1a83aSDaniel Jasper } else {
3978354aa515SDaniel Jasper nextToken();
3979354aa515SDaniel Jasper }
3980354aa515SDaniel Jasper }
3981efc1a83aSDaniel Jasper }
3982354aa515SDaniel Jasper
parseStatementMacro()39835bcf99b4SPaul Hoad void UnwrappedLineParser::parseStatementMacro() {
39846f40e21aSFrancois Ferrand nextToken();
39856f40e21aSFrancois Ferrand if (FormatTok->is(tok::l_paren))
39866f40e21aSFrancois Ferrand parseParens();
39876f40e21aSFrancois Ferrand if (FormatTok->is(tok::semi))
39886f40e21aSFrancois Ferrand nextToken();
39896f40e21aSFrancois Ferrand addUnwrappedLine();
39906f40e21aSFrancois Ferrand }
39916f40e21aSFrancois Ferrand
printDebugInfo(const UnwrappedLine & Line,StringRef Prefix="")39923b203a65SDaniel Jasper LLVM_ATTRIBUTE_UNUSED static void printDebugInfo(const UnwrappedLine &Line,
39933b203a65SDaniel Jasper StringRef Prefix = "") {
39949ad83fe7SKrasimir Georgiev llvm::dbgs() << Prefix << "Line(" << Line.Level
39959ad83fe7SKrasimir Georgiev << ", FSC=" << Line.FirstStartColumn << ")"
39969fe0e8daSDaniel Jasper << (Line.InPPDirective ? " MACRO" : "") << ": ";
399766336056SBjörn Schäpers for (const auto &Node : Line.Tokens) {
399866336056SBjörn Schäpers llvm::dbgs() << Node.Tok->Tok.getName() << "["
399966336056SBjörn Schäpers << "T=" << static_cast<unsigned>(Node.Tok->getType())
400066336056SBjörn Schäpers << ", OC=" << Node.Tok->OriginalColumn << "] ";
40019fe0e8daSDaniel Jasper }
400266336056SBjörn Schäpers for (const auto &Node : Line.Tokens)
400366336056SBjörn Schäpers for (const auto &ChildNode : Node.Children)
400466336056SBjörn Schäpers printDebugInfo(ChildNode, "\nChild: ");
400566336056SBjörn Schäpers
40069fe0e8daSDaniel Jasper llvm::dbgs() << "\n";
40079fe0e8daSDaniel Jasper }
40089fe0e8daSDaniel Jasper
addUnwrappedLine(LineLevel AdjustLevel)4009f7f9f94bSTim Wojtulewicz void UnwrappedLineParser::addUnwrappedLine(LineLevel AdjustLevel) {
4010daffc0ddSDaniel Jasper if (Line->Tokens.empty())
40117c85fde5SDaniel Jasper return;
40123538b39eSNicola Zaghen LLVM_DEBUG({
40139fe0e8daSDaniel Jasper if (CurrentLines == &Lines)
40149fe0e8daSDaniel Jasper printDebugInfo(*Line);
4015ab3dc000SManuel Klimek });
4016f7f9f94bSTim Wojtulewicz
4017f7f9f94bSTim Wojtulewicz // If this line closes a block when in Whitesmiths mode, remember that
4018f7f9f94bSTim Wojtulewicz // information so that the level can be decreased after the line is added.
4019f7f9f94bSTim Wojtulewicz // This has to happen after the addition of the line since the line itself
4020f7f9f94bSTim Wojtulewicz // needs to be indented.
4021f7f9f94bSTim Wojtulewicz bool ClosesWhitesmithsBlock =
4022f7f9f94bSTim Wojtulewicz Line->MatchingOpeningBlockLineIndex != UnwrappedLine::kInvalidIndex &&
4023f7f9f94bSTim Wojtulewicz Style.BreakBeforeBraces == FormatStyle::BS_Whitesmiths;
4024f7f9f94bSTim Wojtulewicz
4025c7551a48SBenjamin Kramer CurrentLines->push_back(std::move(*Line));
4026daffc0ddSDaniel Jasper Line->Tokens.clear();
402785c3704cSKrasimir Georgiev Line->MatchingOpeningBlockLineIndex = UnwrappedLine::kInvalidIndex;
40289ad83fe7SKrasimir Georgiev Line->FirstStartColumn = 0;
4029f7f9f94bSTim Wojtulewicz
4030f7f9f94bSTim Wojtulewicz if (ClosesWhitesmithsBlock && AdjustLevel == LineLevel::Remove)
4031f7f9f94bSTim Wojtulewicz --Line->Level;
4032d3b92fa6SManuel Klimek if (CurrentLines == &Lines && !PreprocessorDirectives.empty()) {
4033c7551a48SBenjamin Kramer CurrentLines->append(
4034c7551a48SBenjamin Kramer std::make_move_iterator(PreprocessorDirectives.begin()),
4035c7551a48SBenjamin Kramer std::make_move_iterator(PreprocessorDirectives.end()));
4036d3b92fa6SManuel Klimek PreprocessorDirectives.clear();
4037d3b92fa6SManuel Klimek }
4038e411aa85SManuel Klimek // Disconnect the current token from the last token on the previous line.
4039e411aa85SManuel Klimek FormatTok->Previous = nullptr;
4040f7935115SDaniel Jasper }
4041f7935115SDaniel Jasper
eof() const4042fee4a971SMarek Kurdej bool UnwrappedLineParser::eof() const { return FormatTok->is(tok::eof); }
4043f7935115SDaniel Jasper
isOnNewLine(const FormatToken & FormatTok)40441fcbe675SManuel Klimek bool UnwrappedLineParser::isOnNewLine(const FormatToken &FormatTok) {
40451fcbe675SManuel Klimek return (Line->InPPDirective || FormatTok.HasUnescapedNewline) &&
40461fcbe675SManuel Klimek FormatTok.NewlinesBefore > 0;
40471fcbe675SManuel Klimek }
40481fcbe675SManuel Klimek
404991834227SKrasimir Georgiev // Checks if \p FormatTok is a line comment that continues the line comment
405091834227SKrasimir Georgiev // section on \p Line.
4051b81cc603SThomas Preud'homme static bool
continuesLineCommentSection(const FormatToken & FormatTok,const UnwrappedLine & Line,const llvm::Regex & CommentPragmasRegex)4052b81cc603SThomas Preud'homme continuesLineCommentSection(const FormatToken &FormatTok,
405300c5c72dSKrasimir Georgiev const UnwrappedLine &Line,
4054b81cc603SThomas Preud'homme const llvm::Regex &CommentPragmasRegex) {
405591834227SKrasimir Georgiev if (Line.Tokens.empty())
405691834227SKrasimir Georgiev return false;
40578432161fSKrasimir Georgiev
405800c5c72dSKrasimir Georgiev StringRef IndentContent = FormatTok.TokenText;
405900c5c72dSKrasimir Georgiev if (FormatTok.TokenText.startswith("//") ||
4060bebf7bdfSowenca FormatTok.TokenText.startswith("/*")) {
406100c5c72dSKrasimir Georgiev IndentContent = FormatTok.TokenText.substr(2);
4062bebf7bdfSowenca }
406300c5c72dSKrasimir Georgiev if (CommentPragmasRegex.match(IndentContent))
406400c5c72dSKrasimir Georgiev return false;
406500c5c72dSKrasimir Georgiev
406691834227SKrasimir Georgiev // If Line starts with a line comment, then FormatTok continues the comment
406791834227SKrasimir Georgiev // section if its original column is greater or equal to the original start
406891834227SKrasimir Georgiev // column of the line.
406991834227SKrasimir Georgiev //
40708432161fSKrasimir Georgiev // Define the min column token of a line as follows: if a line ends in '{' or
40718432161fSKrasimir Georgiev // contains a '{' followed by a line comment, then the min column token is
40728432161fSKrasimir Georgiev // that '{'. Otherwise, the min column token of the line is the first token of
40738432161fSKrasimir Georgiev // the line.
40748432161fSKrasimir Georgiev //
40758432161fSKrasimir Georgiev // If Line starts with a token other than a line comment, then FormatTok
40768432161fSKrasimir Georgiev // continues the comment section if its original column is greater than the
40778432161fSKrasimir Georgiev // original start column of the min column token of the line.
407891834227SKrasimir Georgiev //
407991834227SKrasimir Georgiev // For example, the second line comment continues the first in these cases:
4080b6ccd38dSKrasimir Georgiev //
408191834227SKrasimir Georgiev // // first line
408291834227SKrasimir Georgiev // // second line
4083b6ccd38dSKrasimir Georgiev //
408491834227SKrasimir Georgiev // and:
4085b6ccd38dSKrasimir Georgiev //
408691834227SKrasimir Georgiev // // first line
408791834227SKrasimir Georgiev // // second line
4088b6ccd38dSKrasimir Georgiev //
408991834227SKrasimir Georgiev // and:
4090b6ccd38dSKrasimir Georgiev //
409191834227SKrasimir Georgiev // int i; // first line
409291834227SKrasimir Georgiev // // second line
4093b6ccd38dSKrasimir Georgiev //
40948432161fSKrasimir Georgiev // and:
4095b6ccd38dSKrasimir Georgiev //
40968432161fSKrasimir Georgiev // do { // first line
40978432161fSKrasimir Georgiev // // second line
40988432161fSKrasimir Georgiev // int i;
40998432161fSKrasimir Georgiev // } while (true);
410091834227SKrasimir Georgiev //
4101b6ccd38dSKrasimir Georgiev // and:
4102b6ccd38dSKrasimir Georgiev //
4103b6ccd38dSKrasimir Georgiev // enum {
4104b6ccd38dSKrasimir Georgiev // a, // first line
4105b6ccd38dSKrasimir Georgiev // // second line
4106b6ccd38dSKrasimir Georgiev // b
4107b6ccd38dSKrasimir Georgiev // };
4108b6ccd38dSKrasimir Georgiev //
410991834227SKrasimir Georgiev // The second line comment doesn't continue the first in these cases:
4110b6ccd38dSKrasimir Georgiev //
411191834227SKrasimir Georgiev // // first line
411291834227SKrasimir Georgiev // // second line
4113b6ccd38dSKrasimir Georgiev //
411491834227SKrasimir Georgiev // and:
4115b6ccd38dSKrasimir Georgiev //
411691834227SKrasimir Georgiev // int i; // first line
411791834227SKrasimir Georgiev // // second line
4118b6ccd38dSKrasimir Georgiev //
41198432161fSKrasimir Georgiev // and:
4120b6ccd38dSKrasimir Georgiev //
41218432161fSKrasimir Georgiev // do { // first line
41228432161fSKrasimir Georgiev // // second line
41238432161fSKrasimir Georgiev // int i;
41248432161fSKrasimir Georgiev // } while (true);
4125b6ccd38dSKrasimir Georgiev //
4126b6ccd38dSKrasimir Georgiev // and:
4127b6ccd38dSKrasimir Georgiev //
4128b6ccd38dSKrasimir Georgiev // enum {
4129b6ccd38dSKrasimir Georgiev // a, // first line
4130b6ccd38dSKrasimir Georgiev // // second line
4131b6ccd38dSKrasimir Georgiev // };
41328432161fSKrasimir Georgiev const FormatToken *MinColumnToken = Line.Tokens.front().Tok;
41338432161fSKrasimir Georgiev
41348432161fSKrasimir Georgiev // Scan for '{//'. If found, use the column of '{' as a min column for line
41358432161fSKrasimir Georgiev // comment section continuation.
41368432161fSKrasimir Georgiev const FormatToken *PreviousToken = nullptr;
4137d86c25d6SKrasimir Georgiev for (const UnwrappedLineNode &Node : Line.Tokens) {
41388432161fSKrasimir Georgiev if (PreviousToken && PreviousToken->is(tok::l_brace) &&
41398432161fSKrasimir Georgiev isLineComment(*Node.Tok)) {
41408432161fSKrasimir Georgiev MinColumnToken = PreviousToken;
41418432161fSKrasimir Georgiev break;
41428432161fSKrasimir Georgiev }
41438432161fSKrasimir Georgiev PreviousToken = Node.Tok;
4144b6ccd38dSKrasimir Georgiev
4145b6ccd38dSKrasimir Georgiev // Grab the last newline preceding a token in this unwrapped line.
4146d079995dSMarek Kurdej if (Node.Tok->NewlinesBefore > 0)
4147b6ccd38dSKrasimir Georgiev MinColumnToken = Node.Tok;
4148b6ccd38dSKrasimir Georgiev }
4149d079995dSMarek Kurdej if (PreviousToken && PreviousToken->is(tok::l_brace))
41508432161fSKrasimir Georgiev MinColumnToken = PreviousToken;
41518432161fSKrasimir Georgiev
4152ea222a79SKrasimir Georgiev return continuesLineComment(FormatTok, /*Previous=*/Line.Tokens.back().Tok,
4153ea222a79SKrasimir Georgiev MinColumnToken);
415491834227SKrasimir Georgiev }
415591834227SKrasimir Georgiev
flushComments(bool NewlineBeforeNext)4156f92f7bc5SManuel Klimek void UnwrappedLineParser::flushComments(bool NewlineBeforeNext) {
4157f92f7bc5SManuel Klimek bool JustComments = Line->Tokens.empty();
415801f355feSMarek Kurdej for (FormatToken *Tok : CommentsBeforeNextToken) {
415991834227SKrasimir Georgiev // Line comments that belong to the same line comment section are put on the
416091834227SKrasimir Georgiev // same line since later we might want to reflow content between them.
4161753625b6SKrasimir Georgiev // Additional fine-grained breaking of line comment sections is controlled
4162753625b6SKrasimir Georgiev // by the class BreakableLineCommentSection in case it is desirable to keep
4163753625b6SKrasimir Georgiev // several line comment sections in the same unwrapped line.
4164753625b6SKrasimir Georgiev //
4165753625b6SKrasimir Georgiev // FIXME: Consider putting separate line comment sections as children to the
4166753625b6SKrasimir Georgiev // unwrapped line instead.
416701f355feSMarek Kurdej Tok->ContinuesLineCommentSection =
416801f355feSMarek Kurdej continuesLineCommentSection(*Tok, *Line, CommentPragmasRegex);
416901f355feSMarek Kurdej if (isOnNewLine(*Tok) && JustComments && !Tok->ContinuesLineCommentSection)
4170f92f7bc5SManuel Klimek addUnwrappedLine();
417101f355feSMarek Kurdej pushToken(Tok);
4172f92f7bc5SManuel Klimek }
4173e60cba13SDaniel Jasper if (NewlineBeforeNext && JustComments)
4174f92f7bc5SManuel Klimek addUnwrappedLine();
4175f92f7bc5SManuel Klimek CommentsBeforeNextToken.clear();
4176f92f7bc5SManuel Klimek }
4177f92f7bc5SManuel Klimek
nextToken(int LevelDifference)41783e051054SKrasimir Georgiev void UnwrappedLineParser::nextToken(int LevelDifference) {
4179f7935115SDaniel Jasper if (eof())
4180f7935115SDaniel Jasper return;
41811fcbe675SManuel Klimek flushComments(isOnNewLine(*FormatTok));
4182f92f7bc5SManuel Klimek pushToken(FormatTok);
4183e411aa85SManuel Klimek FormatToken *Previous = FormatTok;
4184142e79b8Smydeveloperday if (!Style.isJavaScript())
41853e051054SKrasimir Georgiev readToken(LevelDifference);
41861dcbbcfcSDaniel Jasper else
41871dcbbcfcSDaniel Jasper readTokenWithJavaScriptASI();
4188e411aa85SManuel Klimek FormatTok->Previous = Previous;
41899ed2e68cSsstwcw if (Style.isVerilog()) {
41909ed2e68cSsstwcw // Blocks in Verilog can have `begin` and `end` instead of braces. For
41919ed2e68cSsstwcw // keywords like `begin`, we can't treat them the same as left braces
41929ed2e68cSsstwcw // because some contexts require one of them. For example structs use
41939ed2e68cSsstwcw // braces and if blocks use keywords, and a left brace can occur in an if
41949ed2e68cSsstwcw // statement, but it is not a block. For keywords like `end`, we simply
41959ed2e68cSsstwcw // treat them the same as right braces.
41969ed2e68cSsstwcw if (Keywords.isVerilogEnd(*FormatTok))
41979ed2e68cSsstwcw FormatTok->Tok.setKind(tok::r_brace);
41989ed2e68cSsstwcw }
4199b9a4990aSDaniel Jasper }
4200b9a4990aSDaniel Jasper
distributeComments(const SmallVectorImpl<FormatToken * > & Comments,const FormatToken * NextTok)4201f62f958aSKrasimir Georgiev void UnwrappedLineParser::distributeComments(
4202f62f958aSKrasimir Georgiev const SmallVectorImpl<FormatToken *> &Comments,
4203f62f958aSKrasimir Georgiev const FormatToken *NextTok) {
4204f62f958aSKrasimir Georgiev // Whether or not a line comment token continues a line is controlled by
4205ea222a79SKrasimir Georgiev // the method continuesLineCommentSection, with the following caveat:
4206f62f958aSKrasimir Georgiev //
4207f62f958aSKrasimir Georgiev // Define a trail of Comments to be a nonempty proper postfix of Comments such
4208f62f958aSKrasimir Georgiev // that each comment line from the trail is aligned with the next token, if
4209f62f958aSKrasimir Georgiev // the next token exists. If a trail exists, the beginning of the maximal
4210f62f958aSKrasimir Georgiev // trail is marked as a start of a new comment section.
4211f62f958aSKrasimir Georgiev //
4212f62f958aSKrasimir Georgiev // For example in this code:
4213f62f958aSKrasimir Georgiev //
4214f62f958aSKrasimir Georgiev // int a; // line about a
4215f62f958aSKrasimir Georgiev // // line 1 about b
4216f62f958aSKrasimir Georgiev // // line 2 about b
4217f62f958aSKrasimir Georgiev // int b;
4218f62f958aSKrasimir Georgiev //
4219f62f958aSKrasimir Georgiev // the two lines about b form a maximal trail, so there are two sections, the
4220f62f958aSKrasimir Georgiev // first one consisting of the single comment "// line about a" and the
4221f62f958aSKrasimir Georgiev // second one consisting of the next two comments.
4222f62f958aSKrasimir Georgiev if (Comments.empty())
4223f62f958aSKrasimir Georgiev return;
4224f62f958aSKrasimir Georgiev bool ShouldPushCommentsInCurrentLine = true;
4225f62f958aSKrasimir Georgiev bool HasTrailAlignedWithNextToken = false;
4226f62f958aSKrasimir Georgiev unsigned StartOfTrailAlignedWithNextToken = 0;
4227f62f958aSKrasimir Georgiev if (NextTok) {
4228f62f958aSKrasimir Georgiev // We are skipping the first element intentionally.
4229f62f958aSKrasimir Georgiev for (unsigned i = Comments.size() - 1; i > 0; --i) {
4230f62f958aSKrasimir Georgiev if (Comments[i]->OriginalColumn == NextTok->OriginalColumn) {
4231f62f958aSKrasimir Georgiev HasTrailAlignedWithNextToken = true;
4232f62f958aSKrasimir Georgiev StartOfTrailAlignedWithNextToken = i;
4233f62f958aSKrasimir Georgiev }
4234f62f958aSKrasimir Georgiev }
4235f62f958aSKrasimir Georgiev }
4236f62f958aSKrasimir Georgiev for (unsigned i = 0, e = Comments.size(); i < e; ++i) {
4237f62f958aSKrasimir Georgiev FormatToken *FormatTok = Comments[i];
423889628f64SManuel Klimek if (HasTrailAlignedWithNextToken && i == StartOfTrailAlignedWithNextToken) {
4239f62f958aSKrasimir Georgiev FormatTok->ContinuesLineCommentSection = false;
4240f62f958aSKrasimir Georgiev } else {
4241f62f958aSKrasimir Georgiev FormatTok->ContinuesLineCommentSection =
4242ea222a79SKrasimir Georgiev continuesLineCommentSection(*FormatTok, *Line, CommentPragmasRegex);
4243f62f958aSKrasimir Georgiev }
4244f62f958aSKrasimir Georgiev if (!FormatTok->ContinuesLineCommentSection &&
4245bebf7bdfSowenca (isOnNewLine(*FormatTok) || FormatTok->IsFirst)) {
4246f62f958aSKrasimir Georgiev ShouldPushCommentsInCurrentLine = false;
4247bebf7bdfSowenca }
4248d079995dSMarek Kurdej if (ShouldPushCommentsInCurrentLine)
4249f62f958aSKrasimir Georgiev pushToken(FormatTok);
4250d079995dSMarek Kurdej else
4251f62f958aSKrasimir Georgiev CommentsBeforeNextToken.push_back(FormatTok);
4252f62f958aSKrasimir Georgiev }
4253f62f958aSKrasimir Georgiev }
4254f62f958aSKrasimir Georgiev
readToken(int LevelDifference)42553e051054SKrasimir Georgiev void UnwrappedLineParser::readToken(int LevelDifference) {
4256f62f958aSKrasimir Georgiev SmallVector<FormatToken *, 1> Comments;
4257a7b5e5b4SMarek Kurdej bool PreviousWasComment = false;
4258a7b5e5b4SMarek Kurdej bool FirstNonCommentOnLine = false;
4259f92f7bc5SManuel Klimek do {
42601abf789cSManuel Klimek FormatTok = Tokens->getNextToken();
4261c2ee9cf8SAlexander Kornienko assert(FormatTok);
426259788422SManuel Klimek while (FormatTok->getType() == TT_ConflictStart ||
426359788422SManuel Klimek FormatTok->getType() == TT_ConflictEnd ||
426459788422SManuel Klimek FormatTok->getType() == TT_ConflictAlternative) {
4265d079995dSMarek Kurdej if (FormatTok->getType() == TT_ConflictStart)
426659788422SManuel Klimek conditionalCompilationStart(/*Unreachable=*/false);
4267d079995dSMarek Kurdej else if (FormatTok->getType() == TT_ConflictAlternative)
426859788422SManuel Klimek conditionalCompilationAlternative();
4269d079995dSMarek Kurdej else if (FormatTok->getType() == TT_ConflictEnd)
427059788422SManuel Klimek conditionalCompilationEnd();
427159788422SManuel Klimek FormatTok = Tokens->getNextToken();
427259788422SManuel Klimek FormatTok->MustBreakBefore = true;
427359788422SManuel Klimek }
427459788422SManuel Klimek
4275a7b5e5b4SMarek Kurdej auto IsFirstNonCommentOnLine = [](bool FirstNonCommentOnLine,
4276a7b5e5b4SMarek Kurdej const FormatToken &Tok,
4277a7b5e5b4SMarek Kurdej bool PreviousWasComment) {
4278a7b5e5b4SMarek Kurdej auto IsFirstOnLine = [](const FormatToken &Tok) {
4279a7b5e5b4SMarek Kurdej return Tok.HasUnescapedNewline || Tok.IsFirst;
4280a7b5e5b4SMarek Kurdej };
4281a7b5e5b4SMarek Kurdej
4282a7b5e5b4SMarek Kurdej // Consider preprocessor directives preceded by block comments as first
4283a7b5e5b4SMarek Kurdej // on line.
4284a7b5e5b4SMarek Kurdej if (PreviousWasComment)
4285a7b5e5b4SMarek Kurdej return FirstNonCommentOnLine || IsFirstOnLine(Tok);
4286a7b5e5b4SMarek Kurdej return IsFirstOnLine(Tok);
4287a7b5e5b4SMarek Kurdej };
4288a7b5e5b4SMarek Kurdej
4289a7b5e5b4SMarek Kurdej FirstNonCommentOnLine = IsFirstNonCommentOnLine(
4290a7b5e5b4SMarek Kurdej FirstNonCommentOnLine, *FormatTok, PreviousWasComment);
4291fee4a971SMarek Kurdej PreviousWasComment = FormatTok->is(tok::comment);
4292a7b5e5b4SMarek Kurdej
4293fee4a971SMarek Kurdej while (!Line->InPPDirective && FormatTok->is(tok::hash) &&
42942e32ff10Ssstwcw (!Style.isVerilog() ||
42952e32ff10Ssstwcw Keywords.isVerilogPPDirective(*Tokens->peekNextToken())) &&
4296a7b5e5b4SMarek Kurdej FirstNonCommentOnLine) {
4297f62f958aSKrasimir Georgiev distributeComments(Comments, FormatTok);
4298f62f958aSKrasimir Georgiev Comments.clear();
4299d3b92fa6SManuel Klimek // If there is an unfinished unwrapped line, we flush the preprocessor
4300d3b92fa6SManuel Klimek // directives only after that unwrapped line was finished later.
430129d39d54SDaniel Jasper bool SwitchToPreprocessorLines = !Line->Tokens.empty();
4302d3b92fa6SManuel Klimek ScopedLineState BlockState(*this, SwitchToPreprocessorLines);
43033e051054SKrasimir Georgiev assert((LevelDifference >= 0 ||
43043e051054SKrasimir Georgiev static_cast<unsigned>(-LevelDifference) <= Line->Level) &&
43053e051054SKrasimir Georgiev "LevelDifference makes Line->Level negative");
43063e051054SKrasimir Georgiev Line->Level += LevelDifference;
4307b1be9d6eSAlexander Kornienko // Comments stored before the preprocessor directive need to be output
4308b1be9d6eSAlexander Kornienko // before the preprocessor directive, at the same level as the
4309b1be9d6eSAlexander Kornienko // preprocessor directive, as we consider them to apply to the directive.
4310701a0d7eSPaul Hoad if (Style.IndentPPDirectives == FormatStyle::PPDIS_BeforeHash &&
4311bebf7bdfSowenca PPBranchLevel > 0) {
4312701a0d7eSPaul Hoad Line->Level += PPBranchLevel;
4313bebf7bdfSowenca }
43141fcbe675SManuel Klimek flushComments(isOnNewLine(*FormatTok));
43159af03864Smydeveloperday parsePPDirective();
4316fee4a971SMarek Kurdej PreviousWasComment = FormatTok->is(tok::comment);
4317a7b5e5b4SMarek Kurdej FirstNonCommentOnLine = IsFirstNonCommentOnLine(
4318a7b5e5b4SMarek Kurdej FirstNonCommentOnLine, *FormatTok, PreviousWasComment);
43191abf789cSManuel Klimek }
4320f2e02123SAlexander Kornienko
4321a98a95ccSFrancois Ferrand if (!PPStack.empty() && (PPStack.back().Kind == PP_Unreachable) &&
4322bebf7bdfSowenca !Line->InPPDirective) {
4323f2e02123SAlexander Kornienko continue;
4324bebf7bdfSowenca }
4325f2e02123SAlexander Kornienko
4326fee4a971SMarek Kurdej if (!FormatTok->is(tok::comment)) {
4327f62f958aSKrasimir Georgiev distributeComments(Comments, FormatTok);
4328f62f958aSKrasimir Georgiev Comments.clear();
4329f92f7bc5SManuel Klimek return;
4330f92f7bc5SManuel Klimek }
4331f62f958aSKrasimir Georgiev
4332f62f958aSKrasimir Georgiev Comments.push_back(FormatTok);
4333f92f7bc5SManuel Klimek } while (!eof());
4334f62f958aSKrasimir Georgiev
4335f62f958aSKrasimir Georgiev distributeComments(Comments, nullptr);
4336f62f958aSKrasimir Georgiev Comments.clear();
4337f92f7bc5SManuel Klimek }
4338f92f7bc5SManuel Klimek
pushToken(FormatToken * Tok)433915dfe7acSManuel Klimek void UnwrappedLineParser::pushToken(FormatToken *Tok) {
43409fe0e8daSDaniel Jasper Line->Tokens.push_back(UnwrappedLineNode(Tok));
4341f92f7bc5SManuel Klimek if (MustBreakBeforeNextToken) {
43429fe0e8daSDaniel Jasper Line->Tokens.back().Tok->MustBreakBefore = true;
4343f92f7bc5SManuel Klimek MustBreakBeforeNextToken = false;
4344f92f7bc5SManuel Klimek }
4345f7935115SDaniel Jasper }
4346f7935115SDaniel Jasper
4347f7935115SDaniel Jasper } // end namespace format
4348f7935115SDaniel Jasper } // end namespace clang
4349