forked from OSchip/llvm-project
Again macros without trailing semicolons: don't care about declaration context.
Summary: Some codebases use these kinds of macros in functions, e.g. Chromium's IPC_BEGIN_MESSAGE_MAP, IPC_BEGIN_MESSAGE_HANDLER, etc. Reviewers: djasper, klimek Reviewed By: klimek CC: cfe-commits Differential Revision: http://llvm-reviews.chandlerc.com/D645 llvm-svn: 179099
This commit is contained in:
parent
e4549a2391
commit
a04e5e213b
|
@ -260,6 +260,33 @@ void UnwrappedLineParser::parsePPUnknown() {
|
|||
addUnwrappedLine();
|
||||
}
|
||||
|
||||
// Here we blacklist certain tokens that are not usually the first token in an
|
||||
// unwrapped line. This is used in attempt to distinguish macro calls without
|
||||
// trailing semicolons from other constructs split to several lines.
|
||||
bool tokenCanStartNewLine(clang::Token Tok) {
|
||||
// Semicolon can be a null-statement, l_square can be a start of a macro or
|
||||
// a C++11 attribute, but this doesn't seem to be common.
|
||||
return Tok.isNot(tok::semi) && Tok.isNot(tok::l_brace) &&
|
||||
Tok.isNot(tok::l_square) &&
|
||||
// Tokens that can only be used as binary operators and a part of
|
||||
// overloaded operator names.
|
||||
Tok.isNot(tok::period) && Tok.isNot(tok::periodstar) &&
|
||||
Tok.isNot(tok::arrow) && Tok.isNot(tok::arrowstar) &&
|
||||
Tok.isNot(tok::less) && Tok.isNot(tok::greater) &&
|
||||
Tok.isNot(tok::slash) && Tok.isNot(tok::percent) &&
|
||||
Tok.isNot(tok::lessless) && Tok.isNot(tok::greatergreater) &&
|
||||
Tok.isNot(tok::equal) && Tok.isNot(tok::plusequal) &&
|
||||
Tok.isNot(tok::minusequal) && Tok.isNot(tok::starequal) &&
|
||||
Tok.isNot(tok::slashequal) && Tok.isNot(tok::percentequal) &&
|
||||
Tok.isNot(tok::ampequal) && Tok.isNot(tok::pipeequal) &&
|
||||
Tok.isNot(tok::caretequal) && Tok.isNot(tok::greatergreaterequal) &&
|
||||
Tok.isNot(tok::lesslessequal) &&
|
||||
// Colon is used in labels, base class lists, initializer lists,
|
||||
// range-based for loops, ternary operator, but should never be the
|
||||
// first token in an unwrapped line.
|
||||
Tok.isNot(tok::colon);
|
||||
}
|
||||
|
||||
void UnwrappedLineParser::parseStructuralElement() {
|
||||
assert(!FormatTok.Tok.is(tok::l_brace));
|
||||
switch (FormatTok.Tok.getKind()) {
|
||||
|
@ -386,11 +413,11 @@ void UnwrappedLineParser::parseStructuralElement() {
|
|||
parseLabel();
|
||||
return;
|
||||
}
|
||||
// Recognize function-like macro usages without trailing semicolon in
|
||||
// declaration context.
|
||||
// Recognize function-like macro usages without trailing semicolon.
|
||||
if (FormatTok.Tok.is(tok::l_paren)) {
|
||||
parseParens();
|
||||
if (Line->MustBeDeclaration && FormatTok.HasUnescapedNewline) {
|
||||
if (FormatTok.HasUnescapedNewline &&
|
||||
tokenCanStartNewLine(FormatTok.Tok)) {
|
||||
addUnwrappedLine();
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -1353,6 +1353,99 @@ TEST_F(FormatTest, MacroCallsWithoutTrailingSemicolon) {
|
|||
" class X {};\n"
|
||||
" INITIALIZE_PASS_END(ScopDetection, \"polly-detect\")\n"
|
||||
" int *createScopDetectionPass() { return 0; }"));
|
||||
// FIXME: We could probably treat IPC_BEGIN_MESSAGE_MAP/IPC_END_MESSAGE_MAP as
|
||||
// braces, so that inner block is indented one level more.
|
||||
EXPECT_EQ("int q() {\n"
|
||||
" IPC_BEGIN_MESSAGE_MAP(WebKitTestController, message)\n"
|
||||
" IPC_MESSAGE_HANDLER(xxx, qqq)\n"
|
||||
" IPC_END_MESSAGE_MAP()\n"
|
||||
"}",
|
||||
format("int q() {\n"
|
||||
" IPC_BEGIN_MESSAGE_MAP(WebKitTestController, message)\n"
|
||||
" IPC_MESSAGE_HANDLER(xxx, qqq)\n"
|
||||
" IPC_END_MESSAGE_MAP()\n"
|
||||
"}"));
|
||||
EXPECT_EQ("int q() {\n"
|
||||
" f(x);\n"
|
||||
" f(x) {}\n"
|
||||
" f(x)->g();\n"
|
||||
" f(x)->*g();\n"
|
||||
" f(x).g();\n"
|
||||
" f(x) = x;\n"
|
||||
" f(x) += x;\n"
|
||||
" f(x) -= x;\n"
|
||||
" f(x) *= x;\n"
|
||||
" f(x) /= x;\n"
|
||||
" f(x) %= x;\n"
|
||||
" f(x) &= x;\n"
|
||||
" f(x) |= x;\n"
|
||||
" f(x) ^= x;\n"
|
||||
" f(x) >>= x;\n"
|
||||
" f(x) <<= x;\n"
|
||||
" f(x)[y].z();\n"
|
||||
" LOG(INFO) << x;\n"
|
||||
" ifstream(x) >> x;\n"
|
||||
"}\n",
|
||||
format("int q() {\n"
|
||||
" f(x)\n;\n"
|
||||
" f(x)\n {}\n"
|
||||
" f(x)\n->g();\n"
|
||||
" f(x)\n->*g();\n"
|
||||
" f(x)\n.g();\n"
|
||||
" f(x)\n = x;\n"
|
||||
" f(x)\n += x;\n"
|
||||
" f(x)\n -= x;\n"
|
||||
" f(x)\n *= x;\n"
|
||||
" f(x)\n /= x;\n"
|
||||
" f(x)\n %= x;\n"
|
||||
" f(x)\n &= x;\n"
|
||||
" f(x)\n |= x;\n"
|
||||
" f(x)\n ^= x;\n"
|
||||
" f(x)\n >>= x;\n"
|
||||
" f(x)\n <<= x;\n"
|
||||
" f(x)\n[y].z();\n"
|
||||
" LOG(INFO)\n << x;\n"
|
||||
" ifstream(x)\n >> x;\n"
|
||||
"}\n"));
|
||||
EXPECT_EQ("int q() {\n"
|
||||
" f(x)\n"
|
||||
" if (1) {\n"
|
||||
" }\n"
|
||||
" f(x)\n"
|
||||
" while (1) {\n"
|
||||
" }\n"
|
||||
" f(x)\n"
|
||||
" g(x);\n"
|
||||
" f(x)\n"
|
||||
" try {\n"
|
||||
" q();\n"
|
||||
" }\n"
|
||||
" catch (...) {\n"
|
||||
" }\n"
|
||||
"}\n",
|
||||
format("int q() {\n"
|
||||
"f(x)\n"
|
||||
"if (1) {}\n"
|
||||
"f(x)\n"
|
||||
"while (1) {}\n"
|
||||
"f(x)\n"
|
||||
"g(x);\n"
|
||||
"f(x)\n"
|
||||
"try { q(); } catch (...) {}\n"
|
||||
"}\n"));
|
||||
EXPECT_EQ("class A {\n"
|
||||
" A() : t(0) {}\n"
|
||||
" A(X x)\n" // FIXME: function-level try blocks are broken.
|
||||
" try : t(0) {\n"
|
||||
" }\n"
|
||||
" catch (...) {\n"
|
||||
" }\n"
|
||||
"};",
|
||||
format("class A {\n"
|
||||
" A()\n : t(0) {}\n"
|
||||
" A(X x)\n"
|
||||
" try : t(0) {} catch (...) {}\n"
|
||||
"};"));
|
||||
}
|
||||
|
||||
TEST_F(FormatTest, IndentPreprocessorDirectivesAtZero) {
|
||||
|
|
Loading…
Reference in New Issue