bool UnwrappedLineParser::parseFile() {
bool Error = parseLevel(/*HasOpeningBrace=*/false);
// Make sure to format the remaining tokens.
+ flushComments(true);
addUnwrappedLine();
return Error;
}
Line->Level += AddLevels;
parseLevel(/*HasOpeningBrace=*/true);
- Line->Level -= AddLevels;
- if (!FormatTok.Tok.is(tok::r_brace))
+ if (!FormatTok.Tok.is(tok::r_brace)) {
+ Line->Level -= AddLevels;
return true;
+ }
nextToken(); // Munch the closing brace.
+ Line->Level -= AddLevels;
return false;
}
addUnwrappedLine();
}
-void UnwrappedLineParser::parseComments() {
- // Consume leading line comments, e.g. for branches without compounds.
- while (FormatTok.Tok.is(tok::comment)) {
- nextToken();
- addUnwrappedLine();
- }
-}
-
void UnwrappedLineParser::parseStructuralElement() {
assert(!FormatTok.Tok.is(tok::l_brace));
- parseComments();
-
int TokenNumber = 0;
switch (FormatTok.Tok.getKind()) {
case tok::at:
++Line->Level;
do {
switch (FormatTok.Tok.getKind()) {
- case tok::comment:
- // FIXME: Handle comments centrally, instead of special casing
- // them everywhere.
- parseComments();
- break;
case tok::l_paren:
parseParens();
break;
void UnwrappedLineParser::addUnwrappedLine() {
if (Line->Tokens.empty())
return;
- // Consume trailing comments.
- while (!eof() && FormatTok.NewlinesBefore == 0 &&
- FormatTok.Tok.is(tok::comment)) {
- nextToken();
- }
DEBUG({
- llvm::dbgs() << "Line: ";
+ llvm::dbgs() << "Line(" << Line->Level << "): ";
for (std::list<FormatToken>::iterator I = Line->Tokens.begin(),
E = Line->Tokens.end();
I != E; ++I) {
return FormatTok.Tok.is(tok::eof);
}
+void UnwrappedLineParser::flushComments(bool NewlineBeforeNext) {
+ bool JustComments = Line->Tokens.empty();
+ for (SmallVectorImpl<FormatToken>::const_iterator
+ I = CommentsBeforeNextToken.begin(),
+ E = CommentsBeforeNextToken.end();
+ I != E; ++I) {
+ if (I->HasUnescapedNewline && JustComments) {
+ addUnwrappedLine();
+ }
+ pushToken(*I);
+ }
+ if (NewlineBeforeNext && JustComments) {
+ addUnwrappedLine();
+ }
+ CommentsBeforeNextToken.clear();
+}
+
void UnwrappedLineParser::nextToken() {
if (eof())
return;
- Line->Tokens.push_back(FormatTok);
- if (MustBreakBeforeNextToken) {
- Line->Tokens.back().MustBreakBefore = true;
- MustBreakBeforeNextToken = false;
- }
+ flushComments(FormatTok.HasUnescapedNewline);
+ pushToken(FormatTok);
readToken();
}
void UnwrappedLineParser::readToken() {
- FormatTok = Tokens->getNextToken();
- while (!Line->InPPDirective && FormatTok.Tok.is(tok::hash) &&
- ((FormatTok.NewlinesBefore > 0 && FormatTok.HasUnescapedNewline) ||
- FormatTok.IsFirst)) {
- // If there is an unfinished unwrapped line, we flush the preprocessor
- // directives only after that unwrapped line was finished later.
- bool SwitchToPreprocessorLines = !Line->Tokens.empty() &&
- CurrentLines == &Lines;
- ScopedLineState BlockState(*this, SwitchToPreprocessorLines);
- parsePPDirective();
+ bool CommentsInCurrentLine = true;
+ do {
+ FormatTok = Tokens->getNextToken();
+ while (!Line->InPPDirective && FormatTok.Tok.is(tok::hash) &&
+ ((FormatTok.NewlinesBefore > 0 && FormatTok.HasUnescapedNewline) ||
+ FormatTok.IsFirst)) {
+ // If there is an unfinished unwrapped line, we flush the preprocessor
+ // directives only after that unwrapped line was finished later.
+ bool SwitchToPreprocessorLines = !Line->Tokens.empty() &&
+ CurrentLines == &Lines;
+ ScopedLineState BlockState(*this, SwitchToPreprocessorLines);
+ parsePPDirective();
+ }
+ if (!FormatTok.Tok.is(tok::comment))
+ return;
+ if (FormatTok.HasUnescapedNewline || FormatTok.IsFirst) {
+ CommentsInCurrentLine = false;
+ }
+ if (CommentsInCurrentLine) {
+ pushToken(FormatTok);
+ } else {
+ CommentsBeforeNextToken.push_back(FormatTok);
+ }
+ } while (!eof());
+}
+
+void UnwrappedLineParser::pushToken(const FormatToken &Tok) {
+ Line->Tokens.push_back(Tok);
+ if (MustBreakBeforeNextToken) {
+ Line->Tokens.back().MustBreakBefore = true;
+ MustBreakBeforeNextToken = false;
}
}
void parsePPDirective();
void parsePPDefine();
void parsePPUnknown();
- void parseComments();
void parseStructuralElement();
void parseBracedList();
void parseReturn();
bool eof() const;
void nextToken();
void readToken();
+ void flushComments(bool NewlineBeforeNext);
+ void pushToken(const FormatToken &Tok);
// FIXME: We are constantly running into bugs where Line.Level is incorrectly
// subtracted from beyond 0. Introduce a method to subtract from Line.Level
// and use that everywhere in the Parser.
OwningPtr<UnwrappedLine> Line;
+
+ // Comments are sorted into unwrapped lines by whether they are in the same
+ // line as the previous token, or not. If not, they belong to the next token.
+ // Since the next token might already be in a new unwrapped line, we need to
+ // store the comments belonging to that token.
+ SmallVector<FormatToken, 1> CommentsBeforeNextToken;
FormatToken FormatTok;
bool MustBreakBeforeNextToken;
" if (true) continue;", ShortMergedIf);
}
+TEST_F(FormatTest, BlockCommentsInControlLoops) {
+ verifyFormat("if (0) /* a comment in a strange place */ {\n"
+ " f();\n"
+ "}");
+ verifyFormat("if (0) /* a comment in a strange place */ {\n"
+ " f();\n"
+ "} /* another comment */ else /* comment #3 */ {\n"
+ " g();\n"
+ "}");
+ verifyFormat("while (0) /* a comment in a strange place */ {\n"
+ " f();\n"
+ "}");
+ verifyFormat("for (;;) /* a comment in a strange place */ {\n"
+ " f();\n"
+ "}");
+ verifyFormat("do /* a comment in a strange place */ {\n"
+ " f();\n"
+ "} /* another comment */ while (0);");
+}
+
+TEST_F(FormatTest, BlockComments) {
+ EXPECT_EQ("/* */ /* */ /* */\n/* */ /* */ /* */",
+ format("/* *//* */ /* */\n/* *//* */ /* */"));
+ EXPECT_EQ("/* */ a /* */ b;",
+ format(" /* */ a/* */ b;"));
+ EXPECT_EQ("#define A /* */\\\n"
+ " b\n"
+ "/* */\n"
+ "someCall(\n"
+ " parameter);",
+ format("#define A /* */ b\n"
+ "/* */\n"
+ "someCall(parameter);", getLLVMStyleWithColumns(15)));
+
+ EXPECT_EQ("#define A\n"
+ "/* */ someCall(\n"
+ " parameter);",
+ format("#define A\n"
+ "/* */someCall(parameter);", getLLVMStyleWithColumns(15)));
+}
+
//===----------------------------------------------------------------------===//
// Objective-C tests.
//===----------------------------------------------------------------------===//