diff options
-rw-r--r-- | src/tools/moc/moc.cpp | 23 | ||||
-rw-r--r-- | tests/auto/tools/moc/faulty_qml_registration/CMakeLists.txt | 18 | ||||
-rw-r--r-- | tests/auto/tools/moc/faulty_qml_registration/faulty_registration.cpp | 6 | ||||
-rw-r--r-- | tests/auto/tools/moc/faulty_qml_registration/faulty_registration.h | 13 | ||||
-rw-r--r-- | tests/auto/tools/moc/tst_moc.cpp | 18 |
5 files changed, 78 insertions, 0 deletions
diff --git a/src/tools/moc/moc.cpp b/src/tools/moc/moc.cpp index 283a75dad20..27655dbe2aa 100644 --- a/src/tools/moc/moc.cpp +++ b/src/tools/moc/moc.cpp @@ -869,6 +869,7 @@ void Moc::parse() continue; ClassDef def; if (parseClassHead(&def)) { + Symbol qmlRegistrationMacroSymbol = {}; prependNamespaces(def, namespaceList); FunctionDef::Access access = FunctionDef::Private; @@ -984,6 +985,17 @@ void Moc::parse() case SEMIC: case COLON: break; + case IDENTIFIER: + { + const QByteArray lex = lexem(); + if (lex.startsWith("QML_")) { + if ( lex == "QML_ELEMENT" || lex == "QML_NAMED_ELEMENT" + || lex == "QML_ANONYMOUS" || lex == "QML_VALUE_TYPE") { + qmlRegistrationMacroSymbol = symbol(); + } + } + } + Q_FALLTHROUGH(); default: FunctionDef funcDef; funcDef.access = access; @@ -1024,6 +1036,17 @@ void Moc::parse() next(RBRACE); + /* if the header is available, moc will see a Q_CLASSINFO entry; the + token is only visible if the header is missing + To avoid false positives, we only warn when encountering the token in a QObject or gadget + */ + if ((def.hasQObject || def.hasQGadget) && qmlRegistrationMacroSymbol.token != NOTOKEN) { + 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 (!def.hasQObject && !def.hasQGadget && def.signalList.isEmpty() && def.slotList.isEmpty() && def.propertyList.isEmpty() && def.enumDeclarations.isEmpty()) continue; // no meta object code required diff --git a/tests/auto/tools/moc/faulty_qml_registration/CMakeLists.txt b/tests/auto/tools/moc/faulty_qml_registration/CMakeLists.txt new file mode 100644 index 00000000000..c0a60687ee4 --- /dev/null +++ b/tests/auto/tools/moc/faulty_qml_registration/CMakeLists.txt @@ -0,0 +1,18 @@ +# Copyright (C) 2025 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + +# This folder is intentionally not added in the parent directory +# The project structure here is only there to support running it as +# a manual test +cmake_minimum_required(VERSION 3.16) + +project(test_add_resource_options) + +find_package(Qt6Core REQUIRED) + +qt_wrap_cpp(faulty_registration.h) + + +qt6_add_executable(faulty_registration faulty_registration.h faulty_registration.cpp) +target_link_libraries(faulty_registration PRIVATE Qt::Core) + diff --git a/tests/auto/tools/moc/faulty_qml_registration/faulty_registration.cpp b/tests/auto/tools/moc/faulty_qml_registration/faulty_registration.cpp new file mode 100644 index 00000000000..d42f20871dd --- /dev/null +++ b/tests/auto/tools/moc/faulty_qml_registration/faulty_registration.cpp @@ -0,0 +1,6 @@ +// Copyright (C) 2025 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only + +#include "faulty_registration.h" + +int main() {} diff --git a/tests/auto/tools/moc/faulty_qml_registration/faulty_registration.h b/tests/auto/tools/moc/faulty_qml_registration/faulty_registration.h new file mode 100644 index 00000000000..abefcd7d4f5 --- /dev/null +++ b/tests/auto/tools/moc/faulty_qml_registration/faulty_registration.h @@ -0,0 +1,13 @@ +// Copyright (C) 2025 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only +#ifndef FAULTY_REGISTRATION +#define FAULTY_REGISTRATION + +#include <QObject> + +struct Faulty : QObject { + Q_OBJECT + QML_ELEMENT +}; + +#endif diff --git a/tests/auto/tools/moc/tst_moc.cpp b/tests/auto/tools/moc/tst_moc.cpp index 6ba72d2fbe0..09f7a9c75de 100644 --- a/tests/auto/tools/moc/tst_moc.cpp +++ b/tests/auto/tools/moc/tst_moc.cpp @@ -786,6 +786,7 @@ private slots: void dontStripNamespaces(); void oldStyleCasts(); + void faultyQmlRegistration(); void warnOnExtraSignalSlotQualifiaction(); void uLongLong(); void inputFileNameWithDotsButNoExtension(); @@ -1020,6 +1021,23 @@ void tst_Moc::oldStyleCasts() #endif } +void tst_Moc::faultyQmlRegistration() +{ +#ifdef MOC_CROSS_COMPILED + QSKIP("Not tested when cross-compiled"); +#endif +#if QT_CONFIG(process) + QProcess proc; + proc.start(m_moc, QStringList(m_sourceDirectory + QStringLiteral("/faulty_qml_registration/faulty_registration.h"))); + QVERIFY(proc.waitForFinished()); + QCOMPARE(proc.exitCode(), 0); + QByteArray errorMsg = proc.readAllStandardError(); + QVERIFY2(errorMsg.contains("QML registration macro"), errorMsg.constData()); +#else + QSKIP("Requires QProcess"); +#endif +} + void tst_Moc::warnOnExtraSignalSlotQualifiaction() { #ifdef MOC_CROSS_COMPILED |