moc: Add a hidden option to make QML macro warnings fatal

We don't want to make them fatal by default, as that could break user
projects with identifiers whose name collide with the macros (which is
fine if they don't actually want to use the registration macros).

However, when using qt_add_qml_module, we can assume that anything
looking like a registration macro should actually be one.

Prepare for this by adding a flag which makes the warning fatal,
and which can then be set in qtdeclarative.

Task-number: QTBUG-134148
Change-Id: I3a49968b05d66e4e4ca3a8a2dae1a7b543471c68
Reviewed-by: Ivan Solovev <ivan.solovev@qt.io>
This commit is contained in:
Fabian Kosmale 2025-03-04 13:10:38 +01:00
parent d5f00591cd
commit c170381f33
4 changed files with 28 additions and 3 deletions

View File

@ -285,6 +285,10 @@ int runMoc(int argc, char **argv)
activeQtMode.setFlags(QCommandLineOption::HiddenFromHelp);
parser.addOption(activeQtMode);
QCommandLineOption qmlMacroWarningIsFatal(QStringLiteral("fatal-qml-macro-warning"));
qmlMacroWarningIsFatal.setFlags(QCommandLineOption::HiddenFromHelp);
parser.addOption(qmlMacroWarningIsFatal);
QCommandLineOption noNotesOption(QStringLiteral("no-notes"));
noNotesOption.setDescription(QStringLiteral("Do not display notes."));
parser.addOption(noNotesOption);
@ -448,6 +452,8 @@ int runMoc(int argc, char **argv)
moc.displayNotes = false;
if (parser.isSet(noWarningsOption) || noNotesCompatValues.contains("w"_L1))
moc.displayWarnings = moc.displayNotes = false;
if (parser.isSet(qmlMacroWarningIsFatal))
moc.qmlMacroWarningIsFatal = true;
if (autoInclude) {
qsizetype spos = filename.lastIndexOf(QDir::separator());

View File

@ -1044,7 +1044,10 @@ void Moc::parse()
QByteArray msg("Potential QML registration macro was found, but no header containing it was included.\n"
"This might cause runtime errors in QML applications\n"
"Include <QtQmlIntegration/qqmlintegration.h> or <QtQml/qqmlregistration.h> to fix this.");
warning(qmlRegistrationMacroSymbol, msg.constData());
if (qmlMacroWarningIsFatal)
error(qmlRegistrationMacroSymbol, msg.constData());
else
warning(qmlRegistrationMacroSymbol, msg.constData());
}
if (!def.hasQObject && !def.hasQGadget && def.signalList.isEmpty() && def.slotList.isEmpty()

View File

@ -19,6 +19,7 @@ public:
bool displayWarnings = true;
bool displayNotes = true;
bool activeQtMode = false;
bool qmlMacroWarningIsFatal = false;
struct IncludePath
{

View File

@ -786,6 +786,7 @@ private slots:
void dontStripNamespaces();
void oldStyleCasts();
void faultyQmlRegistration_data();
void faultyQmlRegistration();
void warnOnExtraSignalSlotQualifiaction();
void uLongLong();
@ -1021,16 +1022,30 @@ void tst_Moc::oldStyleCasts()
#endif
}
void tst_Moc::faultyQmlRegistration_data()
{
QTest::addColumn<bool>("qmlWarningIsFatal");
QTest::addColumn<int>("exitCode");
QTest::newRow("normal") << false << EXIT_SUCCESS;
QTest::newRow("fatalWarning") << true << EXIT_FAILURE;
}
void tst_Moc::faultyQmlRegistration()
{
#ifdef MOC_CROSS_COMPILED
QSKIP("Not tested when cross-compiled");
#endif
#if QT_CONFIG(process)
QFETCH(bool, qmlWarningIsFatal);
QFETCH(int, exitCode);
QProcess proc;
proc.start(m_moc, QStringList(m_sourceDirectory + QStringLiteral("/faulty_qml_registration/faulty_registration.h")));
auto cmd = QStringList(m_sourceDirectory + QStringLiteral("/faulty_qml_registration/faulty_registration.h"));
if (qmlWarningIsFatal)
cmd += QStringLiteral("--fatal-qml-macro-warning");
proc.start(m_moc, cmd);
QVERIFY(proc.waitForFinished());
QCOMPARE(proc.exitCode(), 0);
QCOMPARE(proc.exitCode(), exitCode);
QByteArray errorMsg = proc.readAllStandardError();
QVERIFY2(errorMsg.contains("QML registration macro"), errorMsg.constData());
#else