diff --git a/src/libs/cplusplus/pp-engine.cpp b/src/libs/cplusplus/pp-engine.cpp index ba8470e50e1..93c743133ed 100644 --- a/src/libs/cplusplus/pp-engine.cpp +++ b/src/libs/cplusplus/pp-engine.cpp @@ -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 > *actuals) { Q_ASSERT(tk); @@ -1468,12 +1481,22 @@ bool Preprocessor::collectActualArguments(PPToken *tk, QVector 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); } diff --git a/src/libs/cplusplus/pp-engine.h b/src/libs/cplusplus/pp-engine.h index c394a77cfcf..c994df473de 100644 --- a/src/libs/cplusplus/pp-engine.h +++ b/src/libs/cplusplus/pp-engine.h @@ -218,6 +218,8 @@ private: QVector tokenize(const QByteArray &text) const; + bool scanComment(PPToken *tk); + bool consumeComments(PPToken *tk); bool collectActualArguments(PPToken *tk, QVector > *actuals); void scanActualArgument(PPToken *tk, QVector *tokens); diff --git a/tests/auto/cplusplus/preprocessor/tst_preprocessor.cpp b/tests/auto/cplusplus/preprocessor/tst_preprocessor.cpp index 12d6979c109..376716a9e78 100644 --- a/tests/auto/cplusplus/preprocessor/tst_preprocessor.cpp +++ b/tests/auto/cplusplus/preprocessor/tst_preprocessor.cpp @@ -1631,6 +1631,123 @@ void tst_Preprocessor::comments_within_data() "# 12 \"\"\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 \"\"\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 \"\"\n" + " ;\n" + "# expansion begin 416,7 12:12 ~1 12:15\n" + "i = 3\n" + "# expansion end\n" + "# 12 \"\"\n" + " ;\n" + "# expansion begin 435,7 13:12 ~1 13:15\n" + "i = 3\n" + "# expansion end\n" + "# 13 \"\"\n" + " ;\n" + "# expansion begin 454,7 14:12 ~1 14:15\n" + "i = 3\n" + "# expansion end\n" + "# 14 \"\"\n" + " ;\n" + "# expansion begin 473,7 15:12 ~1 15:15\n" + "i = 3\n" + "# expansion end\n" + "# 15 \"\"\n" + " ;\n" + "# expansion begin 492,7 16:12 ~1 16:15\n" + "i = 3\n" + "# expansion end\n" + "# 16 \"\"\n" + " ;\n" + "# expansion begin 511,7 17:12\n" + "i\n" + "# expansion end\n" + "# 17 \"\"\n" + " ;\n" + "}\n" + ) << _( + "# 1 \"\"\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 \"\"\n" + " ;\n" + "# expansion begin 416,7 12:12 ~1 12:15\n" + "i = 3\n" + "# expansion end\n" + "# 12 \"\"\n" + " ;\n" + "# expansion begin 435,7 13:12 ~1 13:15\n" + "i = 3\n" + "# expansion end\n" + "# 13 \"\"\n" + " ;\n" + "# expansion begin 454,7 14:12 ~1 14:15\n" + "i = 3\n" + "# expansion end\n" + "# 14 \"\"\n" + " ;\n" + "# expansion begin 473,7 15:12 ~1 15:15\n" + "i = 3\n" + "# expansion end\n" + "# 15 \"\"\n" + " ;\n" + "# expansion begin 492,7 16:12 ~1 16:15\n" + "i = 3\n" + "# expansion end\n" + "# 16 \"\"\n" + " ;\n" + "# expansion begin 511,7 17:12\n" + "i\n" + "# expansion end\n" + "# 17 \"\"\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(""), - "\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()