summaryrefslogtreecommitdiff
path: root/lib/Format/UnwrappedLineParser.cpp
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2017-12-18 20:11:37 +0000
committerDimitry Andric <dim@FreeBSD.org>2017-12-18 20:11:37 +0000
commit461a67fa15370a9ec88f8f8a240bf7c123bb2029 (patch)
tree6942083d7d56bba40ec790a453ca58ad3baf6832 /lib/Format/UnwrappedLineParser.cpp
parent75c3240472ba6ac2669ee72ca67eb72d4e2851fc (diff)
Notes
Diffstat (limited to 'lib/Format/UnwrappedLineParser.cpp')
-rw-r--r--lib/Format/UnwrappedLineParser.cpp320
1 files changed, 209 insertions, 111 deletions
diff --git a/lib/Format/UnwrappedLineParser.cpp b/lib/Format/UnwrappedLineParser.cpp
index faac5a371c260..b8608dcac9c7e 100644
--- a/lib/Format/UnwrappedLineParser.cpp
+++ b/lib/Format/UnwrappedLineParser.cpp
@@ -18,6 +18,8 @@
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"
+#include <algorithm>
+
#define DEBUG_TYPE "format-parser"
namespace clang {
@@ -56,8 +58,7 @@ private:
};
static bool isLineComment(const FormatToken &FormatTok) {
- return FormatTok.is(tok::comment) &&
- FormatTok.TokenText.startswith("//");
+ return FormatTok.is(tok::comment) && !FormatTok.TokenText.startswith("/*");
}
// Checks if \p FormatTok is a line comment that continues the line comment
@@ -226,15 +227,21 @@ private:
UnwrappedLineParser::UnwrappedLineParser(const FormatStyle &Style,
const AdditionalKeywords &Keywords,
+ unsigned FirstStartColumn,
ArrayRef<FormatToken *> Tokens,
UnwrappedLineConsumer &Callback)
: Line(new UnwrappedLine), MustBreakBeforeNextToken(false),
CurrentLines(&Lines), Style(Style), Keywords(Keywords),
CommentPragmasRegex(Style.CommentPragmas), Tokens(nullptr),
- Callback(Callback), AllTokens(Tokens), PPBranchLevel(-1) {}
+ Callback(Callback), AllTokens(Tokens), PPBranchLevel(-1),
+ IfNdefCondition(nullptr), FoundIncludeGuardStart(false),
+ IncludeGuardRejected(false), FirstStartColumn(FirstStartColumn) {}
void UnwrappedLineParser::reset() {
PPBranchLevel = -1;
+ IfNdefCondition = nullptr;
+ FoundIncludeGuardStart = false;
+ IncludeGuardRejected = false;
Line.reset(new UnwrappedLine);
CommentsBeforeNextToken.clear();
FormatTok = nullptr;
@@ -243,10 +250,12 @@ void UnwrappedLineParser::reset() {
CurrentLines = &Lines;
DeclarationScopeStack.clear();
PPStack.clear();
+ Line->FirstStartColumn = FirstStartColumn;
}
void UnwrappedLineParser::parse() {
IndexedTokenSource TokenSource(AllTokens);
+ Line->FirstStartColumn = FirstStartColumn;
do {
DEBUG(llvm::dbgs() << "----\n");
reset();
@@ -326,6 +335,12 @@ void UnwrappedLineParser::parseLevel(bool HasOpeningBrace) {
break;
case tok::kw_default:
case tok::kw_case:
+ if (Style.Language == FormatStyle::LK_JavaScript &&
+ Line->MustBeDeclaration) {
+ // A 'case: string' style field declaration.
+ parseStructuralElement();
+ break;
+ }
if (!SwitchLabelEncountered &&
(Style.IndentCaseLabels || (Line->InPPDirective && Line->Level == 1)))
++Line->Level;
@@ -346,7 +361,7 @@ void UnwrappedLineParser::calculateBraceTypes(bool ExpectClassBody) {
// definitions, too.
unsigned StoredPosition = Tokens->getPosition();
FormatToken *Tok = FormatTok;
- const FormatToken *PrevTok = getPreviousToken();
+ const FormatToken *PrevTok = Tok->Previous;
// Keep a stack of positions of lbrace tokens. We will
// update information about whether an lbrace starts a
// braced init list or a different block during the loop.
@@ -364,13 +379,16 @@ void UnwrappedLineParser::calculateBraceTypes(bool ExpectClassBody) {
switch (Tok->Tok.getKind()) {
case tok::l_brace:
if (Style.Language == FormatStyle::LK_JavaScript && PrevTok) {
- if (PrevTok->is(tok::colon))
- // A colon indicates this code is in a type, or a braced list
- // following a label in an object literal ({a: {b: 1}}). The code
- // below could be confused by semicolons between the individual
- // members in a type member list, which would normally trigger
- // BK_Block. In both cases, this must be parsed as an inline braced
- // init.
+ if (PrevTok->isOneOf(tok::colon, tok::less))
+ // A ':' indicates this code is in a type, or a braced list
+ // following a label in an object literal ({a: {b: 1}}).
+ // A '<' could be an object used in a comparison, but that is nonsense
+ // code (can never return true), so more likely it is a generic type
+ // argument (`X<{a: string; b: number}>`).
+ // The code below could be confused by semicolons between the
+ // individual members in a type member list, which would normally
+ // trigger BK_Block. In both cases, this must be parsed as an inline
+ // braced init.
Tok->BlockKind = BK_BracedInit;
else if (PrevTok->is(tok::r_paren))
// `) { }` can only occur in function or method declarations in JS.
@@ -452,6 +470,21 @@ void UnwrappedLineParser::calculateBraceTypes(bool ExpectClassBody) {
FormatTok = Tokens->setPosition(StoredPosition);
}
+template <class T>
+static inline void hash_combine(std::size_t &seed, const T &v) {
+ std::hash<T> hasher;
+ seed ^= hasher(v) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
+}
+
+size_t UnwrappedLineParser::computePPHash() const {
+ size_t h = 0;
+ for (const auto &i : PPStack) {
+ hash_combine(h, size_t(i.Kind));
+ hash_combine(h, i.Line);
+ }
+ return h;
+}
+
void UnwrappedLineParser::parseBlock(bool MustBeDeclaration, bool AddLevel,
bool MunchSemi) {
assert(FormatTok->isOneOf(tok::l_brace, TT_MacroBlockBegin) &&
@@ -459,16 +492,21 @@ void UnwrappedLineParser::parseBlock(bool MustBeDeclaration, bool AddLevel,
const bool MacroBlock = FormatTok->is(TT_MacroBlockBegin);
FormatTok->BlockKind = BK_Block;
+ size_t PPStartHash = computePPHash();
+
unsigned InitialLevel = Line->Level;
- nextToken();
+ nextToken(/*LevelDifference=*/AddLevel ? 1 : 0);
if (MacroBlock && FormatTok->is(tok::l_paren))
parseParens();
+ size_t NbPreprocessorDirectives =
+ CurrentLines == &Lines ? PreprocessorDirectives.size() : 0;
addUnwrappedLine();
- size_t OpeningLineIndex = CurrentLines->empty()
- ? (UnwrappedLine::kInvalidIndex)
- : (CurrentLines->size() - 1);
+ size_t OpeningLineIndex =
+ CurrentLines->empty()
+ ? (UnwrappedLine::kInvalidIndex)
+ : (CurrentLines->size() - 1 - NbPreprocessorDirectives);
ScopedDeclarationState DeclarationState(*Line, DeclarationScopeStack,
MustBeDeclaration);
@@ -486,7 +524,10 @@ void UnwrappedLineParser::parseBlock(bool MustBeDeclaration, bool AddLevel,
return;
}
- nextToken(); // Munch the closing brace.
+ size_t PPEndHash = computePPHash();
+
+ // Munch the closing brace.
+ nextToken(/*LevelDifference=*/AddLevel ? -1 : 0);
if (MacroBlock && FormatTok->is(tok::l_paren))
parseParens();
@@ -494,11 +535,14 @@ void UnwrappedLineParser::parseBlock(bool MustBeDeclaration, bool AddLevel,
if (MunchSemi && FormatTok->Tok.is(tok::semi))
nextToken();
Line->Level = InitialLevel;
- Line->MatchingOpeningBlockLineIndex = OpeningLineIndex;
- if (OpeningLineIndex != UnwrappedLine::kInvalidIndex) {
- // Update the opening line to add the forward reference as well
- (*CurrentLines)[OpeningLineIndex].MatchingOpeningBlockLineIndex =
- CurrentLines->size() - 1;
+
+ if (PPStartHash == PPEndHash) {
+ Line->MatchingOpeningBlockLineIndex = OpeningLineIndex;
+ if (OpeningLineIndex != UnwrappedLine::kInvalidIndex) {
+ // Update the opening line to add the forward reference as well
+ (*CurrentLines)[OpeningLineIndex].MatchingOpeningBlockLineIndex =
+ CurrentLines->size() - 1;
+ }
}
}
@@ -555,9 +599,8 @@ void UnwrappedLineParser::parseChildBlock() {
FormatTok->BlockKind = BK_Block;
nextToken();
{
- bool SkipIndent =
- (Style.Language == FormatStyle::LK_JavaScript &&
- (isGoogScope(*Line) || isIIFE(*Line, Keywords)));
+ bool SkipIndent = (Style.Language == FormatStyle::LK_JavaScript &&
+ (isGoogScope(*Line) || isIIFE(*Line, Keywords)));
ScopedLineState LineState(*this);
ScopedDeclarationState DeclarationState(*Line, DeclarationScopeStack,
/*MustBeDeclaration=*/false);
@@ -606,10 +649,15 @@ void UnwrappedLineParser::parsePPDirective() {
}
void UnwrappedLineParser::conditionalCompilationCondition(bool Unreachable) {
- if (Unreachable || (!PPStack.empty() && PPStack.back() == PP_Unreachable))
- PPStack.push_back(PP_Unreachable);
+ size_t Line = CurrentLines->size();
+ if (CurrentLines == &PreprocessorDirectives)
+ Line += Lines.size();
+
+ if (Unreachable ||
+ (!PPStack.empty() && PPStack.back().Kind == PP_Unreachable))
+ PPStack.push_back({PP_Unreachable, Line});
else
- PPStack.push_back(PP_Conditional);
+ PPStack.push_back({PP_Conditional, Line});
}
void UnwrappedLineParser::conditionalCompilationStart(bool Unreachable) {
@@ -643,7 +691,7 @@ void UnwrappedLineParser::conditionalCompilationEnd() {
}
}
// Guard against #endif's without #if.
- if (PPBranchLevel > 0)
+ if (PPBranchLevel > -1)
--PPBranchLevel;
if (!PPChainBranchIndex.empty())
PPChainBranchIndex.pop();
@@ -660,12 +708,35 @@ void UnwrappedLineParser::parsePPIf(bool IfDef) {
if (IfDef && !IfNDef && FormatTok->TokenText == "SWIG")
Unreachable = true;
conditionalCompilationStart(Unreachable);
+ FormatToken *IfCondition = FormatTok;
+ // If there's a #ifndef on the first line, and the only lines before it are
+ // comments, it could be an include guard.
+ bool MaybeIncludeGuard = IfNDef;
+ if (!IncludeGuardRejected && !FoundIncludeGuardStart && MaybeIncludeGuard) {
+ for (auto &Line : Lines) {
+ if (!Line.Tokens.front().Tok->is(tok::comment)) {
+ MaybeIncludeGuard = false;
+ IncludeGuardRejected = true;
+ break;
+ }
+ }
+ }
+ --PPBranchLevel;
parsePPUnknown();
+ ++PPBranchLevel;
+ if (!IncludeGuardRejected && !FoundIncludeGuardStart && MaybeIncludeGuard)
+ IfNdefCondition = IfCondition;
}
void UnwrappedLineParser::parsePPElse() {
+ // If a potential include guard has an #else, it's not an include guard.
+ if (FoundIncludeGuardStart && PPBranchLevel == 0)
+ FoundIncludeGuardStart = false;
conditionalCompilationAlternative();
+ if (PPBranchLevel > -1)
+ --PPBranchLevel;
parsePPUnknown();
+ ++PPBranchLevel;
}
void UnwrappedLineParser::parsePPElIf() { parsePPElse(); }
@@ -673,6 +744,16 @@ void UnwrappedLineParser::parsePPElIf() { parsePPElse(); }
void UnwrappedLineParser::parsePPEndIf() {
conditionalCompilationEnd();
parsePPUnknown();
+ // If the #endif of a potential include guard is the last thing in the file,
+ // then we count it as a real include guard and subtract one from every
+ // preprocessor indent.
+ unsigned TokenPosition = Tokens->getPosition();
+ FormatToken *PeekNext = AllTokens[TokenPosition];
+ if (FoundIncludeGuardStart && PPBranchLevel == -1 && PeekNext->is(tok::eof) &&
+ Style.IndentPPDirectives != FormatStyle::PPDIS_None)
+ for (auto &Line : Lines)
+ if (Line.InPPDirective && Line.Level > 0)
+ --Line.Level;
}
void UnwrappedLineParser::parsePPDefine() {
@@ -682,14 +763,26 @@ void UnwrappedLineParser::parsePPDefine() {
parsePPUnknown();
return;
}
+ if (IfNdefCondition && IfNdefCondition->TokenText == FormatTok->TokenText) {
+ FoundIncludeGuardStart = true;
+ for (auto &Line : Lines) {
+ if (!Line.Tokens.front().Tok->isOneOf(tok::comment, tok::hash)) {
+ FoundIncludeGuardStart = false;
+ break;
+ }
+ }
+ }
+ IfNdefCondition = nullptr;
nextToken();
if (FormatTok->Tok.getKind() == tok::l_paren &&
FormatTok->WhitespaceRange.getBegin() ==
FormatTok->WhitespaceRange.getEnd()) {
parseParens();
}
+ if (Style.IndentPPDirectives == FormatStyle::PPDIS_AfterHash)
+ Line->Level += PPBranchLevel + 1;
addUnwrappedLine();
- Line->Level = 1;
+ ++Line->Level;
// Errors during a preprocessor directive can only affect the layout of the
// preprocessor directive, and thus we ignore them. An alternative approach
@@ -703,7 +796,10 @@ void UnwrappedLineParser::parsePPUnknown() {
do {
nextToken();
} while (!eof());
+ if (Style.IndentPPDirectives == FormatStyle::PPDIS_AfterHash)
+ Line->Level += PPBranchLevel + 1;
addUnwrappedLine();
+ IfNdefCondition = nullptr;
}
// Here we blacklist certain tokens that are not usually the first token in an
@@ -746,8 +842,8 @@ static bool mustBeJSIdent(const AdditionalKeywords &Keywords,
Keywords.kw_function, Keywords.kw_import, Keywords.kw_is,
Keywords.kw_let, Keywords.kw_var, tok::kw_const,
Keywords.kw_abstract, Keywords.kw_extends, Keywords.kw_implements,
- Keywords.kw_instanceof, Keywords.kw_interface,
- Keywords.kw_throws, Keywords.kw_from));
+ Keywords.kw_instanceof, Keywords.kw_interface, Keywords.kw_throws,
+ Keywords.kw_from));
}
static bool mustBeJSIdentOrValue(const AdditionalKeywords &Keywords,
@@ -800,11 +896,14 @@ void UnwrappedLineParser::readTokenWithJavaScriptASI() {
bool PreviousMustBeValue = mustBeJSIdentOrValue(Keywords, Previous);
bool PreviousStartsTemplateExpr =
Previous->is(TT_TemplateString) && Previous->TokenText.endswith("${");
- if (PreviousMustBeValue && Line && Line->Tokens.size() > 1) {
- // If the token before the previous one is an '@', the previous token is an
- // annotation and can precede another identifier/value.
- const FormatToken *PrePrevious = std::prev(Line->Tokens.end(), 2)->Tok;
- if (PrePrevious->is(tok::at))
+ if (PreviousMustBeValue || Previous->is(tok::r_paren)) {
+ // If the line contains an '@' sign, the previous token might be an
+ // annotation, which can precede another identifier/value.
+ bool HasAt = std::find_if(Line->Tokens.begin(), Line->Tokens.end(),
+ [](UnwrappedLineNode &LineNode) {
+ return LineNode.Tok->is(tok::at);
+ }) != Line->Tokens.end();
+ if (HasAt)
return;
}
if (Next->is(tok::exclaim) && PreviousMustBeValue)
@@ -817,7 +916,8 @@ void UnwrappedLineParser::readTokenWithJavaScriptASI() {
Previous->isOneOf(tok::r_square, tok::r_paren, tok::plusplus,
tok::minusminus)))
return addUnwrappedLine();
- if (PreviousMustBeValue && isJSDeclOrStmt(Keywords, Next))
+ if ((PreviousMustBeValue || Previous->is(tok::r_paren)) &&
+ isJSDeclOrStmt(Keywords, Next))
return addUnwrappedLine();
}
@@ -922,13 +1022,22 @@ void UnwrappedLineParser::parseStructuralElement() {
parseDoWhile();
return;
case tok::kw_switch:
+ if (Style.Language == FormatStyle::LK_JavaScript && Line->MustBeDeclaration)
+ // 'switch: string' field declaration.
+ break;
parseSwitch();
return;
case tok::kw_default:
+ if (Style.Language == FormatStyle::LK_JavaScript && Line->MustBeDeclaration)
+ // 'default: string' field declaration.
+ break;
nextToken();
parseLabel();
return;
case tok::kw_case:
+ if (Style.Language == FormatStyle::LK_JavaScript && Line->MustBeDeclaration)
+ // 'case: string' field declaration.
+ break;
parseCaseLabel();
return;
case tok::kw_try:
@@ -940,7 +1049,12 @@ void UnwrappedLineParser::parseStructuralElement() {
if (FormatTok->Tok.is(tok::string_literal)) {
nextToken();
if (FormatTok->Tok.is(tok::l_brace)) {
- parseBlock(/*MustBeDeclaration=*/true, /*AddLevel=*/false);
+ if (Style.BraceWrapping.AfterExternBlock) {
+ addUnwrappedLine();
+ parseBlock(/*MustBeDeclaration=*/true);
+ } else {
+ parseBlock(/*MustBeDeclaration=*/true, /*AddLevel=*/false);
+ }
addUnwrappedLine();
return;
}
@@ -996,7 +1110,7 @@ void UnwrappedLineParser::parseStructuralElement() {
break;
}
do {
- const FormatToken *Previous = getPreviousToken();
+ const FormatToken *Previous = FormatTok->Previous;
switch (FormatTok->Tok.getKind()) {
case tok::at:
nextToken();
@@ -1186,7 +1300,7 @@ void UnwrappedLineParser::parseStructuralElement() {
nextToken();
parseBracedList();
} else if (Style.Language == FormatStyle::LK_Proto &&
- FormatTok->Tok.is(tok::less)) {
+ FormatTok->Tok.is(tok::less)) {
nextToken();
parseBracedList(/*ContinueOnSemicolons=*/false,
/*ClosingBraceKind=*/tok::greater);
@@ -1210,14 +1324,6 @@ bool UnwrappedLineParser::tryToParseLambda() {
nextToken();
return false;
}
- const FormatToken* Previous = getPreviousToken();
- if (Previous &&
- (Previous->isOneOf(tok::identifier, tok::kw_operator, tok::kw_new,
- tok::kw_delete) ||
- Previous->closesScope() || Previous->isSimpleTypeSpecifier())) {
- nextToken();
- return false;
- }
assert(FormatTok->is(tok::l_square));
FormatToken &LSquare = *FormatTok;
if (!tryToParseLambdaIntroducer())
@@ -1260,49 +1366,18 @@ bool UnwrappedLineParser::tryToParseLambda() {
}
bool UnwrappedLineParser::tryToParseLambdaIntroducer() {
- nextToken();
- if (FormatTok->is(tok::equal)) {
- nextToken();
- if (FormatTok->is(tok::r_square)) {
- nextToken();
- return true;
- }
- if (FormatTok->isNot(tok::comma))
- return false;
- nextToken();
- } else if (FormatTok->is(tok::amp)) {
- nextToken();
- if (FormatTok->is(tok::r_square)) {
- nextToken();
- return true;
- }
- if (!FormatTok->isOneOf(tok::comma, tok::identifier)) {
- return false;
- }
- if (FormatTok->is(tok::comma))
- nextToken();
- } else if (FormatTok->is(tok::r_square)) {
+ const FormatToken *Previous = FormatTok->Previous;
+ if (Previous &&
+ (Previous->isOneOf(tok::identifier, tok::kw_operator, tok::kw_new,
+ tok::kw_delete) ||
+ FormatTok->isCppStructuredBinding(Style) || Previous->closesScope() ||
+ Previous->isSimpleTypeSpecifier())) {
nextToken();
- return true;
+ return false;
}
- do {
- if (FormatTok->is(tok::amp))
- nextToken();
- if (!FormatTok->isOneOf(tok::identifier, tok::kw_this))
- return false;
- nextToken();
- if (FormatTok->is(tok::ellipsis))
- nextToken();
- if (FormatTok->is(tok::comma)) {
- nextToken();
- } else if (FormatTok->is(tok::r_square)) {
- nextToken();
- return true;
- } else {
- return false;
- }
- } while (!eof());
- return false;
+ nextToken();
+ parseSquare(/*LambdaIntroducer=*/true);
+ return true;
}
void UnwrappedLineParser::tryToParseJSFunction() {
@@ -1419,6 +1494,15 @@ bool UnwrappedLineParser::parseBracedList(bool ContinueOnSemicolons,
nextToken();
parseBracedList();
break;
+ case tok::less:
+ if (Style.Language == FormatStyle::LK_Proto) {
+ nextToken();
+ parseBracedList(/*ContinueOnSemicolons=*/false,
+ /*ClosingBraceKind=*/tok::greater);
+ } else {
+ nextToken();
+ }
+ break;
case tok::semi:
// JavaScript (or more precisely TypeScript) can have semicolons in braced
// lists (in so-called TypeMemberLists). Thus, the semicolon cannot be
@@ -1495,10 +1579,12 @@ void UnwrappedLineParser::parseParens() {
} while (!eof());
}
-void UnwrappedLineParser::parseSquare() {
- assert(FormatTok->Tok.is(tok::l_square) && "'[' expected.");
- if (tryToParseLambda())
- return;
+void UnwrappedLineParser::parseSquare(bool LambdaIntroducer) {
+ if (!LambdaIntroducer) {
+ assert(FormatTok->Tok.is(tok::l_square) && "'[' expected.");
+ if (tryToParseLambda())
+ return;
+ }
do {
switch (FormatTok->Tok.getKind()) {
case tok::l_paren:
@@ -1939,6 +2025,17 @@ void UnwrappedLineParser::parseRecord(bool ParseAsExpr) {
((Style.Language == FormatStyle::LK_Java ||
Style.Language == FormatStyle::LK_JavaScript) &&
FormatTok->isOneOf(tok::period, tok::comma))) {
+ if (Style.Language == FormatStyle::LK_JavaScript &&
+ FormatTok->isOneOf(Keywords.kw_extends, Keywords.kw_implements)) {
+ // JavaScript/TypeScript supports inline object types in
+ // extends/implements positions:
+ // class Foo implements {bar: number} { }
+ nextToken();
+ if (FormatTok->is(tok::l_brace)) {
+ tryToParseBracedList();
+ continue;
+ }
+ }
bool IsNonMacroIdentifier =
FormatTok->is(tok::identifier) &&
FormatTok->TokenText != FormatTok->TokenText.upper();
@@ -2090,7 +2187,7 @@ void UnwrappedLineParser::parseJavaScriptEs6ImportExport() {
while (!eof()) {
if (FormatTok->is(tok::semi))
return;
- if (Line->Tokens.size() == 0) {
+ if (Line->Tokens.empty()) {
// Common issue: Automatic Semicolon Insertion wrapped the line, so the
// import statement should terminate.
return;
@@ -2107,14 +2204,15 @@ void UnwrappedLineParser::parseJavaScriptEs6ImportExport() {
LLVM_ATTRIBUTE_UNUSED static void printDebugInfo(const UnwrappedLine &Line,
StringRef Prefix = "") {
- llvm::dbgs() << Prefix << "Line(" << Line.Level << ")"
+ llvm::dbgs() << Prefix << "Line(" << Line.Level
+ << ", FSC=" << Line.FirstStartColumn << ")"
<< (Line.InPPDirective ? " MACRO" : "") << ": ";
for (std::list<UnwrappedLineNode>::const_iterator I = Line.Tokens.begin(),
E = Line.Tokens.end();
I != E; ++I) {
llvm::dbgs() << I->Tok->Tok.getName() << "["
- << "T=" << I->Tok->Type
- << ", OC=" << I->Tok->OriginalColumn << "] ";
+ << "T=" << I->Tok->Type << ", OC=" << I->Tok->OriginalColumn
+ << "] ";
}
for (std::list<UnwrappedLineNode>::const_iterator I = Line.Tokens.begin(),
E = Line.Tokens.end();
@@ -2140,12 +2238,15 @@ void UnwrappedLineParser::addUnwrappedLine() {
CurrentLines->push_back(std::move(*Line));
Line->Tokens.clear();
Line->MatchingOpeningBlockLineIndex = UnwrappedLine::kInvalidIndex;
+ Line->FirstStartColumn = 0;
if (CurrentLines == &Lines && !PreprocessorDirectives.empty()) {
CurrentLines->append(
std::make_move_iterator(PreprocessorDirectives.begin()),
std::make_move_iterator(PreprocessorDirectives.end()));
PreprocessorDirectives.clear();
}
+ // Disconnect the current token from the last token on the previous line.
+ FormatTok->Previous = nullptr;
}
bool UnwrappedLineParser::eof() const { return FormatTok->Tok.is(tok::eof); }
@@ -2287,23 +2388,17 @@ void UnwrappedLineParser::flushComments(bool NewlineBeforeNext) {
CommentsBeforeNextToken.clear();
}
-void UnwrappedLineParser::nextToken() {
+void UnwrappedLineParser::nextToken(int LevelDifference) {
if (eof())
return;
flushComments(isOnNewLine(*FormatTok));
pushToken(FormatTok);
+ FormatToken *Previous = FormatTok;
if (Style.Language != FormatStyle::LK_JavaScript)
- readToken();
+ readToken(LevelDifference);
else
readTokenWithJavaScriptASI();
-}
-
-const FormatToken *UnwrappedLineParser::getPreviousToken() {
- // FIXME: This is a dirty way to access the previous token. Find a better
- // solution.
- if (!Line || Line->Tokens.empty())
- return nullptr;
- return Line->Tokens.back().Tok;
+ FormatTok->Previous = Previous;
}
void UnwrappedLineParser::distributeComments(
@@ -2343,8 +2438,7 @@ void UnwrappedLineParser::distributeComments(
}
for (unsigned i = 0, e = Comments.size(); i < e; ++i) {
FormatToken *FormatTok = Comments[i];
- if (HasTrailAlignedWithNextToken &&
- i == StartOfTrailAlignedWithNextToken) {
+ if (HasTrailAlignedWithNextToken && i == StartOfTrailAlignedWithNextToken) {
FormatTok->ContinuesLineCommentSection = false;
} else {
FormatTok->ContinuesLineCommentSection =
@@ -2362,7 +2456,7 @@ void UnwrappedLineParser::distributeComments(
}
}
-void UnwrappedLineParser::readToken() {
+void UnwrappedLineParser::readToken(int LevelDifference) {
SmallVector<FormatToken *, 1> Comments;
do {
FormatTok = Tokens->getNextToken();
@@ -2375,6 +2469,10 @@ void UnwrappedLineParser::readToken() {
// directives only after that unwrapped line was finished later.
bool SwitchToPreprocessorLines = !Line->Tokens.empty();
ScopedLineState BlockState(*this, SwitchToPreprocessorLines);
+ assert((LevelDifference >= 0 ||
+ static_cast<unsigned>(-LevelDifference) <= Line->Level) &&
+ "LevelDifference makes Line->Level negative");
+ Line->Level += LevelDifference;
// Comments stored before the preprocessor directive need to be output
// before the preprocessor directive, at the same level as the
// preprocessor directive, as we consider them to apply to the directive.
@@ -2395,7 +2493,7 @@ void UnwrappedLineParser::readToken() {
FormatTok->MustBreakBefore = true;
}
- if (!PPStack.empty() && (PPStack.back() == PP_Unreachable) &&
+ if (!PPStack.empty() && (PPStack.back().Kind == PP_Unreachable) &&
!Line->InPPDirective) {
continue;
}