Commit a341094a authored by Orgad Shaneh's avatar Orgad Shaneh Committed by Orgad Shaneh

C++: Fix preprocessing of comments within function-like macro

Task-number: QTCREATORBUG-9535
Change-Id: Ifd94f674214314b3694be74cca297ddab873cd8c
Reviewed-by: default avatarNikolai Kosjar <nikolai.kosjar@theqtcompany.com>
parent 2a2d0a0c
......@@ -900,11 +900,7 @@ void Preprocessor::skipPreprocesorDirective(PPToken *tk)
ScopedBoolSwap s(m_state.m_inPreprocessorDirective, true);
while (isContinuationToken(*tk)) {
if (tk->isComment()) {
synchronizeOutputLines(*tk);
enforceSpacing(*tk, true);
currentOutputBuffer().append(tk->tokenStart(), tk->bytes());
}
scanComment(tk);
lex(tk);
}
}
......@@ -1461,6 +1457,23 @@ void Preprocessor::preprocess(const QString &fileName, const QByteArray &source,
m_state.popTokenBuffer();
}
bool Preprocessor::scanComment(Preprocessor::PPToken *tk)
{
if (!tk->isComment())
return false;
synchronizeOutputLines(*tk);
enforceSpacing(*tk, true);
currentOutputBuffer().append(tk->tokenStart(), tk->bytes());
return true;
}
bool Preprocessor::consumeComments(PPToken *tk)
{
while (scanComment(tk))
lex(tk);
return tk->isNot(T_EOF_SYMBOL);
}
bool Preprocessor::collectActualArguments(PPToken *tk, QVector<QVector<PPToken> > *actuals)
{
Q_ASSERT(tk);
......@@ -1468,12 +1481,22 @@ bool Preprocessor::collectActualArguments(PPToken *tk, QVector<QVector<PPToken>
lex(tk); // consume the identifier
// consume comments
while (tk->isComment()) {
bool lastCommentIsCpp = false;
while (scanComment(tk)) {
/* After C++ comments we need to add a new line
e.g.
#define foo(a, b) int a = b
foo // comment
(x, 3);
can result in
// commentint
x = 3;
*/
lastCommentIsCpp = tk->is(T_CPP_COMMENT) || tk->is(T_CPP_DOXY_COMMENT);
lex(tk);
if (!tk)
return false;
}
if (lastCommentIsCpp)
maybeStartOutputLine();
if (tk->isNot(T_LPAREN))
//### TODO: error message
......@@ -1639,6 +1662,9 @@ void Preprocessor::handleDefineDirective(PPToken *tk)
const unsigned defineOffset = tk->byteOffset;
lex(tk); // consume "define" token
if (!consumeComments(tk))
return;
if (tk->isNot(T_IDENTIFIER))
return;
......@@ -1658,6 +1684,8 @@ void Preprocessor::handleDefineDirective(PPToken *tk)
macro.setFunctionLike(true);
lex(tk); // skip `('
if (!consumeComments(tk))
return;
bool hasIdentifier = false;
if (isContinuationToken(*tk) && tk->is(T_IDENTIFIER)) {
......@@ -1665,13 +1693,19 @@ void Preprocessor::handleDefineDirective(PPToken *tk)
macro.addFormal(tk->asByteArrayRef().toByteArray());
lex(tk);
if (!consumeComments(tk))
return;
while (isContinuationToken(*tk) && tk->is(T_COMMA)) {
lex(tk);
if (!consumeComments(tk))
return;
if (isContinuationToken(*tk) && tk->is(T_IDENTIFIER)) {
macro.addFormal(tk->asByteArrayRef().toByteArray());
lex(tk);
if (!consumeComments(tk))
return;
} else {
hasIdentifier = false;
}
......@@ -1683,6 +1717,8 @@ void Preprocessor::handleDefineDirective(PPToken *tk)
if (!hasIdentifier)
macro.addFormal("__VA_ARGS__");
lex(tk); // consume elipsis token
if (!consumeComments(tk))
return;
}
if (isContinuationToken(*tk) && tk->is(T_RPAREN))
lex(tk); // consume ")" token
......@@ -1727,14 +1763,8 @@ void Preprocessor::handleDefineDirective(PPToken *tk)
previousUtf16charsOffset = tk->utf16charOffset;
previousLine = tk->lineno;
// Discard comments in macro definitions (keep comments flag doesn't apply here).
if (tk->isComment()) {
synchronizeOutputLines(*tk);
enforceSpacing(*tk, true);
currentOutputBuffer().append(tk->tokenStart(), tk->bytes());
} else {
if (!scanComment(tk))
bodyTokens.push_back(*tk);
}
lex(tk);
}
......
......@@ -218,6 +218,8 @@ private:
QVector<CPlusPlus::Token> tokenize(const QByteArray &text) const;
bool scanComment(PPToken *tk);
bool consumeComments(PPToken *tk);
bool collectActualArguments(PPToken *tk, QVector<QVector<PPToken> > *actuals);
void scanActualArgument(PPToken *tk, QVector<PPToken> *tokens);
......
......@@ -1631,6 +1631,123 @@ void tst_Preprocessor::comments_within_data()
"# 12 \"<stdin>\"\n"
"int foo = 4;"
);
QTest::newRow("inside_function_like_macro") << _(
"#define /* comment */ ASSIGN1(VAR, VALUE) VAR = VALUE\n"
"#define ASSIGN2(/* comment */ VAR, VALUE) VAR = VALUE\n"
"#define ASSIGN3(VAR /* comment */, VALUE) VAR = VALUE\n"
"#define ASSIGN4(VAR, /* comment */ VALUE) VAR = VALUE\n"
"#define ASSIGN5(VAR, VALUE /* comment */) VAR = VALUE\n"
"#define ASSIGN6(VAR, VALUE) /* comment */ VAR = VALUE\n"
"#define ASSIGN7(VAR, ... /* comment */) VAR\n"
"void func()\n"
"{\n"
" int i;\n"
" ASSIGN1(i, 3);\n"
" ASSIGN2(i, 3);\n"
" ASSIGN3(i, 3);\n"
" ASSIGN4(i, 3);\n"
" ASSIGN5(i, 3);\n"
" ASSIGN6(i, 3);\n"
" ASSIGN7(i, 3);\n"
"}\n"
) << _(
"# 1 \"<stdin>\"\n"
"\n"
"\n"
"\n"
"\n"
"\n"
"\n"
"\n"
"void func()\n"
"{\n"
" int i;\n"
"# expansion begin 397,7 11:12 ~1 11:15\n"
"i = 3\n"
"# expansion end\n"
"# 11 \"<stdin>\"\n"
" ;\n"
"# expansion begin 416,7 12:12 ~1 12:15\n"
"i = 3\n"
"# expansion end\n"
"# 12 \"<stdin>\"\n"
" ;\n"
"# expansion begin 435,7 13:12 ~1 13:15\n"
"i = 3\n"
"# expansion end\n"
"# 13 \"<stdin>\"\n"
" ;\n"
"# expansion begin 454,7 14:12 ~1 14:15\n"
"i = 3\n"
"# expansion end\n"
"# 14 \"<stdin>\"\n"
" ;\n"
"# expansion begin 473,7 15:12 ~1 15:15\n"
"i = 3\n"
"# expansion end\n"
"# 15 \"<stdin>\"\n"
" ;\n"
"# expansion begin 492,7 16:12 ~1 16:15\n"
"i = 3\n"
"# expansion end\n"
"# 16 \"<stdin>\"\n"
" ;\n"
"# expansion begin 511,7 17:12\n"
"i\n"
"# expansion end\n"
"# 17 \"<stdin>\"\n"
" ;\n"
"}\n"
) << _(
"# 1 \"<stdin>\"\n"
" /* comment */\n"
" /* comment */\n"
" /* comment */\n"
" /* comment */\n"
" /* comment */\n"
" /* comment */\n"
" /* comment */\n"
"void func()\n"
"{\n"
" int i;\n"
"# expansion begin 397,7 11:12 ~1 11:15\n"
"i = 3\n"
"# expansion end\n"
"# 11 \"<stdin>\"\n"
" ;\n"
"# expansion begin 416,7 12:12 ~1 12:15\n"
"i = 3\n"
"# expansion end\n"
"# 12 \"<stdin>\"\n"
" ;\n"
"# expansion begin 435,7 13:12 ~1 13:15\n"
"i = 3\n"
"# expansion end\n"
"# 13 \"<stdin>\"\n"
" ;\n"
"# expansion begin 454,7 14:12 ~1 14:15\n"
"i = 3\n"
"# expansion end\n"
"# 14 \"<stdin>\"\n"
" ;\n"
"# expansion begin 473,7 15:12 ~1 15:15\n"
"i = 3\n"
"# expansion end\n"
"# 15 \"<stdin>\"\n"
" ;\n"
"# expansion begin 492,7 16:12 ~1 16:15\n"
"i = 3\n"
"# expansion end\n"
"# 16 \"<stdin>\"\n"
" ;\n"
"# expansion begin 511,7 17:12\n"
"i\n"
"# expansion end\n"
"# 17 \"<stdin>\"\n"
" ;\n"
"}\n"
);
}
void tst_Preprocessor::comments_before_args()
......@@ -1641,17 +1758,32 @@ void tst_Preprocessor::comments_before_args()
Preprocessor preprocess(client, &env);
preprocess.setKeepComments(true);
QByteArray preprocessed = preprocess.run(QLatin1String("<stdin>"),
"\n#define foo(a,b) int a = b;"
"\nfoo/*C comment*/(a,1)\n"
"\nfoo/**Doxygen comment*/(b,2)\n"
"\nfoo//C++ comment\n(c,3)\n"
"\nfoo///Doxygen C++ comment\n(d,4)\n"
"\nfoo/*multiple*///comments\n/**as well*/(e,5)\n",
"#define foo(a,b) int a = b;\n"
"foo/*C comment*/(a,1)\n"
"foo/**Doxygen comment*/(b,2)\n"
"foo//C++ comment\n"
"(c,3)\n"
"foo///Doxygen C++ comment\n"
"(d,4)\n"
"foo/*multiple*///comments\n"
"/**as well*/(e,5)\n",
true, false);
preprocessed = preprocessed.simplified();
// DUMP_OUTPUT(preprocessed);
QVERIFY(compare(simplified(preprocessed), "int a=1;int b=2;int c=3;int d=4;int e=5;"));
QByteArray expected =
"\n"
" /*C comment*/int a = 1;\n"
" /**Doxygen comment*/int b = 2;\n"
" //C++ comment\n"
"int\n"
"c = 3;\n"
" ///Doxygen C++ comment\n"
"int\n"
"d = 4;\n"
" /*multiple*/ //comments\n"
"/**as well*/ int\n"
"e = 5;\n";
QVERIFY(compare(preprocessed, expected));
}
void tst_Preprocessor::multiline_strings()
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment