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