Uploaded image for project: 'Qt'
  1. Qt
  2. QTBUG-136097

Can't use the properties and signals when definitions such as them are enabled by `__has_include`

    XMLWordPrintable

Details

    • Bug
    • Resolution: Unresolved
    • P2: Important
    • 6.10
    • 6.8.3
    • Build tools: moc
    • None
    • Linux/Wayland, Windows

    Description

      When enabling definitions of properties, signals, etc. using `TEST_EXIST_FOR_TEST_NG` defined by `__has_include` as follows, the following issues.

      1. Properties or signals cannot be used from QML.
      2. When using `SIGNAL` or `SLOT` in QObject::connect, the target function cannot use.
      • testNG.h
        #ifndef TESTNG_H
        #define TESTNG_H
        
        #include <QDebug>
        
        #if __has_include("test.h")
        #include "test.h"
        #define TEST_EXIST_FOR_TEST_NG
        #endif
        
        class TestNG : public QObject
        {
            Q_OBJECT
        #ifdef TEST_EXIST_FOR_TEST_NG
            Q_PROPERTY(int num READ num WRITE setNum NOTIFY numChanged)
        #endif // TEST_EXIST_FOR_TEST_NG
        
        public:
            TestNG() : QObject(nullptr) {}
        #ifdef TEST_EXIST_FOR_TEST_NG
            TestNG(Test *test)
                : QObject(nullptr)
                , mTest(test)
            {
                qDebug()
                    << static_cast<bool>(
                        QObject::connect(
                            mTest,
                            SIGNAL(numChanged()),
                            this,
                            SLOT(slotTest())));
            }
            int num() const
            {
                return mNum;
            }
        
        signals:
            void numChanged();
            void calledSlotTest();
        
        public slots:
            void setNum(const int &nNum)
            {
                if (nNum != mNum) {
                    mNum = nNum;
                    emit numChanged();
                }
            }
            void slotTest()
            {
                qDebug() << __FUNCTION__;
                emit calledSlotTest();
            }
        
        private:
            Test *mTest;
        
        protected:
            int mNum = 0;
        #endif // TEST_EXIST_FOR_TEST_NG
        };
        
        #endif // TESTNG_H
        
      • test.h
        #ifndef TEST_H
        #define TEST_H
        
        #include <QObject>
        #include <QDebug>
        
        class Test : public QObject
        {
            Q_OBJECT
            Q_PROPERTY(int num READ num WRITE setNum NOTIFY numChanged)
        
        public:
            Test() : QObject(nullptr) {}
            int num() const
            {
                return mNum;
            }
        
        signals:
            void numChanged();
            void calledSlotTest();
        
        public slots:
            void setNum(const int &nNum)
            {
                if (nNum != mNum) {
                    mNum = nNum;
                    emit numChanged();
                }
            }
            void slotTest()
            {
                qDebug() << __FUNCTION__;
                emit calledSlotTest();
            }
        
        protected:
            int mNum = 0;
        };
        
        #endif // TEST_H
        
      • main.cpp
        #include <QGuiApplication>
        #include <QQmlApplicationEngine>
        #include <QQmlContext>
        
        #include "test.h"
        #include "testNG.h"
        
        int main(int argc, char *argv[])
        {
            QGuiApplication app(argc, argv);
        
            QQmlApplicationEngine engine;
        
            Test testObj;
            engine.rootContext()->setContextProperty("Test", &testObj);
        #ifdef TEST_EXIST_FOR_TEST_NG
            TestNG testNGObj(&testObj);
        #else
            TestNG testNGObj();
        #endif // TEST_EXIST_FOR_TEST_NG
            engine.rootContext()->setContextProperty("TestNG", &testNGObj);
        
            QObject::connect(
                &engine,
                &QQmlApplicationEngine::objectCreationFailed,
                &app,
                []() { QCoreApplication::exit(-1); },
                Qt::QueuedConnection);
            engine.loadFromModule("Main", "Main");
        
            return app.exec();
        }
        
      • Main.qml
        import QtQuick
        import QtQuick.Controls
        import QtQuick.Layouts
        import QtQml.Models
        import Main
        
        Window {
            id: root
            objectName: "Main.qml"
            width: 640
            height: 480
            visible: true
            title: qsTr("Main")
        
            property ObjectModel testModel: ObjectModel {
                Component.onCompleted: {
                    root.testModel.append(Test)
                    root.testModel.append(TestNG)
                }
            }
        
            ScrollView {
                anchors.fill: parent
                ColumnLayout {
                    Repeater {
                        id: contentsRepeater
                        model: root.testModel.count
                        delegate: RowLayout {
                            id: contentsRepeaterDelegate
                            required property int index
                            readonly property var target: root.testModel.get(index)
                            Text {
                                text: "" + contentsRepeaterDelegate.target
                            }
                            GridLayout {
                                columns: 2
                                Text {
                                    text: "num"
                                }
                                Text {
                                    text: contentsRepeaterDelegate.target.num
                                }
                                Button {
                                    Layout.columnSpan: 2
                                    text: "num count up"
                                    onReleased: {
                                        contentsRepeaterDelegate.target.num = contentsRepeaterDelegate.target.num + 1;
                                    }
                                }
                                Text {
                                    text: "onNumChangedTime"
                                }
                                Text {
                                    id: onNumChangedTimeText
                                }
                                Text {
                                    text: "onCalledSlotTestTime"
                                }
                                Text {
                                    id: onCalledSlotTestTimeText
                                }
                                Connections {
                                    target: contentsRepeaterDelegate.target
                                    function onNumChanged() {
                                        onNumChangedTimeText.text = new Date().toLocaleTimeString(Qt.locale(), "hh:mm:ss.zzz")
                                    }
                                    function onCalledSlotTest() {
                                        onCalledSlotTestTimeText.text = new Date().toLocaleTimeString(Qt.locale(), "hh:mm:ss.zzz")
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
        

      The following warning will be displayed when executed.

      2025-04-21 17:19:27.269 [37532] [21912] [warning] [qt.core.qobject.connect] - QObject::connect: No such slot TestNG::slotTest() in C:\work\projects\JVC\git\cannot-connect-to-slot\main\testNG.h:31
      2025-04-21 17:19:27.879 [37532] [21912] [warning] [default] - QML Connections: Detected function "onNumChanged" in Connections element. This is probably intended to be a signal handler but no signal of the target matches the name.
      2025-04-21 17:19:27.879 [37532] [21912] [warning] [default] - QML Connections: Detected function "onCalledSlotTest" in Connections element. This is probably intended to be a signal handler but no signal of the target matches the name.
      2025-04-21 17:19:27.881 [37532] [21912] [warning] [default] - Unable to assign [undefined] to QString
      2025-04-21 17:19:41.881 [37532] [21912] [warning] [default] - TypeError: Value is null and could not be converted to an object
      

      The issue seems to be that the created moc does not contain items enabled with `__has_include`.

      • moc_testNG.cpp
        /****************************************************************************
        ** Meta object code from reading C++ file 'testNG.h'
        **
        ** Created by: The Qt Meta Object Compiler version 68 (Qt 6.8.3)
        **
        ** WARNING! All changes made in this file will be lost!
        *****************************************************************************/
        
        #include "../../../../../../cannot-connect-to-slot/main/testNG.h"
        #include <QtCore/qmetatype.h>
        
        #include <QtCore/qtmochelpers.h>
        
        #include <memory>
        
        
        #include <QtCore/qxptype_traits.h>
        #if !defined(Q_MOC_OUTPUT_REVISION)
        #error "The header file 'testNG.h' doesn't include <QObject>."
        #elif Q_MOC_OUTPUT_REVISION != 68
        #error "This file was generated using the moc from 6.8.3. It"
        #error "cannot be used with the include files from this version of Qt."
        #error "(The moc has changed too much.)"
        #endif
        
        #ifndef Q_CONSTINIT
        #define Q_CONSTINIT
        #endif
        
        QT_WARNING_PUSH
        QT_WARNING_DISABLE_DEPRECATED
        QT_WARNING_DISABLE_GCC("-Wuseless-cast")
        namespace {
        struct qt_meta_tag_ZN6TestNGE_t {};
        } // unnamed namespace
        
        
        #ifdef QT_MOC_HAS_STRINGDATA
        static constexpr auto qt_meta_stringdata_ZN6TestNGE = QtMocHelpers::stringData(
            "TestNG"
        );
        #else  // !QT_MOC_HAS_STRINGDATA
        #error "qtmochelpers.h not found or too old."
        #endif // !QT_MOC_HAS_STRINGDATA
        
        Q_CONSTINIT static const uint qt_meta_data_ZN6TestNGE[] = {
        
        // content:
            12,       // revision
            0,       // classname
            0,    0, // classinfo
            0,    0, // methods
            0,    0, // properties
            0,    0, // enums/sets
            0,    0, // constructors
            0,       // flags
            0,       // signalCount
        
            0        // eod
        };
        
        Q_CONSTINIT const QMetaObject TestNG::staticMetaObject = { {
            QMetaObject::SuperData::link<QObject::staticMetaObject>(),
            qt_meta_stringdata_ZN6TestNGE.offsetsAndSizes,
            qt_meta_data_ZN6TestNGE,
            qt_static_metacall,
            nullptr,
            qt_incomplete_metaTypeArray<qt_meta_tag_ZN6TestNGE_t,
                // Q_OBJECT / Q_GADGET
                QtPrivate::TypeAndForceComplete<TestNG, std::true_type>
            >,
            nullptr
        } };
        
        void TestNG::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a)
        {
            auto *_t = static_cast<TestNG *>(_o);
            (void)_t;
            (void)_c;
            (void)_id;
            (void)_a;
        }
        
        const QMetaObject *TestNG::metaObject() const
        {
            return QObject::d_ptr->metaObject ? QObject::d_ptr->dynamicMetaObject() : &staticMetaObject;
        }
        
        void *TestNG::qt_metacast(const char *_clname)
        {
            if (!_clname) return nullptr;
            if (!strcmp(_clname, qt_meta_stringdata_ZN6TestNGE.stringdata0))
                return static_cast<void*>(this);
            return QObject::qt_metacast(_clname);
        }
        
        int TestNG::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
        {
            _id = QObject::qt_metacall(_c, _id, _a);
            return _id;
        }
        QT_WARNING_POP
        

      Attachments

        For Gerrit Dashboard: QTBUG-136097
        # Subject Branch Project Status CR V

        Activity

          People

            fabiankosmale Fabian Kosmale
            susumuendo Susumu Endo
            Votes:
            0 Vote for this issue
            Watchers:
            5 Start watching this issue

            Dates

              Created:
              Updated:

              Gerrit Reviews

                There is 1 open Gerrit change