moc: output errors and warnings in a way that matches compilers

gcc, clang, and MSVC all use lowercase "warning:", "error:" and
"note:". Follow that standard.
Also, include a column number; just print 1, as the Symbol doesn't
give us a column number, and searching backwards for a newline seems
overkill.

This fixes IDE integrations that parse compiler output using regular
expressions.

The test checks for moc output, but most tests were so far only
running on Linux systems. Expand this to Unix for most tests, which
then includes macOS.

Change-Id: I0a6151cc0dc50e52ca72ff8048a45213aebdb3a8
Reviewed-by: Lars Knoll <lars.knoll@qt.io>
This commit is contained in:
Volker Hilsheimer 2020-11-05 18:23:32 +01:00
parent 8379de41f6
commit f9058a7534
2 changed files with 60 additions and 60 deletions

View File

@ -40,9 +40,9 @@ Symbol::LexemStore Symbol::lexemStore;
static const char *error_msg = nullptr; static const char *error_msg = nullptr;
#ifdef Q_CC_MSVC #ifdef Q_CC_MSVC
#define ErrorFormatString "%s(%d): " #define ErrorFormatString "%s(%d:%d): "
#else #else
#define ErrorFormatString "%s:%d: " #define ErrorFormatString "%s:%d:%d: "
#endif #endif
void Parser::error(int rollback) { void Parser::error(int rollback) {
@ -51,24 +51,24 @@ void Parser::error(int rollback) {
} }
void Parser::error(const char *msg) { void Parser::error(const char *msg) {
if (msg || error_msg) if (msg || error_msg)
fprintf(stderr, ErrorFormatString "Error: %s\n", fprintf(stderr, ErrorFormatString "error: %s\n",
currentFilenames.top().constData(), symbol().lineNum, msg?msg:error_msg); currentFilenames.top().constData(), symbol().lineNum, 1, msg?msg:error_msg);
else else
fprintf(stderr, ErrorFormatString "Parse error at \"%s\"\n", fprintf(stderr, ErrorFormatString "error: Parse error at \"%s\"\n",
currentFilenames.top().constData(), symbol().lineNum, symbol().lexem().data()); currentFilenames.top().constData(), symbol().lineNum, 1, symbol().lexem().data());
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
void Parser::warning(const char *msg) { void Parser::warning(const char *msg) {
if (displayWarnings && msg) if (displayWarnings && msg)
fprintf(stderr, ErrorFormatString "Warning: %s\n", fprintf(stderr, ErrorFormatString "warning: %s\n",
currentFilenames.top().constData(), qMax(0, index > 0 ? symbol().lineNum : 0), msg); currentFilenames.top().constData(), qMax(0, index > 0 ? symbol().lineNum : 0), 1, msg);
} }
void Parser::note(const char *msg) { void Parser::note(const char *msg) {
if (displayNotes && msg) if (displayNotes && msg)
fprintf(stderr, ErrorFormatString "Note: %s\n", fprintf(stderr, ErrorFormatString "note: %s\n",
currentFilenames.top().constData(), qMax(0, index > 0 ? symbol().lineNum : 0), msg); currentFilenames.top().constData(), qMax(0, index > 0 ? symbol().lineNum : 0), 1, msg);
} }
QT_END_NAMESPACE QT_END_NAMESPACE

View File

@ -847,7 +847,7 @@ void tst_Moc::warnOnExtraSignalSlotQualifiaction()
#ifdef MOC_CROSS_COMPILED #ifdef MOC_CROSS_COMPILED
QSKIP("Not tested when cross-compiled"); QSKIP("Not tested when cross-compiled");
#endif #endif
#if defined(Q_OS_LINUX) && defined(Q_CC_GNU) && QT_CONFIG(process) #if defined(Q_OS_UNIX) && defined(Q_CC_GNU) && QT_CONFIG(process)
QProcess proc; QProcess proc;
const QString header = m_sourceDirectory + QStringLiteral("/extraqualification.h"); const QString header = m_sourceDirectory + QStringLiteral("/extraqualification.h");
proc.start(m_moc, QStringList(header)); proc.start(m_moc, QStringList(header));
@ -857,10 +857,10 @@ void tst_Moc::warnOnExtraSignalSlotQualifiaction()
QVERIFY(!mocOut.isEmpty()); QVERIFY(!mocOut.isEmpty());
QString mocWarning = QString::fromLocal8Bit(proc.readAllStandardError()); QString mocWarning = QString::fromLocal8Bit(proc.readAllStandardError());
QCOMPARE(mocWarning, header + QCOMPARE(mocWarning, header +
QString(":43: Warning: Function declaration Test::badFunctionDeclaration contains extra qualification. Ignoring as signal or slot.\n") + QString(":43:1: warning: Function declaration Test::badFunctionDeclaration contains extra qualification. Ignoring as signal or slot.\n") +
header + QString(":46: Warning: parsemaybe: Function declaration Test::anotherOne contains extra qualification. Ignoring as signal or slot.\n")); header + QString(":46:1: warning: parsemaybe: Function declaration Test::anotherOne contains extra qualification. Ignoring as signal or slot.\n"));
#else #else
QSKIP("Only tested on linux/gcc"); QSKIP("Only tested on unix/gcc");
#endif #endif
} }
@ -1142,7 +1142,7 @@ void tst_Moc::warnOnMultipleInheritance()
QVERIFY(!mocOut.isEmpty()); QVERIFY(!mocOut.isEmpty());
QString mocWarning = QString::fromLocal8Bit(proc.readAllStandardError()); QString mocWarning = QString::fromLocal8Bit(proc.readAllStandardError());
QCOMPARE(mocWarning, header + QCOMPARE(mocWarning, header +
QString(":43: Warning: Class Bar inherits from two QObject subclasses QWindow and Foo. This is not supported!\n")); QString(":43:1: warning: Class Bar inherits from two QObject subclasses QWindow and Foo. This is not supported!\n"));
#else #else
QSKIP("Only tested on linux/gcc"); QSKIP("Only tested on linux/gcc");
#endif #endif
@ -1206,7 +1206,7 @@ void tst_Moc::forgottenQInterface()
QVERIFY(!mocOut.isEmpty()); QVERIFY(!mocOut.isEmpty());
QString mocWarning = QString::fromLocal8Bit(proc.readAllStandardError()); QString mocWarning = QString::fromLocal8Bit(proc.readAllStandardError());
QCOMPARE(mocWarning, header + QCOMPARE(mocWarning, header +
QString(":45: Warning: Class Test implements the interface MyInterface but does not list it in Q_INTERFACES. qobject_cast to MyInterface will not work!\n")); QString(":45:1: warning: Class Test implements the interface MyInterface but does not list it in Q_INTERFACES. qobject_cast to MyInterface will not work!\n"));
#else #else
QSKIP("Only tested on linux/gcc"); QSKIP("Only tested on linux/gcc");
#endif #endif
@ -1320,7 +1320,7 @@ void tst_Moc::templateGtGt()
#ifdef MOC_CROSS_COMPILED #ifdef MOC_CROSS_COMPILED
QSKIP("Not tested when cross-compiled"); QSKIP("Not tested when cross-compiled");
#endif #endif
#if defined(Q_OS_LINUX) && defined(Q_CC_GNU) && QT_CONFIG(process) #if defined(Q_OS_UNIX) && defined(Q_CC_GNU) && QT_CONFIG(process)
QProcess proc; QProcess proc;
proc.start(m_moc, QStringList(m_sourceDirectory + QStringLiteral("/template-gtgt.h"))); proc.start(m_moc, QStringList(m_sourceDirectory + QStringLiteral("/template-gtgt.h")));
QVERIFY(proc.waitForFinished()); QVERIFY(proc.waitForFinished());
@ -1330,13 +1330,13 @@ void tst_Moc::templateGtGt()
QString mocWarning = QString::fromLocal8Bit(proc.readAllStandardError()); QString mocWarning = QString::fromLocal8Bit(proc.readAllStandardError());
QVERIFY(mocWarning.isEmpty()); QVERIFY(mocWarning.isEmpty());
#else #else
QSKIP("Only tested on linux/gcc"); QSKIP("Only tested on unix/gcc");
#endif #endif
} }
void tst_Moc::defineMacroViaCmdline() void tst_Moc::defineMacroViaCmdline()
{ {
#if defined(Q_OS_LINUX) && defined(Q_CC_GNU) && QT_CONFIG(process) #if defined(Q_OS_UNIX) && defined(Q_CC_GNU) && QT_CONFIG(process)
QProcess proc; QProcess proc;
QStringList args; QStringList args;
@ -1350,13 +1350,13 @@ void tst_Moc::defineMacroViaCmdline()
QByteArray mocOut = proc.readAllStandardOutput(); QByteArray mocOut = proc.readAllStandardOutput();
QVERIFY(!mocOut.isEmpty()); QVERIFY(!mocOut.isEmpty());
#else #else
QSKIP("Only tested on linux/gcc"); QSKIP("Only tested on unix/gcc");
#endif #endif
} }
void tst_Moc::defineMacroViaForcedInclude() void tst_Moc::defineMacroViaForcedInclude()
{ {
#if defined(Q_OS_LINUX) && defined(Q_CC_GNU) && QT_CONFIG(process) #if defined(Q_OS_UNIX) && defined(Q_CC_GNU) && QT_CONFIG(process)
QProcess proc; QProcess proc;
QStringList args; QStringList args;
@ -1370,13 +1370,13 @@ void tst_Moc::defineMacroViaForcedInclude()
QByteArray mocOut = proc.readAllStandardOutput(); QByteArray mocOut = proc.readAllStandardOutput();
QVERIFY(!mocOut.isEmpty()); QVERIFY(!mocOut.isEmpty());
#else #else
QSKIP("Only tested on linux/gcc"); QSKIP("Only tested on unix/gcc");
#endif #endif
} }
void tst_Moc::defineMacroViaForcedIncludeRelative() void tst_Moc::defineMacroViaForcedIncludeRelative()
{ {
#if defined(Q_OS_LINUX) && defined(Q_CC_GNU) && QT_CONFIG(process) #if defined(Q_OS_UNIX) && defined(Q_CC_GNU) && QT_CONFIG(process)
QProcess proc; QProcess proc;
QStringList args; QStringList args;
@ -1390,14 +1390,14 @@ void tst_Moc::defineMacroViaForcedIncludeRelative()
QByteArray mocOut = proc.readAllStandardOutput(); QByteArray mocOut = proc.readAllStandardOutput();
QVERIFY(!mocOut.isEmpty()); QVERIFY(!mocOut.isEmpty());
#else #else
QSKIP("Only tested on linux/gcc"); QSKIP("Only tested on unix/gcc");
#endif #endif
} }
void tst_Moc::environmentIncludePaths_data() void tst_Moc::environmentIncludePaths_data()
{ {
#if defined(Q_OS_LINUX) && defined(Q_CC_GNU) && QT_CONFIG(process) #if defined(Q_OS_UNIX) && defined(Q_CC_GNU) && QT_CONFIG(process)
QTest::addColumn<QString>("cmdline"); QTest::addColumn<QString>("cmdline");
QTest::addColumn<QString>("varname"); QTest::addColumn<QString>("varname");
@ -1411,7 +1411,7 @@ void tst_Moc::environmentIncludePaths_data()
void tst_Moc::environmentIncludePaths() void tst_Moc::environmentIncludePaths()
{ {
#if defined(Q_OS_LINUX) && defined(Q_CC_GNU) && QT_CONFIG(process) #if defined(Q_OS_UNIX) && defined(Q_CC_GNU) && QT_CONFIG(process)
QFETCH(QString, cmdline); QFETCH(QString, cmdline);
QFETCH(QString, varname); QFETCH(QString, varname);
@ -1436,7 +1436,7 @@ void tst_Moc::environmentIncludePaths()
QByteArray mocOut = proc.readAllStandardOutput(); QByteArray mocOut = proc.readAllStandardOutput();
QVERIFY(!mocOut.isEmpty()); QVERIFY(!mocOut.isEmpty());
#else #else
QSKIP("Only tested on linux/gcc"); QSKIP("Only tested on unix/gcc");
#endif #endif
} }
@ -1600,7 +1600,7 @@ void tst_Moc::warnOnPropertyWithoutREAD()
#ifdef MOC_CROSS_COMPILED #ifdef MOC_CROSS_COMPILED
QSKIP("Not tested when cross-compiled"); QSKIP("Not tested when cross-compiled");
#endif #endif
#if defined(Q_OS_LINUX) && defined(Q_CC_GNU) && QT_CONFIG(process) #if defined(Q_OS_UNIX) && defined(Q_CC_GNU) && QT_CONFIG(process)
QProcess proc; QProcess proc;
const QString header = m_sourceDirectory + QStringLiteral("/warn-on-property-without-read.h"); const QString header = m_sourceDirectory + QStringLiteral("/warn-on-property-without-read.h");
proc.start(m_moc, QStringList(header)); proc.start(m_moc, QStringList(header));
@ -1610,9 +1610,9 @@ void tst_Moc::warnOnPropertyWithoutREAD()
QVERIFY(!mocOut.isEmpty()); QVERIFY(!mocOut.isEmpty());
QString mocWarning = QString::fromLocal8Bit(proc.readAllStandardError()); QString mocWarning = QString::fromLocal8Bit(proc.readAllStandardError());
QCOMPARE(mocWarning, header + QCOMPARE(mocWarning, header +
QString(":36: Warning: Property declaration foo has neither an associated QProperty<> member, nor a READ accessor function nor an associated MEMBER variable. The property will be invalid.\n")); QString(":36:1: warning: Property declaration foo has neither an associated QProperty<> member, nor a READ accessor function nor an associated MEMBER variable. The property will be invalid.\n"));
#else #else
QSKIP("Only tested on linux/gcc"); QSKIP("Only tested on unix/gcc");
#endif #endif
} }
@ -1711,7 +1711,7 @@ void tst_Moc::warnOnVirtualSignal()
#ifdef MOC_CROSS_COMPILED #ifdef MOC_CROSS_COMPILED
QSKIP("Not tested when cross-compiled"); QSKIP("Not tested when cross-compiled");
#endif #endif
#if defined(Q_OS_LINUX) && defined(Q_CC_GNU) && QT_CONFIG(process) #if defined(Q_OS_UNIX) && defined(Q_CC_GNU) && QT_CONFIG(process)
QProcess proc; QProcess proc;
const QString header = m_sourceDirectory + QStringLiteral("/pure-virtual-signals.h"); const QString header = m_sourceDirectory + QStringLiteral("/pure-virtual-signals.h");
proc.start(m_moc, QStringList(header)); proc.start(m_moc, QStringList(header));
@ -1720,10 +1720,10 @@ void tst_Moc::warnOnVirtualSignal()
QByteArray mocOut = proc.readAllStandardOutput(); QByteArray mocOut = proc.readAllStandardOutput();
QVERIFY(!mocOut.isEmpty()); QVERIFY(!mocOut.isEmpty());
QString mocWarning = QString::fromLocal8Bit(proc.readAllStandardError()); QString mocWarning = QString::fromLocal8Bit(proc.readAllStandardError());
QCOMPARE(mocWarning, header + QString(":38: Warning: Signals cannot be declared virtual\n") + QCOMPARE(mocWarning, header + QString(":38:1: warning: Signals cannot be declared virtual\n") +
header + QString(":40: Warning: Signals cannot be declared virtual\n")); header + QString(":40:1: warning: Signals cannot be declared virtual\n"));
#else #else
QSKIP("Only tested on linux/gcc"); QSKIP("Only tested on unix/gcc");
#endif #endif
} }
@ -2060,7 +2060,7 @@ void tst_Moc::warnings_data()
<< QStringList() << QStringList()
<< 0 << 0
<< QString() << QString()
<< QString("standard input:0: Note: No relevant classes found. No output generated."); << QString("standard input:0:1: note: No relevant classes found. No output generated.");
// passing "-nn" should suppress "no relevant classes" note // passing "-nn" should suppress "no relevant classes" note
QTest::newRow("-nn") QTest::newRow("-nn")
@ -2084,7 +2084,7 @@ void tst_Moc::warnings_data()
<< QStringList() << QStringList()
<< 0 << 0
<< QString("IGNORE_ALL_STDOUT") << QString("IGNORE_ALL_STDOUT")
<< QString("standard input:1: Warning: Property declaration x has neither an associated QProperty<> member, nor a READ accessor function nor an associated MEMBER variable. The property will be invalid."); << QString("standard input:1:1: warning: Property declaration x has neither an associated QProperty<> member, nor a READ accessor function nor an associated MEMBER variable. The property will be invalid.");
// This should output a warning // This should output a warning
QTest::newRow("Duplicate property warning") QTest::newRow("Duplicate property warning")
@ -2092,7 +2092,7 @@ void tst_Moc::warnings_data()
<< QStringList() << QStringList()
<< 0 << 0
<< QString("IGNORE_ALL_STDOUT") << QString("IGNORE_ALL_STDOUT")
<< QString("standard input:1: Warning: The property 'x' is defined multiple times in class X."); << QString("standard input:1:1: warning: The property 'x' is defined multiple times in class X.");
// Passing "-nn" should NOT suppress the warning // Passing "-nn" should NOT suppress the warning
QTest::newRow("Invalid property warning with -nn") QTest::newRow("Invalid property warning with -nn")
@ -2100,7 +2100,7 @@ void tst_Moc::warnings_data()
<< (QStringList() << "-nn") << (QStringList() << "-nn")
<< 0 << 0
<< QString("IGNORE_ALL_STDOUT") << QString("IGNORE_ALL_STDOUT")
<< QString("standard input:1: Warning: Property declaration x has neither an associated QProperty<> member, nor a READ accessor function nor an associated MEMBER variable. The property will be invalid."); << QString("standard input:1:1: warning: Property declaration x has neither an associated QProperty<> member, nor a READ accessor function nor an associated MEMBER variable. The property will be invalid.");
// Passing "-nw" should suppress the warning // Passing "-nw" should suppress the warning
QTest::newRow("Invalid property warning with -nw") QTest::newRow("Invalid property warning with -nw")
@ -2116,7 +2116,7 @@ void tst_Moc::warnings_data()
<< QStringList() << QStringList()
<< 1 << 1
<< QString() << QString()
<< QString("standard input:1: Error: Class contains Q_OBJECT macro but does not inherit from QObject"); << QString("standard input:1:1: error: Class contains Q_OBJECT macro but does not inherit from QObject");
// "-nn" should not suppress the error // "-nn" should not suppress the error
QTest::newRow("Does not inherit QObject with -nn") QTest::newRow("Does not inherit QObject with -nn")
@ -2124,7 +2124,7 @@ void tst_Moc::warnings_data()
<< (QStringList() << "-nn") << (QStringList() << "-nn")
<< 1 << 1
<< QString() << QString()
<< QString("standard input:1: Error: Class contains Q_OBJECT macro but does not inherit from QObject"); << QString("standard input:1:1: error: Class contains Q_OBJECT macro but does not inherit from QObject");
// "-nw" should not suppress the error // "-nw" should not suppress the error
QTest::newRow("Does not inherit QObject with -nw") QTest::newRow("Does not inherit QObject with -nw")
@ -2132,7 +2132,7 @@ void tst_Moc::warnings_data()
<< (QStringList() << "-nw") << (QStringList() << "-nw")
<< 1 << 1
<< QString() << QString()
<< QString("standard input:1: Error: Class contains Q_OBJECT macro but does not inherit from QObject"); << QString("standard input:1:1: error: Class contains Q_OBJECT macro but does not inherit from QObject");
QTest::newRow("Warning on invalid macro") QTest::newRow("Warning on invalid macro")
<< QByteArray("#define Foo(a, b)\n class X : public QObject { Q_OBJECT }; \n Foo(a) \n Foo(a,b,c) \n") << QByteArray("#define Foo(a, b)\n class X : public QObject { Q_OBJECT }; \n Foo(a) \n Foo(a,b,c) \n")
@ -2146,63 +2146,63 @@ void tst_Moc::warnings_data()
<< QStringList() << QStringList()
<< 1 << 1
<< QString() << QString()
<< QString("standard input:5: Error: Class declaration lacks Q_OBJECT macro."); << QString("standard input:5:1: error: Class declaration lacks Q_OBJECT macro.");
QTest::newRow("Namespace declaration lacks Q_NAMESPACE macro.") QTest::newRow("Namespace declaration lacks Q_NAMESPACE macro.")
<< QByteArray("namespace X {\nQ_CLASSINFO(\"key\",\"value\")\nenum class MyEnum {Key1 = 1}\nQ_ENUMS(MyEnum)\n}\n") << QByteArray("namespace X {\nQ_CLASSINFO(\"key\",\"value\")\nenum class MyEnum {Key1 = 1}\nQ_ENUMS(MyEnum)\n}\n")
<< QStringList() << QStringList()
<< 1 << 1
<< QString() << QString()
<< QString("standard input:1: Error: Namespace declaration lacks Q_NAMESPACE macro."); << QString("standard input:1:1: error: Namespace declaration lacks Q_NAMESPACE macro.");
QTest::newRow("Wrong Q_ENUM context.") QTest::newRow("Wrong Q_ENUM context.")
<< QByteArray("namespace X {\nQ_NAMESPACE\n\nenum class MyEnum {Key1 = 1}\nQ_ENUM(MyEnum)\n}\n") << QByteArray("namespace X {\nQ_NAMESPACE\n\nenum class MyEnum {Key1 = 1}\nQ_ENUM(MyEnum)\n}\n")
<< QStringList() << QStringList()
<< 1 << 1
<< QString() << QString()
<< QString("standard input:5: Error: Q_ENUM can't be used in a Q_NAMESPACE, use Q_ENUM_NS instead"); << QString("standard input:5:1: error: Q_ENUM can't be used in a Q_NAMESPACE, use Q_ENUM_NS instead");
QTest::newRow("Wrong Q_FLAG context.") QTest::newRow("Wrong Q_FLAG context.")
<< QByteArray("namespace X {\nQ_NAMESPACE\n\nenum class MyEnum {Key1 = 1}\nQ_FLAG(MyEnum)\n}\n") << QByteArray("namespace X {\nQ_NAMESPACE\n\nenum class MyEnum {Key1 = 1}\nQ_FLAG(MyEnum)\n}\n")
<< QStringList() << QStringList()
<< 1 << 1
<< QString() << QString()
<< QString("standard input:5: Error: Q_FLAG can't be used in a Q_NAMESPACE, use Q_FLAG_NS instead"); << QString("standard input:5:1: error: Q_FLAG can't be used in a Q_NAMESPACE, use Q_FLAG_NS instead");
QTest::newRow("Wrong Q_ENUM_NS context.") QTest::newRow("Wrong Q_ENUM_NS context.")
<< QByteArray("class X {\nQ_GADGET\n\nenum class MyEnum {Key1 = 1}\nQ_ENUM_NS(MyEnum)\n};\n") << QByteArray("class X {\nQ_GADGET\n\nenum class MyEnum {Key1 = 1}\nQ_ENUM_NS(MyEnum)\n};\n")
<< QStringList() << QStringList()
<< 1 << 1
<< QString() << QString()
<< QString("standard input:5: Error: Q_ENUM_NS can't be used in a Q_OBJECT/Q_GADGET, use Q_ENUM instead"); << QString("standard input:5:1: error: Q_ENUM_NS can't be used in a Q_OBJECT/Q_GADGET, use Q_ENUM instead");
QTest::newRow("Wrong Q_FLAG_NS context.") QTest::newRow("Wrong Q_FLAG_NS context.")
<< QByteArray("class X {\nQ_GADGET\n\nenum class MyEnum {Key1 = 1}\nQ_FLAG_NS(MyEnum)\n};\n") << QByteArray("class X {\nQ_GADGET\n\nenum class MyEnum {Key1 = 1}\nQ_FLAG_NS(MyEnum)\n};\n")
<< QStringList() << QStringList()
<< 1 << 1
<< QString() << QString()
<< QString("standard input:5: Error: Q_FLAG_NS can't be used in a Q_OBJECT/Q_GADGET, use Q_FLAG instead"); << QString("standard input:5:1: error: Q_FLAG_NS can't be used in a Q_OBJECT/Q_GADGET, use Q_FLAG instead");
QTest::newRow("Invalid macro definition") QTest::newRow("Invalid macro definition")
<< QByteArray("#define Foo(a, b, c) a b c #a #b #c a##b##c #d\n Foo(45, 42, 39);") << QByteArray("#define Foo(a, b, c) a b c #a #b #c a##b##c #d\n Foo(45, 42, 39);")
<< QStringList() << QStringList()
<< 1 << 1
<< QString("IGNORE_ALL_STDOUT") << QString("IGNORE_ALL_STDOUT")
<< QString(":2: Error: '#' is not followed by a macro parameter"); << QString(":2:1: error: '#' is not followed by a macro parameter");
QTest::newRow("QTBUG-46210: crash on invalid macro invocation") QTest::newRow("QTBUG-46210: crash on invalid macro invocation")
<< QByteArray("#define Foo(a, b, c) a b c #a #b #c a##b##c\n Foo(45);") << QByteArray("#define Foo(a, b, c) a b c #a #b #c a##b##c\n Foo(45);")
<< QStringList() << QStringList()
<< 1 << 1
<< QString("IGNORE_ALL_STDOUT") << QString("IGNORE_ALL_STDOUT")
<< QString(":2: Error: Macro invoked with too few parameters for a use of '#'"); << QString(":2:1: error: Macro invoked with too few parameters for a use of '#'");
QTest::newRow("QTBUG-54609: crash on invalid input") QTest::newRow("QTBUG-54609: crash on invalid input")
<< QByteArray::fromBase64("EAkJCQkJbGFzcyBjbGFzcyBiYWkcV2kgTUEKcGYjZGVmaW5lIE1BKFEs/4D/FoQ=") << QByteArray::fromBase64("EAkJCQkJbGFzcyBjbGFzcyBiYWkcV2kgTUEKcGYjZGVmaW5lIE1BKFEs/4D/FoQ=")
<< QStringList() << QStringList()
<< 1 << 1
<< QString("IGNORE_ALL_STDOUT") << QString("IGNORE_ALL_STDOUT")
<< QString(":-1: Error: Unexpected character in macro argument list."); << QString(":-1:1: error: Unexpected character in macro argument list.");
QTest::newRow("Missing header warning") QTest::newRow("Missing header warning")
<< QByteArray("class X : public QObject { Q_OBJECT };") << QByteArray("class X : public QObject { Q_OBJECT };")
@ -2216,22 +2216,22 @@ void tst_Moc::warnings_data()
<< QStringList() << QStringList()
<< 0 << 0
<< QString() << QString()
<< QString("standard input:1: Note: No relevant classes found. No output generated."); << QString("standard input:1:1: note: No relevant classes found. No output generated.");
QTest::newRow("Q_PLUGIN_METADATA: invalid file") QTest::newRow("Q_PLUGIN_METADATA: invalid file")
<< QByteArray("class X { \n Q_PLUGIN_METADATA(FILE \"does.not.exists\") \n };") << QByteArray("class X { \n Q_PLUGIN_METADATA(FILE \"does.not.exists\") \n };")
<< QStringList() << QStringList()
<< 1 << 1
<< QString() << QString()
<< QString("standard input:2: Error: Plugin Metadata file \"does.not.exists\" does not exist. Declaration will be ignored"); << QString("standard input:2:1: error: Plugin Metadata file \"does.not.exists\" does not exist. Declaration will be ignored");
#ifdef Q_OS_LINUX // Limit to Linux because the error message is platform-dependent #ifdef Q_OS_UNIX // Limit to Unix because the error message is platform-dependent
QTest::newRow("Q_PLUGIN_METADATA: unreadable file") QTest::newRow("Q_PLUGIN_METADATA: unreadable file")
<< QByteArray("class X { \n Q_PLUGIN_METADATA(FILE \".\") \n };") << QByteArray("class X { \n Q_PLUGIN_METADATA(FILE \".\") \n };")
<< QStringList() << QStringList()
<< 1 << 1
<< QString() << QString()
<< QString("standard input:2: Error: Plugin Metadata file \".\" could not be opened: file to open is a directory"); << QString("standard input:2:1: error: Plugin Metadata file \".\" could not be opened: file to open is a directory");
#endif #endif
} }
@ -2247,9 +2247,9 @@ void tst_Moc::warnings()
QFETCH(QString, expectedStdErr); QFETCH(QString, expectedStdErr);
#ifdef Q_CC_MSVC #ifdef Q_CC_MSVC
// for some reasons, moc compiled with MSVC uses a different output format // moc compiled with MSVC uses a different output format to match MSVC compiler style
QRegularExpression lineNumberRe(":(-?\\d+):", QRegularExpression::InvertedGreedinessOption); QRegularExpression lineNumberRe(":(-?\\d+):(\\d+)", QRegularExpression::InvertedGreedinessOption);
expectedStdErr.replace(lineNumberRe, "(\\1):"); expectedStdErr.replace(lineNumberRe, "(\\1:\\2)");
#endif #endif
#if QT_CONFIG(process) #if QT_CONFIG(process)
@ -3519,7 +3519,7 @@ void tst_Moc::preprocessorOnly()
#ifdef MOC_CROSS_COMPILED #ifdef MOC_CROSS_COMPILED
QSKIP("Not tested when cross-compiled"); QSKIP("Not tested when cross-compiled");
#endif #endif
#if defined(Q_OS_LINUX) && defined(Q_CC_GNU) && QT_CONFIG(process) #if defined(Q_OS_UNIX) && defined(Q_CC_GNU) && QT_CONFIG(process)
QProcess proc; QProcess proc;
proc.start(m_moc, QStringList() << "-E" << m_sourceDirectory + QStringLiteral("/pp-dollar-signs.h")); proc.start(m_moc, QStringList() << "-E" << m_sourceDirectory + QStringLiteral("/pp-dollar-signs.h"));
QVERIFY(proc.waitForFinished()); QVERIFY(proc.waitForFinished());
@ -3530,7 +3530,7 @@ void tst_Moc::preprocessorOnly()
QVERIFY(mocOut.contains("$$ = parser->createFoo()")); QVERIFY(mocOut.contains("$$ = parser->createFoo()"));
#else #else
QSKIP("Only tested on linux/gcc"); QSKIP("Only tested on unix/gcc");
#endif #endif
} }
@ -3540,7 +3540,7 @@ void tst_Moc::unterminatedFunctionMacro()
#ifdef MOC_CROSS_COMPILED #ifdef MOC_CROSS_COMPILED
QSKIP("Not tested when cross-compiled"); QSKIP("Not tested when cross-compiled");
#endif #endif
#if defined(Q_OS_LINUX) && defined(Q_CC_GNU) && QT_CONFIG(process) #if defined(Q_OS_UNIX) && defined(Q_CC_GNU) && QT_CONFIG(process)
QProcess proc; QProcess proc;
proc.start(m_moc, QStringList() << "-E" << m_sourceDirectory + QStringLiteral("/unterminated-function-macro.h")); proc.start(m_moc, QStringList() << "-E" << m_sourceDirectory + QStringLiteral("/unterminated-function-macro.h"));
QVERIFY(proc.waitForFinished()); QVERIFY(proc.waitForFinished());