diff options
Diffstat (limited to 'src/qml/qml')
42 files changed, 1130 insertions, 468 deletions
diff --git a/src/qml/qml/ftw/qqmlrefcount_p.h b/src/qml/qml/ftw/qqmlrefcount_p.h index 140f129b21..b4f8acad49 100644 --- a/src/qml/qml/ftw/qqmlrefcount_p.h +++ b/src/qml/qml/ftw/qqmlrefcount_p.h @@ -113,25 +113,25 @@ QQmlRefCount::QQmlRefCount() QQmlRefCount::~QQmlRefCount() { - Q_ASSERT(refCount.load() == 0); + Q_ASSERT(refCount.loadRelaxed() == 0); } void QQmlRefCount::addref() const { - Q_ASSERT(refCount.load() > 0); + Q_ASSERT(refCount.loadRelaxed() > 0); refCount.ref(); } void QQmlRefCount::release() const { - Q_ASSERT(refCount.load() > 0); + Q_ASSERT(refCount.loadRelaxed() > 0); if (!refCount.deref()) delete this; } int QQmlRefCount::count() const { - return refCount.load(); + return refCount.loadRelaxed(); } template<class T> diff --git a/src/qml/qml/ftw/qqmlthread.cpp b/src/qml/qml/ftw/qqmlthread.cpp index 2ef1dc7e93..e961ed3d0d 100644 --- a/src/qml/qml/ftw/qqmlthread.cpp +++ b/src/qml/qml/ftw/qqmlthread.cpp @@ -104,14 +104,18 @@ QQmlThreadPrivate::MainObject::MainObject(QQmlThreadPrivate *p) // Trigger mainEvent in main thread. Must be called from thread. void QQmlThreadPrivate::triggerMainEvent() { +#if QT_CONFIG(thread) Q_ASSERT(q->isThisThread()); +#endif QCoreApplication::postEvent(&m_mainObject, new QEvent(QEvent::User)); } // Trigger even in thread. Must be called from main thread. void QQmlThreadPrivate::triggerThreadEvent() { +#if QT_CONFIG(thread) Q_ASSERT(!q->isThisThread()); +#endif QCoreApplication::postEvent(this, new QEvent(QEvent::User)); } @@ -353,6 +357,12 @@ void QQmlThread::internalCallMethodInThread(Message *message) void QQmlThread::internalCallMethodInMain(Message *message) { +#if !QT_CONFIG(thread) + message->call(this); + delete message; + return; +#endif + Q_ASSERT(isThisThread()); d->lock(); @@ -397,7 +407,9 @@ void QQmlThread::internalPostMethodToThread(Message *message) void QQmlThread::internalPostMethodToMain(Message *message) { +#if QT_CONFIG(thread) Q_ASSERT(isThisThread()); +#endif d->lock(); bool wasEmpty = d->mainList.isEmpty(); d->mainList.append(message); @@ -408,7 +420,9 @@ void QQmlThread::internalPostMethodToMain(Message *message) void QQmlThread::waitForNextMessage() { +#if QT_CONFIG(thread) Q_ASSERT(!isThisThread()); +#endif d->lock(); Q_ASSERT(d->m_mainThreadWaiting == false); diff --git a/src/qml/qml/qml.pri b/src/qml/qml/qml.pri index c625743f61..15ea12cbe7 100644 --- a/src/qml/qml/qml.pri +++ b/src/qml/qml/qml.pri @@ -1,5 +1,6 @@ SOURCES += \ $$PWD/qqml.cpp \ + $$PWD/qqmlerror.cpp \ $$PWD/qqmlopenmetaobject.cpp \ $$PWD/qqmlvmemetaobject.cpp \ $$PWD/qqmlengine.cpp \ @@ -142,7 +143,8 @@ HEADERS += \ $$PWD/qqmlpropertyresolver_p.h \ $$PWD/qqmltypecompiler_p.h \ $$PWD/qqmlpropertycachecreator_p.h \ - $$PWD/qqmlpropertyvalidator_p.h + $$PWD/qqmlpropertyvalidator_p.h \ + $$PWD/qqmlsourcecoordinate_p.h qtConfig(qml-xml-http-request) { HEADERS += \ diff --git a/src/qml/qml/qqml.cpp b/src/qml/qml/qqml.cpp index c1a8ed2a3d..613816e3f7 100644 --- a/src/qml/qml/qqml.cpp +++ b/src/qml/qml/qqml.cpp @@ -55,9 +55,7 @@ void qmlClearTypeRegistrations() // Declared in qqml.h { QQmlMetaType::clearTypeRegistrations(); QQmlEnginePrivate::baseModulesUninitialized = true; //So the engine re-registers its types -#if QT_CONFIG(library) qmlClearEnginePlugins(); -#endif } //From qqml.h @@ -113,4 +111,24 @@ int QQmlPrivate::qmlregister(RegistrationType type, void *data) return dtype.index(); } +void QQmlPrivate::qmlunregister(RegistrationType type, quintptr data) +{ + switch (type) { + case AutoParentRegistration: + QQmlMetaType::unregisterAutoParentFunction(reinterpret_cast<AutoParentFunction>(data)); + break; + case QmlUnitCacheHookRegistration: + QQmlMetaType::removeCachedUnitLookupFunction( + reinterpret_cast<QmlUnitCacheLookupFunction>(data)); + break; + case TypeRegistration: + case InterfaceRegistration: + case SingletonRegistration: + case CompositeRegistration: + case CompositeSingletonRegistration: + QQmlMetaType::unregisterType(data); + break; + } +} + QT_END_NAMESPACE diff --git a/src/qml/qml/qqml.h b/src/qml/qml/qqml.h index 7b3f89e943..4f3bfb76b0 100644 --- a/src/qml/qml/qqml.h +++ b/src/qml/qml/qqml.h @@ -608,9 +608,12 @@ Q_QML_EXPORT void qmlRegisterModule(const char *uri, int versionMajor, int versi template<typename T> QObject *qmlAttachedPropertiesObject(const QObject *obj, bool create = true) { - QObject *mutableObj = const_cast<QObject *>(obj); - return qmlAttachedPropertiesObject( - mutableObj, qmlAttachedPropertiesFunction(mutableObj, &T::staticMetaObject), create); + // We don't need a concrete object to resolve the function. As T is a C++ type, it and all its + // super types should be registered as CppType (or not at all). We only need the object and its + // QML engine to resolve composite types. Therefore, the function is actually a static property + // of the C++ type system and we can cache it here for improved performance on further lookups. + static const auto func = qmlAttachedPropertiesFunction(nullptr, &T::staticMetaObject); + return qmlAttachedPropertiesObject(const_cast<QObject *>(obj), func, create); } inline int qmlRegisterSingletonType(const char *uri, int versionMajor, int versionMinor, const char *typeName, @@ -621,13 +624,13 @@ inline int qmlRegisterSingletonType(const char *uri, int versionMajor, int versi uri, versionMajor, versionMinor, typeName, - callback, nullptr, nullptr, 0, 0 + callback, nullptr, nullptr, 0, 0, {} }; return QQmlPrivate::qmlregister(QQmlPrivate::SingletonRegistration, &api); } -enum { QmlCurrentSingletonTypeRegistrationVersion = 2 }; +enum { QmlCurrentSingletonTypeRegistrationVersion = 3 }; template <typename T> inline int qmlRegisterSingletonType(const char *uri, int versionMajor, int versionMinor, const char *typeName, QObject *(*callback)(QQmlEngine *, QJSEngine *)) @@ -639,7 +642,26 @@ inline int qmlRegisterSingletonType(const char *uri, int versionMajor, int versi uri, versionMajor, versionMinor, typeName, - nullptr, callback, &T::staticMetaObject, qRegisterNormalizedMetaType<T *>(pointerName.constData()), 0 + nullptr, nullptr, &T::staticMetaObject, qRegisterNormalizedMetaType<T *>(pointerName.constData()), 0, callback + }; + + return QQmlPrivate::qmlregister(QQmlPrivate::SingletonRegistration, &api); +} + +template <typename T, typename F, typename std::enable_if<std::is_convertible<F, std::function<QObject *(QQmlEngine *, QJSEngine *)>>::value + && !std::is_convertible<F, QObject *(*)(QQmlEngine *, QJSEngine *)>::value, void>::type* = nullptr> +inline int qmlRegisterSingletonType(const char *uri, int versionMajor, int versionMinor, const char *typeName, + F&& callback) +{ + + QML_GETTYPENAMES + + QQmlPrivate::RegisterSingletonType api = { + QmlCurrentSingletonTypeRegistrationVersion, + + uri, versionMajor, versionMinor, typeName, + + nullptr, nullptr, &T::staticMetaObject, qRegisterNormalizedMetaType<T *>(pointerName.constData()), 0, callback }; return QQmlPrivate::qmlregister(QQmlPrivate::SingletonRegistration, &api); diff --git a/src/qml/qml/qqmlapplicationengine.cpp b/src/qml/qml/qqmlapplicationengine.cpp index 1b7a433a84..7149f8c134 100644 --- a/src/qml/qml/qqmlapplicationengine.cpp +++ b/src/qml/qml/qqmlapplicationengine.cpp @@ -62,9 +62,6 @@ void QQmlApplicationEnginePrivate::cleanUp() obj->disconnect(q); qDeleteAll(objects); -#if QT_CONFIG(translation) - qDeleteAll(translators); -#endif } void QQmlApplicationEnginePrivate::init() @@ -75,10 +72,11 @@ void QQmlApplicationEnginePrivate::init() q->connect(q, &QQmlApplicationEngine::exit, QCoreApplication::instance(), &QCoreApplication::exit, Qt::QueuedConnection); #if QT_CONFIG(translation) - QTranslator* qtTranslator = new QTranslator; - if (qtTranslator->load(QLocale(), QLatin1String("qt"), QLatin1String("_"), QLibraryInfo::location(QLibraryInfo::TranslationsPath))) + QTranslator* qtTranslator = new QTranslator(q); + if (qtTranslator->load(QLocale(), QLatin1String("qt"), QLatin1String("_"), QLibraryInfo::location(QLibraryInfo::TranslationsPath), QLatin1String(".qm"))) QCoreApplication::installTranslator(qtTranslator); - translators << qtTranslator; + else + delete qtTranslator; #endif new QQmlFileSelector(q,q); QCoreApplication::instance()->setProperty("__qml_using_qqmlapplicationengine", QVariant(true)); @@ -90,15 +88,14 @@ void QQmlApplicationEnginePrivate::loadTranslations(const QUrl &rootFile) if (rootFile.scheme() != QLatin1String("file") && rootFile.scheme() != QLatin1String("qrc")) return; - QFileInfo fi(rootFile.toLocalFile()); + QFileInfo fi(QQmlFile::urlToLocalFileOrQrc(rootFile)); - QTranslator *translator = new QTranslator; - if (translator->load(QLocale(), QLatin1String("qml"), QLatin1String("_"), fi.path() + QLatin1String("/i18n"))) { + Q_Q(QQmlApplicationEngine); + QTranslator *translator = new QTranslator(q); + if (translator->load(QLocale(), QLatin1String("qml"), QLatin1String("_"), fi.path() + QLatin1String("/i18n"), QLatin1String(".qm"))) QCoreApplication::installTranslator(translator); - translators << translator; - } else { + else delete translator; - } #else Q_UNUSED(rootFile) #endif @@ -180,6 +177,9 @@ void QQmlApplicationEnginePrivate::finishLoad(QQmlComponent *c) \list \li Connecting Qt.quit() to QCoreApplication::quit() \li Automatically loads translation files from an i18n directory adjacent to the main QML file. + \list + \li Translation files must have "qml_" prefix e.g. qml_ja_JP.qm. + \endlist \li Automatically sets an incubation controller if the scene contains a QQuickWindow. \li Automatically sets a \c QQmlFileSelector as the url interceptor, applying file selectors to all QML files and assets. diff --git a/src/qml/qml/qqmlapplicationengine_p.h b/src/qml/qml/qqmlapplicationengine_p.h index 6cf6828832..7a341847bd 100644 --- a/src/qml/qml/qqmlapplicationengine_p.h +++ b/src/qml/qml/qqmlapplicationengine_p.h @@ -59,7 +59,6 @@ QT_BEGIN_NAMESPACE -class QTranslator; class QFileSelector; class Q_QML_PRIVATE_EXPORT QQmlApplicationEnginePrivate : public QQmlEnginePrivate { @@ -74,10 +73,6 @@ public: void loadTranslations(const QUrl &rootFile); void finishLoad(QQmlComponent *component); QList<QObject *> objects; - -#if QT_CONFIG(translation) - QList<QTranslator *> translators; -#endif }; QT_END_NAMESPACE diff --git a/src/qml/qml/qqmlcomponent.cpp b/src/qml/qml/qqmlcomponent.cpp index 04debc0615..59b5cc2691 100644 --- a/src/qml/qml/qqmlcomponent.cpp +++ b/src/qml/qml/qqmlcomponent.cpp @@ -64,7 +64,6 @@ #include <QThreadStorage> #include <QtCore/qdebug.h> #include <qqmlinfo.h> -#include "qqmlmemoryprofiler_p.h" namespace { QThreadStorage<int> creationDepth; @@ -774,7 +773,6 @@ QQmlComponent::QQmlComponent(QQmlComponentPrivate &dd, QObject *parent) QObject *QQmlComponent::create(QQmlContext *context) { Q_D(QQmlComponent); - QML_MEMORY_SCOPE_URL(url()); if (!context) context = d->engine->rootContext(); @@ -1206,7 +1204,7 @@ static void QQmlComponent_setQmlParent(QObject *me, QObject *parent) \js var component = Qt.createComponent("Button.qml"); if (component.status == Component.Ready) - component.createObject(parent, {"x": 100, "y": 100}); + component.createObject(parent, {x: 100, y: 100}); \endjs Dynamically created instances can be deleted with the \c destroy() method. diff --git a/src/qml/qml/qqmlcontext.cpp b/src/qml/qml/qqmlcontext.cpp index bd59409475..14892bd6ad 100644 --- a/src/qml/qml/qqmlcontext.cpp +++ b/src/qml/qml/qqmlcontext.cpp @@ -317,6 +317,12 @@ void QQmlContext::setContextProperty(const QString &name, const QVariant &value) d->propertyValues[idx] = value; QMetaObject::activate(this, d->notifyIndex, idx, nullptr); } + + if (auto *obj = qvariant_cast<QObject *>(value)) { + connect(obj, &QObject::destroyed, this, [d, name](QObject *destroyed) { + d->dropDestroyedQObject(name, destroyed); + }); + } } /*! @@ -524,6 +530,17 @@ QObject *QQmlContextPrivate::context_at(QQmlListProperty<QObject> *prop, int ind } } +void QQmlContextPrivate::dropDestroyedQObject(const QString &name, QObject *destroyed) +{ + const int idx = data->propertyNames().value(name); + Q_ASSERT(idx >= 0); + if (qvariant_cast<QObject *>(propertyValues[idx]) != destroyed) + return; + + propertyValues[idx] = QVariant::fromValue<QObject *>(nullptr); + QMetaObject::activate(q_func(), notifyIndex, idx, nullptr); +} + QQmlContextData::QQmlContextData() : QQmlContextData(nullptr) diff --git a/src/qml/qml/qqmlcontext_p.h b/src/qml/qml/qqmlcontext_p.h index 1ddd04c9ff..5f7316b00c 100644 --- a/src/qml/qml/qqmlcontext_p.h +++ b/src/qml/qml/qqmlcontext_p.h @@ -104,6 +104,8 @@ public: static int context_count(QQmlListProperty<QObject> *); static QObject *context_at(QQmlListProperty<QObject> *, int); + + void dropDestroyedQObject(const QString &name, QObject *destroyed); }; class QQmlComponentAttached; diff --git a/src/qml/qml/qqmlcustomparser.cpp b/src/qml/qml/qqmlcustomparser.cpp index 5cf87f5264..c477415ef7 100644 --- a/src/qml/qml/qqmlcustomparser.cpp +++ b/src/qml/qml/qqmlcustomparser.cpp @@ -100,7 +100,12 @@ void QQmlCustomParser::clearErrors() */ void QQmlCustomParser::error(const QV4::CompiledData::Location &location, const QString &description) { - exceptions << QQmlCompileError(location, description); + QQmlJS::DiagnosticMessage error; + error.line = location.line; + error.column = location.column; + error.message = description; + + exceptions << error; } struct StaticQtMetaObject : public QObject diff --git a/src/qml/qml/qqmlcustomparser_p.h b/src/qml/qml/qqmlcustomparser_p.h index c8e1300a1b..94671a4f35 100644 --- a/src/qml/qml/qqmlcustomparser_p.h +++ b/src/qml/qml/qqmlcustomparser_p.h @@ -83,7 +83,7 @@ public: virtual void verifyBindings(const QQmlRefPointer<QV4::ExecutableCompilationUnit> &, const QList<const QV4::CompiledData::Binding *> &) = 0; virtual void applyBindings(QObject *, const QQmlRefPointer<QV4::ExecutableCompilationUnit> &, const QList<const QV4::CompiledData::Binding *> &) = 0; - QVector<QQmlCompileError> errors() const { return exceptions; } + QVector<QQmlJS::DiagnosticMessage> errors() const { return exceptions; } protected: void error(const QV4::CompiledData::Binding *binding, const QString& description) @@ -97,7 +97,7 @@ protected: const QMetaObject *resolveType(const QString&) const; private: - QVector<QQmlCompileError> exceptions; + QVector<QQmlJS::DiagnosticMessage> exceptions; QQmlEnginePrivate *engine; const QQmlPropertyValidator *validator; Flags m_flags; diff --git a/src/qml/qml/qqmlengine.cpp b/src/qml/qml/qqmlengine.cpp index 691eb987f6..4460312e2c 100644 --- a/src/qml/qml/qqmlengine.cpp +++ b/src/qml/qml/qqmlengine.cpp @@ -811,9 +811,9 @@ void QQmlData::signalEmitted(QAbstractDeclarativeData *, QObject *object, int in // marshalled back onto the QObject's thread and handled by QML from there. This is tested // by the qqmlecmascript::threadSignal() autotest. if (ddata->notifyList && - QThread::currentThreadId() != QObjectPrivate::get(object)->threadData->threadId.load()) { + QThread::currentThreadId() != QObjectPrivate::get(object)->threadData->threadId.loadRelaxed()) { - if (!QObjectPrivate::get(object)->threadData->thread) + if (!QObjectPrivate::get(object)->threadData->thread.loadAcquire()) return; QMetaMethod m = QMetaObjectPrivate::signal(object->metaObject(), index); @@ -849,7 +849,7 @@ void QQmlData::signalEmitted(QAbstractDeclarativeData *, QObject *object, int in QQmlThreadNotifierProxyObject *mpo = new QQmlThreadNotifierProxyObject; mpo->target = object; - mpo->moveToThread(QObjectPrivate::get(object)->threadData->thread); + mpo->moveToThread(QObjectPrivate::get(object)->threadData->thread.loadAcquire()); QCoreApplication::postEvent(mpo, ev); } else { @@ -1169,6 +1169,13 @@ void QQmlEnginePrivate::registerFinalizeCallback(QObject *obj, int index) } } +QSharedPointer<QQmlImageProviderBase> QQmlEnginePrivate::imageProvider(const QString &providerId) const +{ + const QString providerIdLower = providerId.toLower(); + QMutexLocker locker(&mutex); + return imageProviders.value(providerIdLower); +} + #if QT_CONFIG(qml_network) /*! Sets the \a factory to use for creating QNetworkAccessManager(s). @@ -1258,8 +1265,10 @@ QNetworkAccessManager *QQmlEngine::networkAccessManager() const void QQmlEngine::addImageProvider(const QString &providerId, QQmlImageProviderBase *provider) { Q_D(QQmlEngine); + QString providerIdLower = providerId.toLower(); + QSharedPointer<QQmlImageProviderBase> sp(provider); QMutexLocker locker(&d->mutex); - d->imageProviders.insert(providerId.toLower(), QSharedPointer<QQmlImageProviderBase>(provider)); + d->imageProviders.insert(std::move(providerIdLower), std::move(sp)); } /*! @@ -1270,8 +1279,9 @@ void QQmlEngine::addImageProvider(const QString &providerId, QQmlImageProviderBa QQmlImageProviderBase *QQmlEngine::imageProvider(const QString &providerId) const { Q_D(const QQmlEngine); + const QString providerIdLower = providerId.toLower(); QMutexLocker locker(&d->mutex); - return d->imageProviders.value(providerId.toLower()).data(); + return d->imageProviders.value(providerIdLower).data(); } /*! @@ -1282,8 +1292,9 @@ QQmlImageProviderBase *QQmlEngine::imageProvider(const QString &providerId) cons void QQmlEngine::removeImageProvider(const QString &providerId) { Q_D(QQmlEngine); + const QString providerIdLower = providerId.toLower(); QMutexLocker locker(&d->mutex); - d->imageProviders.take(providerId.toLower()); + d->imageProviders.take(providerIdLower); } /*! @@ -2109,15 +2120,15 @@ QList<QQmlError> QQmlEnginePrivate::qmlErrorFromDiagnostics(const QString &fileN QList<QQmlError> errors; for (const DiagnosticMessage &m : diagnosticMessages) { if (m.isWarning()) { - qWarning("%s:%d : %s", qPrintable(fileName), m.loc.startLine, qPrintable(m.message)); + qWarning("%s:%d : %s", qPrintable(fileName), m.line, qPrintable(m.message)); continue; } QQmlError error; error.setUrl(QUrl(fileName)); error.setDescription(m.message); - error.setLine(m.loc.startLine); - error.setColumn(m.loc.startColumn); + error.setLine(m.line); + error.setColumn(m.column); errors << error; } return errors; @@ -2245,6 +2256,7 @@ void QQmlEngine::setPluginPathList(const QStringList &paths) d->importDatabase.setPluginPathList(paths); } +#if QT_CONFIG(library) /*! Imports the plugin named \a filePath with the \a uri provided. Returns true if the plugin was successfully imported; otherwise returns false. @@ -2258,6 +2270,7 @@ bool QQmlEngine::importPlugin(const QString &filePath, const QString &uri, QList Q_D(QQmlEngine); return d->importDatabase.importDynamicPlugin(filePath, uri, QString(), -1, errors); } +#endif /*! \property QQmlEngine::offlineStoragePath diff --git a/src/qml/qml/qqmlengine.h b/src/qml/qml/qqmlengine.h index da91c8fa15..31fe3a1849 100644 --- a/src/qml/qml/qqmlengine.h +++ b/src/qml/qml/qqmlengine.h @@ -114,7 +114,9 @@ public: bool addNamedBundle(const QString &name, const QString &fileName); +#if QT_CONFIG(library) bool importPlugin(const QString &filePath, const QString &uri, QList<QQmlError> *errors); +#endif #if QT_CONFIG(qml_network) void setNetworkAccessManagerFactory(QQmlNetworkAccessManagerFactory *); diff --git a/src/qml/qml/qqmlengine_p.h b/src/qml/qml/qqmlengine_p.h index 3b716683fd..e58ff554a7 100644 --- a/src/qml/qml/qqmlengine_p.h +++ b/src/qml/qml/qqmlengine_p.h @@ -167,6 +167,8 @@ public: mutable QQmlNetworkAccessManagerFactory *networkAccessManagerFactory; #endif QHash<QString,QSharedPointer<QQmlImageProviderBase> > imageProviders; + QSharedPointer<QQmlImageProviderBase> imageProvider(const QString &providerId) const; + QQmlAbstractUrlInterceptor* urlInterceptor; diff --git a/src/qml/qml/qqmlerror.cpp b/src/qml/qml/qqmlerror.cpp new file mode 100644 index 0000000000..739d5ce4cd --- /dev/null +++ b/src/qml/qml/qqmlerror.cpp @@ -0,0 +1,348 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qqmlerror.h" +#include "qqmlsourcecoordinate_p.h" +#include <private/qqmljsdiagnosticmessage_p.h> + +#include <QtCore/qdebug.h> +#include <QtCore/qfile.h> +#include <QtCore/qstringlist.h> +#include <QtCore/qvector.h> + +#include <QtCore/qobject.h> +#include <QtCore/qpointer.h> + +QT_BEGIN_NAMESPACE + +/*! + \class QQmlError + \since 5.0 + \inmodule QtQml + \brief The QQmlError class encapsulates a QML error. + + QQmlError includes a textual description of the error, as well + as location information (the file, line, and column). The toString() + method creates a single-line, human-readable string containing all of + this information, for example: + \code + file:///home/user/test.qml:7:8: Invalid property assignment: double expected + \endcode + + You can use qDebug(), qInfo(), or qWarning() to output errors to the console. + This method will attempt to open the file indicated by the error + and include additional contextual information. + \code + file:///home/user/test.qml:7:8: Invalid property assignment: double expected + y: "hello" + ^ + \endcode + + \sa QQuickView::errors(), QQmlComponent::errors() +*/ +class QQmlErrorPrivate : public QQmlJS::DiagnosticMessage +{ +public: + QQmlErrorPrivate() { type = QtWarningMsg; } + QUrl url; + QPointer<QObject> object; +}; + +/*! + Creates an empty error object. +*/ +QQmlError::QQmlError() +: d(nullptr) +{ +} + +/*! + Creates a copy of \a other. +*/ +QQmlError::QQmlError(const QQmlError &other) +: d(nullptr) +{ + *this = other; +} + +/*! + Assigns \a other to this error object. +*/ +QQmlError &QQmlError::operator=(const QQmlError &other) +{ + if (!other.d) { + delete d; + d = nullptr; + } else { + if (!d) + d = new QQmlErrorPrivate; + d->url = other.d->url; + d->message = other.d->message; + d->line = other.d->line; + d->column = other.d->column; + d->object = other.d->object; + d->type = other.d->type; + } + return *this; +} + +/*! + \internal +*/ +QQmlError::~QQmlError() +{ + delete d; d = nullptr; +} + +/*! + Returns true if this error is valid, otherwise false. +*/ +bool QQmlError::isValid() const +{ + return d != nullptr; +} + +/*! + Returns the url for the file that caused this error. +*/ +QUrl QQmlError::url() const +{ + if (d) + return d->url; + return QUrl(); +} + +/*! + Sets the \a url for the file that caused this error. +*/ +void QQmlError::setUrl(const QUrl &url) +{ + if (!d) + d = new QQmlErrorPrivate; + d->url = url; +} + +/*! + Returns the error description. +*/ +QString QQmlError::description() const +{ + if (d) + return d->message; + return QString(); +} + +/*! + Sets the error \a description. +*/ +void QQmlError::setDescription(const QString &description) +{ + if (!d) + d = new QQmlErrorPrivate; + d->message = description; +} + +/*! + Returns the error line number. +*/ +int QQmlError::line() const +{ + if (d) + return qmlConvertSourceCoordinate<quint32, int>(d->line); + return -1; +} + +/*! + Sets the error \a line number. +*/ +void QQmlError::setLine(int line) +{ + if (!d) + d = new QQmlErrorPrivate; + d->line = qmlConvertSourceCoordinate<int, quint32>(line); +} + +/*! + Returns the error column number. +*/ +int QQmlError::column() const +{ + if (d) + return qmlConvertSourceCoordinate<quint32, int>(d->column); + return -1; +} + +/*! + Sets the error \a column number. +*/ +void QQmlError::setColumn(int column) +{ + if (!d) + d = new QQmlErrorPrivate; + d->column = qmlConvertSourceCoordinate<int, quint32>(column); +} + +/*! + Returns the nearest object where this error occurred. + Exceptions in bound property expressions set this to the object + to which the property belongs. It will be 0 for all + other exceptions. + */ +QObject *QQmlError::object() const +{ + if (d) + return d->object; + return nullptr; +} + +/*! + Sets the nearest \a object where this error occurred. + */ +void QQmlError::setObject(QObject *object) +{ + if (!d) + d = new QQmlErrorPrivate; + d->object = object; +} + +/*! + \since 5.9 + + Returns the message type. + */ +QtMsgType QQmlError::messageType() const +{ + if (d) + return d->type; + return QtMsgType::QtWarningMsg; +} + +/*! + \since 5.9 + + Sets the \a messageType for this message. The message type determines which + QDebug handlers are responsible for receiving the message. + */ +void QQmlError::setMessageType(QtMsgType messageType) +{ + if (!d) + d = new QQmlErrorPrivate; + d->type = messageType; +} + +/*! + Returns the error as a human readable string. +*/ +QString QQmlError::toString() const +{ + QString rv; + + QUrl u(url()); + int l(line()); + + if (u.isEmpty() || (u.isLocalFile() && u.path().isEmpty())) + rv += QLatin1String("<Unknown File>"); + else + rv += u.toString(); + + if (l != -1) { + rv += QLatin1Char(':') + QString::number(l); + + int c(column()); + if (c != -1) + rv += QLatin1Char(':') + QString::number(c); + } + + rv += QLatin1String(": ") + description(); + + return rv; +} + +/*! + \relates QQmlError + \fn QDebug operator<<(QDebug debug, const QQmlError &error) + + Outputs a human readable version of \a error to \a debug. +*/ + +QDebug operator<<(QDebug debug, const QQmlError &error) +{ + debug << qPrintable(error.toString()); + + QUrl url = error.url(); + + if (error.line() > 0 && url.scheme() == QLatin1String("file")) { + QString file = url.toLocalFile(); + QFile f(file); + if (f.open(QIODevice::ReadOnly)) { + QByteArray data = f.readAll(); + QTextStream stream(data, QIODevice::ReadOnly); +#if QT_CONFIG(textcodec) + stream.setCodec("UTF-8"); +#endif + const QString code = stream.readAll(); + const auto lines = code.splitRef(QLatin1Char('\n')); + + if (lines.count() >= error.line()) { + const QStringRef &line = lines.at(error.line() - 1); + debug << "\n " << line.toLocal8Bit().constData(); + + if(error.column() > 0) { + int column = qMax(0, error.column() - 1); + column = qMin(column, line.length()); + + QByteArray ind; + ind.reserve(column); + for (int i = 0; i < column; ++i) { + const QChar ch = line.at(i); + if (ch.isSpace()) + ind.append(ch.unicode()); + else + ind.append(' '); + } + ind.append('^'); + debug << "\n " << ind.constData(); + } + } + } + } + return debug; +} + +QT_END_NAMESPACE diff --git a/src/qml/qml/qqmlerror.h b/src/qml/qml/qqmlerror.h new file mode 100644 index 0000000000..8ea493c11d --- /dev/null +++ b/src/qml/qml/qqmlerror.h @@ -0,0 +1,89 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQMLERROR_H +#define QQMLERROR_H + +#include <QtQml/qtqmlglobal.h> + +#include <QtCore/qurl.h> +#include <QtCore/qstring.h> + +QT_BEGIN_NAMESPACE + +// ### Qt 6: should this be called QQmlMessage, since it can have a message type? +class QDebug; +class QQmlErrorPrivate; +class Q_QML_EXPORT QQmlError +{ +public: + QQmlError(); + QQmlError(const QQmlError &); + QQmlError &operator=(const QQmlError &); + ~QQmlError(); + + bool isValid() const; + + QUrl url() const; + void setUrl(const QUrl &); + QString description() const; + void setDescription(const QString &); + int line() const; + void setLine(int); + int column() const; + void setColumn(int); + + QObject *object() const; + void setObject(QObject *); + + QtMsgType messageType() const; + void setMessageType(QtMsgType messageType); + + QString toString() const; +private: + QQmlErrorPrivate *d; +}; + +QDebug Q_QML_EXPORT operator<<(QDebug debug, const QQmlError &error); + +Q_DECLARE_TYPEINFO(QQmlError, Q_MOVABLE_TYPE); + +QT_END_NAMESPACE + +#endif // QQMLERROR_H diff --git a/src/qml/qml/qqmlexpression.cpp b/src/qml/qml/qqmlexpression.cpp index 6a11583f18..be0adc54a7 100644 --- a/src/qml/qml/qqmlexpression.cpp +++ b/src/qml/qml/qqmlexpression.cpp @@ -351,7 +351,7 @@ QString QQmlExpression::sourceFile() const int QQmlExpression::lineNumber() const { Q_D(const QQmlExpression); - return qmlSourceCoordinate(d->line); + return qmlConvertSourceCoordinate<quint16, int>(d->line); } /*! @@ -361,7 +361,7 @@ int QQmlExpression::lineNumber() const int QQmlExpression::columnNumber() const { Q_D(const QQmlExpression); - return qmlSourceCoordinate(d->column); + return qmlConvertSourceCoordinate<quint16, int>(d->column); } /*! @@ -372,8 +372,8 @@ void QQmlExpression::setSourceLocation(const QString &url, int line, int column) { Q_D(QQmlExpression); d->url = url; - d->line = qmlSourceCoordinate(line); - d->column = qmlSourceCoordinate(column); + d->line = qmlConvertSourceCoordinate<int, quint16>(line); + d->column = qmlConvertSourceCoordinate<int, quint16>(column); } /*! diff --git a/src/qml/qml/qqmlimport.cpp b/src/qml/qml/qqmlimport.cpp index 9d5801bbc6..95ab79070d 100644 --- a/src/qml/qml/qqmlimport.cpp +++ b/src/qml/qml/qqmlimport.cpp @@ -1020,13 +1020,6 @@ bool QQmlImportsPrivate::populatePluginPairVector(QVector<StaticPluginPair> &res return true; } -#if defined(QT_SHARED) || !QT_CONFIG(library) -static inline QString msgCannotLoadPlugin(const QString &uri, const QString &why) -{ - return QQmlImportDatabase::tr("plugin cannot be loaded for module \"%1\": %2").arg(uri, why); -} -#endif - /* Import an extension defined by a qmldir file. @@ -1075,7 +1068,7 @@ bool QQmlImportsPrivate::importExtension(const QString &qmldirFilePath, int dynamicPluginsFound = 0; int staticPluginsFound = 0; -#if defined(QT_SHARED) +#if QT_CONFIG(library) const auto qmldirPlugins = qmldir.plugins(); for (const QQmlDirParser::Plugin &plugin : qmldirPlugins) { QString resolvedFilePath = database->resolvePlugin(typeLoader, qmldirPath, plugin.path, plugin.name); @@ -1086,9 +1079,11 @@ bool QQmlImportsPrivate::importExtension(const QString &qmldirFilePath, // XXX TODO: should we leave the import plugin error alone? // Here, we pop it off the top and coalesce it into this error's message. // The reason is that the lower level may add url and line/column numbering information. - QQmlError poppedError = errors->takeFirst(); QQmlError error; - error.setDescription(msgCannotLoadPlugin(uri, poppedError.description())); + error.setDescription( + QQmlImportDatabase::tr( + "plugin cannot be loaded for module \"%1\": %2") + .arg(uri, errors->takeFirst().description())); error.setUrl(QUrl::fromLocalFile(qmldirFilePath)); errors->prepend(error); } @@ -1096,7 +1091,7 @@ bool QQmlImportsPrivate::importExtension(const QString &qmldirFilePath, } } } -#endif // QT_SHARED +#endif // QT_CONFIG(library) if (dynamicPluginsFound < qmldirPluginCount) { // Check if the missing plugins can be resolved statically. We do this by looking at @@ -2020,13 +2015,13 @@ bool QQmlImportDatabase::importStaticPlugin(QObject *instance, const QString &ba return true; } +#if QT_CONFIG(library) /*! \internal */ bool QQmlImportDatabase::importDynamicPlugin(const QString &filePath, const QString &uri, const QString &typeNamespace, int vmaj, QList<QQmlError> *errors) { -#if QT_CONFIG(library) QFileInfo fileInfo(filePath); const QString absoluteFilePath = fileInfo.absoluteFilePath(); @@ -2104,16 +2099,10 @@ bool QQmlImportDatabase::importDynamicPlugin(const QString &filePath, const QStr } return true; -#else - Q_UNUSED(filePath); - Q_UNUSED(uri); - Q_UNUSED(typeNamespace); - Q_UNUSED(vmaj); - Q_UNUSED(errors); - return false; -#endif } +#endif // QT_CONFIG(library) + void QQmlImportDatabase::clearDirCache() { QStringHash<QmldirCache *>::ConstIterator itr = qmldirCache.constBegin(); diff --git a/src/qml/qml/qqmlimport_p.h b/src/qml/qml/qqmlimport_p.h index d3055b552c..ea9c2eafb5 100644 --- a/src/qml/qml/qqmlimport_p.h +++ b/src/qml/qml/qqmlimport_p.h @@ -44,6 +44,7 @@ #include <QtCore/qcoreapplication.h> #include <QtCore/qset.h> #include <QtCore/qstringlist.h> +#include <QtQml/qqmlerror.h> #include <private/qqmldirparser_p.h> #include <private/qqmltype_p.h> #include <private/qstringhash_p.h> @@ -211,7 +212,9 @@ public: QQmlImportDatabase(QQmlEngine *); ~QQmlImportDatabase(); +#if QT_CONFIG(library) bool importDynamicPlugin(const QString &filePath, const QString &uri, const QString &importNamespace, int vmaj, QList<QQmlError> *errors); +#endif QStringList importPathList(PathType type = LocalOrRemote) const; void setImportPathList(const QStringList &paths); diff --git a/src/qml/qml/qqmlincubator.cpp b/src/qml/qml/qqmlincubator.cpp index 39da550d63..bc06226cbf 100644 --- a/src/qml/qml/qqmlincubator.cpp +++ b/src/qml/qml/qqmlincubator.cpp @@ -42,7 +42,6 @@ #include "qqmlincubator_p.h" #include "qqmlexpression_p.h" -#include "qqmlmemoryprofiler_p.h" #include "qqmlobjectcreator_p.h" void QQmlEnginePrivate::incubate(QQmlIncubator &i, QQmlContextData *forContext) @@ -272,8 +271,6 @@ void QQmlIncubatorPrivate::incubate(QQmlInstantiationInterrupt &i) if (!compilationUnit) return; - QML_MEMORY_SCOPE_URL(compilationUnit->finalUrl()); - QExplicitlySharedDataPointer<QQmlIncubatorPrivate> protectThis(this); QRecursionWatcher<QQmlIncubatorPrivate, &QQmlIncubatorPrivate::recursion> watcher(this); diff --git a/src/qml/qml/qqmlirloader_p.h b/src/qml/qml/qqmlirloader_p.h index aa303c923f..4812946ef0 100644 --- a/src/qml/qml/qqmlirloader_p.h +++ b/src/qml/qml/qqmlirloader_p.h @@ -51,6 +51,7 @@ // We mean it. // +#include <private/qtqmlglobal_p.h> #include <private/qv4compileddata_p.h> #include <private/qqmljsmemorypool_p.h> diff --git a/src/qml/qml/qqmlmetatype.cpp b/src/qml/qml/qqmlmetatype.cpp index a5b92d14f7..67fdf8847b 100644 --- a/src/qml/qml/qqmlmetatype.cpp +++ b/src/qml/qml/qqmlmetatype.cpp @@ -107,7 +107,7 @@ static QQmlTypePrivate *createQQmlType(QQmlMetaTypeData *data, const QString &el d->version_maj = type.versionMajor; d->version_min = type.versionMinor; - if (type.qobjectApi) { + if (type.qobjectApi || (type.version >= 3 && type.generalizedQobjectApi)) { if (type.version >= 1) // static metaobject added in version 1 d->baseMetaObject = type.instanceMetaObject; if (type.version >= 2) // typeId added in version 2 @@ -118,10 +118,14 @@ static QQmlTypePrivate *createQQmlType(QQmlMetaTypeData *data, const QString &el d->extraData.sd->singletonInstanceInfo = new QQmlType::SingletonInstanceInfo; d->extraData.sd->singletonInstanceInfo->scriptCallback = type.scriptApi; - d->extraData.sd->singletonInstanceInfo->qobjectCallback = type.qobjectApi; + if (type.version >= 3) { + d->extraData.sd->singletonInstanceInfo->qobjectCallback = type.generalizedQobjectApi; + } else { + d->extraData.sd->singletonInstanceInfo->qobjectCallback = type.qobjectApi; + } d->extraData.sd->singletonInstanceInfo->typeName = QString::fromUtf8(type.typeName); d->extraData.sd->singletonInstanceInfo->instanceMetaObject - = (type.qobjectApi && type.version >= 1) ? type.instanceMetaObject : nullptr; + = ((type.qobjectApi || (type.version >= 3 && type.generalizedQobjectApi) ) && type.version >= 1) ? type.instanceMetaObject : nullptr; return d; } @@ -281,7 +285,7 @@ void QQmlMetaType::clearTypeRegistrations() data->undeletableTypes.clear(); } -int QQmlMetaType::registerAutoParentFunction(QQmlPrivate::RegisterAutoParent &autoparent) +int QQmlMetaType::registerAutoParentFunction(const QQmlPrivate::RegisterAutoParent &autoparent) { QQmlMetaTypeDataPtr data; @@ -290,6 +294,12 @@ int QQmlMetaType::registerAutoParentFunction(QQmlPrivate::RegisterAutoParent &au return data->parentFunctions.count() - 1; } +void QQmlMetaType::unregisterAutoParentFunction(const QQmlPrivate::AutoParentFunction &function) +{ + QQmlMetaTypeDataPtr data; + data->parentFunctions.removeOne(function); +} + QQmlType QQmlMetaType::registerInterface(const QQmlPrivate::RegisterInterface &type) { if (type.version > 0) @@ -1193,7 +1203,8 @@ QQmlPropertyCache *QQmlMetaType::propertyCache(const QQmlType &type, int minorVe void QQmlMetaType::unregisterType(int typeIndex) { QQmlMetaTypeDataPtr data; - if (const QQmlTypePrivate *d = data->types.value(typeIndex).priv()) { + const QQmlType type = data->types.value(typeIndex); + if (const QQmlTypePrivate *d = type.priv()) { removeQQmlTypePrivate(data->idToType, d); removeQQmlTypePrivate(data->nameToType, d); removeQQmlTypePrivate(data->urlToType, d); @@ -1203,6 +1214,7 @@ void QQmlMetaType::unregisterType(int typeIndex) module->remove(d); data->clearPropertyCachesForMinorVersion(typeIndex); data->types[typeIndex] = QQmlType(); + data->undeletableTypes.remove(type); } } @@ -1324,7 +1336,7 @@ const QV4::CompiledData::Unit *QQmlMetaType::findCachedCompilationUnit(const QUr for (const auto lookup : qAsConst(data->lookupCachedQmlUnit)) { if (const QQmlPrivate::CachedQmlUnit *unit = lookup(uri)) { QString error; - if (!unit->qmlData->verifyHeader(QDateTime(), &error)) { + if (!QV4::ExecutableCompilationUnit::verifyHeader(unit->qmlData, QDateTime(), &error)) { qCDebug(DBG_DISK_CACHE) << "Error loading pre-compiled file " << uri << ":" << error; if (status) *status = CachedUnitLookupError::VersionMismatch; diff --git a/src/qml/qml/qqmlmetatype_p.h b/src/qml/qml/qqmlmetatype_p.h index 911e519cf2..c2535a7fd5 100644 --- a/src/qml/qml/qqmlmetatype_p.h +++ b/src/qml/qml/qqmlmetatype_p.h @@ -176,7 +176,9 @@ public: } } - static int registerAutoParentFunction(QQmlPrivate::RegisterAutoParent &autoparent); + static int registerAutoParentFunction(const QQmlPrivate::RegisterAutoParent &autoparent); + static void unregisterAutoParentFunction(const QQmlPrivate::AutoParentFunction &function); + static int registerUnitCacheHook(const QQmlPrivate::RegisterQmlUnitCacheHook &hookRegistration); static void clearTypeRegistrations(); diff --git a/src/qml/qml/qqmlnotifier.cpp b/src/qml/qml/qqmlnotifier.cpp index 0706b8c0cf..1359586b31 100644 --- a/src/qml/qml/qqmlnotifier.cpp +++ b/src/qml/qml/qqmlnotifier.cpp @@ -118,8 +118,8 @@ void QQmlNotifierEndpoint::connect(QObject *source, int sourceSignal, QQmlEngine disconnect(); Q_ASSERT(engine); - if (QObjectPrivate::get(source)->threadData->threadId.load() != - QObjectPrivate::get(engine)->threadData->threadId.load()) { + if (QObjectPrivate::get(source)->threadData->threadId.loadRelaxed() != + QObjectPrivate::get(engine)->threadData->threadId.loadRelaxed()) { QString sourceName; QDebug(&sourceName) << source; diff --git a/src/qml/qml/qqmlobjectcreator.cpp b/src/qml/qml/qqmlobjectcreator.cpp index e5f376fd34..be40eeb58a 100644 --- a/src/qml/qml/qqmlobjectcreator.cpp +++ b/src/qml/qml/qqmlobjectcreator.cpp @@ -939,7 +939,7 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *bindingProper auto bindingTarget = _bindingTarget; auto valueTypeProperty = _valueTypeProperty; - auto assignBinding = [qmlBinding, bindingTarget, targetProperty, subprop, bindingProperty, valueTypeProperty](QQmlObjectCreatorSharedState *sharedState) -> bool { + auto assignBinding = [qmlBinding, bindingTarget, targetProperty, subprop, bindingProperty, valueTypeProperty](QQmlObjectCreatorSharedState *sharedState) mutable -> bool { if (!qmlBinding->setTarget(bindingTarget, *targetProperty, subprop) && targetProperty->isAlias()) return false; @@ -1384,7 +1384,8 @@ QQmlContextData *QQmlObjectCreator::finalize(QQmlInstantiationInterrupt &interru QQmlPropertyData::DontRemoveBinding); if (!b->isValueTypeProxy()) { QQmlBinding *binding = static_cast<QQmlBinding*>(b.data()); - if (!binding->hasError() && !binding->hasDependencies()) + if (!binding->hasError() && !binding->hasDependencies() + && binding->context() && !binding->context()->unresolvedNames) b->removeFromObject(); } diff --git a/src/qml/qml/qqmlobjectcreator_p.h b/src/qml/qml/qqmlobjectcreator_p.h index 0766e2082e..1cbad87920 100644 --- a/src/qml/qml/qqmlobjectcreator_p.h +++ b/src/qml/qml/qqmlobjectcreator_p.h @@ -94,14 +94,14 @@ public: QQmlContextData *finalize(QQmlInstantiationInterrupt &interrupt); void clear(); - QQmlComponentAttached **componentAttachment() const { return &sharedState->componentAttached; } + QQmlComponentAttached **componentAttachment() { return &sharedState->componentAttached; } - QList<QQmlEnginePrivate::FinalizeCallback> *finalizeCallbacks() const { return &sharedState->finalizeCallbacks; } + QList<QQmlEnginePrivate::FinalizeCallback> *finalizeCallbacks() { return &sharedState->finalizeCallbacks; } QList<QQmlError> errors; QQmlContextData *parentContextData() const { return parentContext.contextData(); } - QFiniteStack<QPointer<QObject> > &allCreatedObjects() const { return sharedState->allCreatedObjects; } + QFiniteStack<QPointer<QObject> > &allCreatedObjects() { return sharedState->allCreatedObjects; } private: QQmlObjectCreator(QQmlContextData *contextData, const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit, QQmlObjectCreatorSharedState *inheritedSharedState); diff --git a/src/qml/qml/qqmlprivate.h b/src/qml/qml/qqmlprivate.h index ae84803648..eff78195d9 100644 --- a/src/qml/qml/qqmlprivate.h +++ b/src/qml/qml/qqmlprivate.h @@ -51,6 +51,8 @@ // We mean it. // +#include <functional> + #include <QtQml/qtqmlglobal.h> #include <QtCore/qglobal.h> @@ -276,6 +278,7 @@ namespace QQmlPrivate const QMetaObject *instanceMetaObject; // new in version 1 int typeId; // new in version 2 int revision; // new in version 2 + std::function<QObject*(QQmlEngine *, QJSEngine *)> generalizedQobjectApi; // new in version 3 // If this is extended ensure "version" is bumped!!! }; @@ -318,6 +321,7 @@ namespace QQmlPrivate }; int Q_QML_EXPORT qmlregister(RegistrationType, void *); + void Q_QML_EXPORT qmlunregister(RegistrationType, quintptr); } QT_END_NAMESPACE diff --git a/src/qml/qml/qqmlpropertycachecreator.cpp b/src/qml/qml/qqmlpropertycachecreator.cpp index bd4f2a0612..034ebfc743 100644 --- a/src/qml/qml/qqmlpropertycachecreator.cpp +++ b/src/qml/qml/qqmlpropertycachecreator.cpp @@ -45,6 +45,35 @@ QT_BEGIN_NAMESPACE QAtomicInt QQmlPropertyCacheCreatorBase::classIndexCounter(0); + +int QQmlPropertyCacheCreatorBase::metaTypeForPropertyType(QV4::CompiledData::BuiltinType type) +{ + switch (type) { + case QV4::CompiledData::BuiltinType::Var: return QMetaType::QVariant; + case QV4::CompiledData::BuiltinType::Variant: return QMetaType::QVariant; + case QV4::CompiledData::BuiltinType::Int: return QMetaType::Int; + case QV4::CompiledData::BuiltinType::Bool: return QMetaType::Bool; + case QV4::CompiledData::BuiltinType::Real: return QMetaType::Double; + case QV4::CompiledData::BuiltinType::String: return QMetaType::QString; + case QV4::CompiledData::BuiltinType::Url: return QMetaType::QUrl; + case QV4::CompiledData::BuiltinType::Color: return QMetaType::QColor; + case QV4::CompiledData::BuiltinType::Font: return QMetaType::QFont; + case QV4::CompiledData::BuiltinType::Time: return QMetaType::QTime; + case QV4::CompiledData::BuiltinType::Date: return QMetaType::QDate; + case QV4::CompiledData::BuiltinType::DateTime: return QMetaType::QDateTime; + case QV4::CompiledData::BuiltinType::Rect: return QMetaType::QRectF; + case QV4::CompiledData::BuiltinType::Point: return QMetaType::QPointF; + case QV4::CompiledData::BuiltinType::Size: return QMetaType::QSizeF; + case QV4::CompiledData::BuiltinType::Vector2D: return QMetaType::QVector2D; + case QV4::CompiledData::BuiltinType::Vector3D: return QMetaType::QVector3D; + case QV4::CompiledData::BuiltinType::Vector4D: return QMetaType::QVector4D; + case QV4::CompiledData::BuiltinType::Matrix4x4: return QMetaType::QMatrix4x4; + case QV4::CompiledData::BuiltinType::Quaternion: return QMetaType::QQuaternion; + case QV4::CompiledData::BuiltinType::InvalidBuiltin: break; + }; + return QMetaType::UnknownType; +} + QQmlBindingInstantiationContext::QQmlBindingInstantiationContext(int referencingObjectIndex, const QV4::CompiledData::Binding *instantiatingBinding, const QString &instantiatingPropertyName, QQmlPropertyCache *referencingObjectPropertyCache) : referencingObjectIndex(referencingObjectIndex) diff --git a/src/qml/qml/qqmlpropertycachecreator_p.h b/src/qml/qml/qqmlpropertycachecreator_p.h index 28eea27675..14f734277d 100644 --- a/src/qml/qml/qqmlpropertycachecreator_p.h +++ b/src/qml/qml/qqmlpropertycachecreator_p.h @@ -84,6 +84,8 @@ struct QQmlPropertyCacheCreatorBase Q_DECLARE_TR_FUNCTIONS(QQmlPropertyCacheCreatorBase) public: static QAtomicInt classIndexCounter; + + static int metaTypeForPropertyType(QV4::CompiledData::BuiltinType type); }; template <typename ObjectContainer> @@ -97,12 +99,12 @@ public: QQmlEnginePrivate *enginePrivate, const ObjectContainer *objectContainer, const QQmlImports *imports); - QQmlCompileError buildMetaObjects(); + QQmlJS::DiagnosticMessage buildMetaObjects(); protected: - QQmlCompileError buildMetaObjectRecursively(int objectIndex, const QQmlBindingInstantiationContext &context); - QQmlRefPointer<QQmlPropertyCache> propertyCacheForObject(const CompiledObject *obj, const QQmlBindingInstantiationContext &context, QQmlCompileError *error) const; - QQmlCompileError createMetaObject(int objectIndex, const CompiledObject *obj, const QQmlRefPointer<QQmlPropertyCache> &baseTypeCache); + QQmlJS::DiagnosticMessage buildMetaObjectRecursively(int objectIndex, const QQmlBindingInstantiationContext &context); + QQmlRefPointer<QQmlPropertyCache> propertyCacheForObject(const CompiledObject *obj, const QQmlBindingInstantiationContext &context, QQmlJS::DiagnosticMessage *error) const; + QQmlJS::DiagnosticMessage createMetaObject(int objectIndex, const CompiledObject *obj, const QQmlRefPointer<QQmlPropertyCache> &baseTypeCache); QString stringAt(int index) const { return objectContainer->stringAt(index); } @@ -128,14 +130,14 @@ inline QQmlPropertyCacheCreator<ObjectContainer>::QQmlPropertyCacheCreator(QQmlP } template <typename ObjectContainer> -inline QQmlCompileError QQmlPropertyCacheCreator<ObjectContainer>::buildMetaObjects() +inline QQmlJS::DiagnosticMessage QQmlPropertyCacheCreator<ObjectContainer>::buildMetaObjects() { QQmlBindingInstantiationContext context; return buildMetaObjectRecursively(/*root object*/0, context); } template <typename ObjectContainer> -inline QQmlCompileError QQmlPropertyCacheCreator<ObjectContainer>::buildMetaObjectRecursively(int objectIndex, const QQmlBindingInstantiationContext &context) +inline QQmlJS::DiagnosticMessage QQmlPropertyCacheCreator<ObjectContainer>::buildMetaObjectRecursively(int objectIndex, const QQmlBindingInstantiationContext &context) { const CompiledObject *obj = objectContainer->objectAt(objectIndex); @@ -155,8 +157,8 @@ inline QQmlCompileError QQmlPropertyCacheCreator<ObjectContainer>::buildMetaObje auto *typeRef = objectContainer->resolvedType(obj->inheritedTypeNameIndex); Q_ASSERT(typeRef); QQmlRefPointer<QQmlPropertyCache> baseTypeCache = typeRef->createPropertyCache(QQmlEnginePrivate::get(enginePrivate)); - QQmlCompileError error = createMetaObject(context.referencingObjectIndex, obj, baseTypeCache); - if (error.isSet()) + QQmlJS::DiagnosticMessage error = createMetaObject(context.referencingObjectIndex, obj, baseTypeCache); + if (error.isValid()) return error; } } else { @@ -170,16 +172,16 @@ inline QQmlCompileError QQmlPropertyCacheCreator<ObjectContainer>::buildMetaObje QQmlRefPointer<QQmlPropertyCache> baseTypeCache; { - QQmlCompileError error; + QQmlJS::DiagnosticMessage error; baseTypeCache = propertyCacheForObject(obj, context, &error); - if (error.isSet()) + if (error.isValid()) return error; } if (baseTypeCache) { if (needVMEMetaObject) { - QQmlCompileError error = createMetaObject(objectIndex, obj, baseTypeCache); - if (error.isSet()) + QQmlJS::DiagnosticMessage error = createMetaObject(objectIndex, obj, baseTypeCache); + if (error.isValid()) return error; } else { propertyCaches->set(objectIndex, baseTypeCache); @@ -200,18 +202,18 @@ inline QQmlCompileError QQmlPropertyCacheCreator<ObjectContainer>::buildMetaObje if (!context.resolveInstantiatingProperty()) pendingGroupPropertyBindings->append(context); - QQmlCompileError error = buildMetaObjectRecursively(binding->value.objectIndex, context); - if (error.isSet()) + QQmlJS::DiagnosticMessage error = buildMetaObjectRecursively(binding->value.objectIndex, context); + if (error.isValid()) return error; } } - QQmlCompileError noError; + QQmlJS::DiagnosticMessage noError; return noError; } template <typename ObjectContainer> -inline QQmlRefPointer<QQmlPropertyCache> QQmlPropertyCacheCreator<ObjectContainer>::propertyCacheForObject(const CompiledObject *obj, const QQmlBindingInstantiationContext &context, QQmlCompileError *error) const +inline QQmlRefPointer<QQmlPropertyCache> QQmlPropertyCacheCreator<ObjectContainer>::propertyCacheForObject(const CompiledObject *obj, const QQmlBindingInstantiationContext &context, QQmlJS::DiagnosticMessage *error) const { if (context.instantiatingProperty) { return context.instantiatingPropertyCache(enginePrivate); @@ -221,15 +223,15 @@ inline QQmlRefPointer<QQmlPropertyCache> QQmlPropertyCacheCreator<ObjectContaine if (typeRef->isFullyDynamicType) { if (obj->propertyCount() > 0 || obj->aliasCount() > 0) { - *error = QQmlCompileError(obj->location, QQmlPropertyCacheCreatorBase::tr("Fully dynamic types cannot declare new properties.")); + *error = qQmlCompileError(obj->location, QQmlPropertyCacheCreatorBase::tr("Fully dynamic types cannot declare new properties.")); return nullptr; } if (obj->signalCount() > 0) { - *error = QQmlCompileError(obj->location, QQmlPropertyCacheCreatorBase::tr("Fully dynamic types cannot declare new signals.")); + *error = qQmlCompileError(obj->location, QQmlPropertyCacheCreatorBase::tr("Fully dynamic types cannot declare new signals.")); return nullptr; } if (obj->functionCount() > 0) { - *error = QQmlCompileError(obj->location, QQmlPropertyCacheCreatorBase::tr("Fully Dynamic types cannot declare new functions.")); + *error = qQmlCompileError(obj->location, QQmlPropertyCacheCreatorBase::tr("Fully Dynamic types cannot declare new functions.")); return nullptr; } } @@ -256,7 +258,7 @@ inline QQmlRefPointer<QQmlPropertyCache> QQmlPropertyCacheCreator<ObjectContaine const QMetaObject *attachedMo = qmltype.attachedPropertiesType(enginePrivate); if (!attachedMo) { - *error = QQmlCompileError(context.instantiatingBinding->location, QQmlPropertyCacheCreatorBase::tr("Non-existent attached object")); + *error = qQmlCompileError(context.instantiatingBinding->location, QQmlPropertyCacheCreatorBase::tr("Non-existent attached object")); return nullptr; } return enginePrivate->cache(attachedMo); @@ -265,7 +267,7 @@ inline QQmlRefPointer<QQmlPropertyCache> QQmlPropertyCacheCreator<ObjectContaine } template <typename ObjectContainer> -inline QQmlCompileError QQmlPropertyCacheCreator<ObjectContainer>::createMetaObject(int objectIndex, const CompiledObject *obj, const QQmlRefPointer<QQmlPropertyCache> &baseTypeCache) +inline QQmlJS::DiagnosticMessage QQmlPropertyCacheCreator<ObjectContainer>::createMetaObject(int objectIndex, const CompiledObject *obj, const QQmlRefPointer<QQmlPropertyCache> &baseTypeCache) { QQmlRefPointer<QQmlPropertyCache> cache; cache.adopt(baseTypeCache->copyAndReserve(obj->propertyCount() + obj->aliasCount(), @@ -275,33 +277,6 @@ inline QQmlCompileError QQmlPropertyCacheCreator<ObjectContainer>::createMetaObj propertyCaches->set(objectIndex, cache); propertyCaches->setNeedsVMEMetaObject(objectIndex); - struct TypeData { - QV4::CompiledData::Property::Type dtype; - int metaType; - } builtinTypes[] = { - { QV4::CompiledData::Property::Var, QMetaType::QVariant }, - { QV4::CompiledData::Property::Variant, QMetaType::QVariant }, - { QV4::CompiledData::Property::Int, QMetaType::Int }, - { QV4::CompiledData::Property::Bool, QMetaType::Bool }, - { QV4::CompiledData::Property::Real, QMetaType::Double }, - { QV4::CompiledData::Property::String, QMetaType::QString }, - { QV4::CompiledData::Property::Url, QMetaType::QUrl }, - { QV4::CompiledData::Property::Color, QMetaType::QColor }, - { QV4::CompiledData::Property::Font, QMetaType::QFont }, - { QV4::CompiledData::Property::Time, QMetaType::QTime }, - { QV4::CompiledData::Property::Date, QMetaType::QDate }, - { QV4::CompiledData::Property::DateTime, QMetaType::QDateTime }, - { QV4::CompiledData::Property::Rect, QMetaType::QRectF }, - { QV4::CompiledData::Property::Point, QMetaType::QPointF }, - { QV4::CompiledData::Property::Size, QMetaType::QSizeF }, - { QV4::CompiledData::Property::Vector2D, QMetaType::QVector2D }, - { QV4::CompiledData::Property::Vector3D, QMetaType::QVector3D }, - { QV4::CompiledData::Property::Vector4D, QMetaType::QVector4D }, - { QV4::CompiledData::Property::Matrix4x4, QMetaType::QMatrix4x4 }, - { QV4::CompiledData::Property::Quaternion, QMetaType::QQuaternion } -}; - static const uint builtinTypeCount = sizeof(builtinTypes) / sizeof(TypeData); - QByteArray newClassName; if (objectIndex == /*root object*/0) { @@ -329,13 +304,13 @@ inline QQmlCompileError QQmlPropertyCacheCreator<ObjectContainer>::createMetaObj auto p = obj->propertiesBegin(); auto pend = obj->propertiesEnd(); for ( ; p != pend; ++p) { - if (p->type == QV4::CompiledData::Property::Var) + if (p->builtinType() == QV4::CompiledData::BuiltinType::Var) varPropCount++; bool notInRevision = false; QQmlPropertyData *d = resolver.property(stringAt(p->nameIndex), ¬InRevision); if (d && d->isFinal()) - return QQmlCompileError(p->location, QQmlPropertyCacheCreatorBase::tr("Cannot override FINAL property")); + return qQmlCompileError(p->location, QQmlPropertyCacheCreatorBase::tr("Cannot override FINAL property")); } auto a = obj->aliasesBegin(); @@ -344,7 +319,7 @@ inline QQmlCompileError QQmlPropertyCacheCreator<ObjectContainer>::createMetaObj bool notInRevision = false; QQmlPropertyData *d = resolver.property(stringAt(a->nameIndex), ¬InRevision); if (d && d->isFinal()) - return QQmlCompileError(a->location, QQmlPropertyCacheCreatorBase::tr("Cannot override FINAL property")); + return qQmlCompileError(a->location, QQmlPropertyCacheCreatorBase::tr("Cannot override FINAL property")); } int effectivePropertyIndex = cache->propertyIndexCacheStart; @@ -429,16 +404,15 @@ inline QQmlCompileError QQmlPropertyCacheCreator<ObjectContainer>::createMetaObj auto end = s->parametersEnd(); for ( ; param != end; ++param, ++i) { names.append(stringAt(param->nameIndex).toUtf8()); - if (param->type < builtinTypeCount) { + if (param->indexIsBuiltinType) { // built-in type - paramTypes[i + 1] = builtinTypes[param->type].metaType; + paramTypes[i + 1] = metaTypeForPropertyType(static_cast<QV4::CompiledData::BuiltinType>(int(param->typeNameIndexOrBuiltinType))); } else { // lazily resolved type - Q_ASSERT(param->type == QV4::CompiledData::Property::Custom); - const QString customTypeName = stringAt(param->customTypeNameIndex); + const QString customTypeName = stringAt(param->typeNameIndexOrBuiltinType); QQmlType qmltype; if (!imports->resolveType(customTypeName, &qmltype, nullptr, nullptr, nullptr)) - return QQmlCompileError(s->location, QQmlPropertyCacheCreatorBase::tr("Invalid signal parameter type: %1").arg(customTypeName)); + return qQmlCompileError(s->location, QQmlPropertyCacheCreatorBase::tr("Invalid signal parameter type: %1").arg(customTypeName)); if (qmltype.isComposite()) { QQmlRefPointer<QQmlTypeData> tdata = enginePrivate->typeLoader.getType(qmltype.sourceUrl()); @@ -461,7 +435,7 @@ inline QQmlCompileError QQmlPropertyCacheCreator<ObjectContainer>::createMetaObj QString signalName = stringAt(s->nameIndex); if (seenSignals.contains(signalName)) - return QQmlCompileError(s->location, QQmlPropertyCacheCreatorBase::tr("Duplicate signal name: invalid override of property change signal or superclass signal")); + return qQmlCompileError(s->location, QQmlPropertyCacheCreatorBase::tr("Duplicate signal name: invalid override of property change signal or superclass signal")); seenSignals.insert(signalName); cache->appendSignal(signalName, flags, effectiveMethodIndex++, @@ -477,7 +451,7 @@ inline QQmlCompileError QQmlPropertyCacheCreator<ObjectContainer>::createMetaObj const QString slotName = stringAt(function->nameIndex); if (seenSignals.contains(slotName)) - return QQmlCompileError(function->location, QQmlPropertyCacheCreatorBase::tr("Duplicate method name: invalid override of property change signal or superclass signal")); + return qQmlCompileError(function->location, QQmlPropertyCacheCreatorBase::tr("Duplicate method name: invalid override of property change signal or superclass signal")); // Note: we don't append slotName to the seenSignals list, since we don't // protect against overriding change signals or methods with properties. @@ -503,21 +477,23 @@ inline QQmlCompileError QQmlPropertyCacheCreator<ObjectContainer>::createMetaObj int propertTypeMinorVersion = 0; QQmlPropertyData::Flags propertyFlags; - if (p->type == QV4::CompiledData::Property::Var) { - propertyType = QMetaType::QVariant; + const QV4::CompiledData::BuiltinType type = p->builtinType(); + + if (type == QV4::CompiledData::BuiltinType::Var) propertyFlags.type = QQmlPropertyData::Flags::VarPropertyType; - } else if (p->type < builtinTypeCount) { - propertyType = builtinTypes[p->type].metaType; - if (p->type == QV4::CompiledData::Property::Variant) + + if (type != QV4::CompiledData::BuiltinType::InvalidBuiltin) { + propertyType = metaTypeForPropertyType(type); + + if (type == QV4::CompiledData::BuiltinType::Variant) propertyFlags.type = QQmlPropertyData::Flags::QVariantType; } else { - Q_ASSERT(p->type == QV4::CompiledData::Property::CustomList || - p->type == QV4::CompiledData::Property::Custom); + Q_ASSERT(!p->isBuiltinType); QQmlType qmltype; - if (!imports->resolveType(stringAt(p->customTypeNameIndex), &qmltype, nullptr, nullptr, nullptr)) { - return QQmlCompileError(p->location, QQmlPropertyCacheCreatorBase::tr("Invalid property type")); + if (!imports->resolveType(stringAt(p->builtinTypeOrTypeNameIndex), &qmltype, nullptr, nullptr, nullptr)) { + return qQmlCompileError(p->location, QQmlPropertyCacheCreatorBase::tr("Invalid property type")); } Q_ASSERT(qmltype.isValid()); @@ -528,27 +504,27 @@ inline QQmlCompileError QQmlPropertyCacheCreator<ObjectContainer>::createMetaObj auto compilationUnit = tdata->compilationUnit(); - if (p->type == QV4::CompiledData::Property::Custom) { - propertyType = compilationUnit->metaTypeId; - } else { + if (p->isList) { propertyType = compilationUnit->listMetaTypeId; + } else { + propertyType = compilationUnit->metaTypeId; } } else { - if (p->type == QV4::CompiledData::Property::Custom) { + if (p->isList) { + propertyType = qmltype.qListTypeId(); + } else { propertyType = qmltype.typeId(); propertTypeMinorVersion = qmltype.minorVersion(); - } else { - propertyType = qmltype.qListTypeId(); } } - if (p->type == QV4::CompiledData::Property::Custom) - propertyFlags.type = QQmlPropertyData::Flags::QObjectDerivedType; - else + if (p->isList) propertyFlags.type = QQmlPropertyData::Flags::QListType; + else + propertyFlags.type = QQmlPropertyData::Flags::QObjectDerivedType; } - if (!(p->flags & QV4::CompiledData::Property::IsReadOnly) && p->type != QV4::CompiledData::Property::CustomList) + if (!p->isReadOnly && !p->isList) propertyFlags.isWritable = true; @@ -561,7 +537,7 @@ inline QQmlCompileError QQmlPropertyCacheCreator<ObjectContainer>::createMetaObj effectiveSignalIndex++; } - QQmlCompileError noError; + QQmlJS::DiagnosticMessage noError; return noError; } @@ -575,11 +551,11 @@ public: void appendAliasPropertiesToMetaObjects(); - QQmlCompileError appendAliasesToPropertyCache(const CompiledObject &component, int objectIndex); + QQmlJS::DiagnosticMessage appendAliasesToPropertyCache(const CompiledObject &component, int objectIndex); private: void appendAliasPropertiesInMetaObjectsWithinComponent(const CompiledObject &component, int firstObjectIndex); - QQmlCompileError propertyDataForAlias(const CompiledObject &component, const QV4::CompiledData::Alias &alias, int *type, int *rev, QQmlPropertyData::Flags *propertyFlags); + QQmlJS::DiagnosticMessage propertyDataForAlias(const CompiledObject &component, const QV4::CompiledData::Alias &alias, int *type, int *rev, QQmlPropertyData::Flags *propertyFlags); void collectObjectsWithAliasesRecursively(int objectIndex, QVector<int> *objectsWithAliases) const; @@ -690,7 +666,7 @@ inline void QQmlPropertyCacheAliasCreator<ObjectContainer>::collectObjectsWithAl } template <typename ObjectContainer> -inline QQmlCompileError QQmlPropertyCacheAliasCreator<ObjectContainer>::propertyDataForAlias( +inline QQmlJS::DiagnosticMessage QQmlPropertyCacheAliasCreator<ObjectContainer>::propertyDataForAlias( const CompiledObject &component, const QV4::CompiledData::Alias &alias, int *type, int *minorVersion, QQmlPropertyData::Flags *propertyFlags) { @@ -716,7 +692,7 @@ inline QQmlCompileError QQmlPropertyCacheAliasCreator<ObjectContainer>::property const QV4::CompiledData::Alias *targetAlias = &(*nextAlias); if (seenAliases.contains(targetAlias)) { - return QQmlCompileError(targetAlias->location, + return qQmlCompileError(targetAlias->location, QQmlPropertyCacheCreatorBase::tr("Cyclic alias")); } @@ -738,7 +714,8 @@ inline QQmlCompileError QQmlPropertyCacheAliasCreator<ObjectContainer>::property // Can be caused by the alias target not being a valid id or property. E.g.: // property alias dataValue: dataVal // invalidAliasComponent { id: dataVal } - return QQmlCompileError(targetObject.location, QQmlPropertyCacheCreatorBase::tr("Invalid alias target")); + return qQmlCompileError(targetObject.location, + QQmlPropertyCacheCreatorBase::tr("Invalid alias target")); } if (typeRef->type.isValid()) @@ -782,18 +759,18 @@ inline QQmlCompileError QQmlPropertyCacheAliasCreator<ObjectContainer>::property } } - propertyFlags->isWritable = !(alias.flags & QV4::CompiledData::Property::IsReadOnly) && writable; + propertyFlags->isWritable = !(alias.flags & QV4::CompiledData::Alias::IsReadOnly) && writable; propertyFlags->isResettable = resettable; - return QQmlCompileError(); + return QQmlJS::DiagnosticMessage(); } template <typename ObjectContainer> -inline QQmlCompileError QQmlPropertyCacheAliasCreator<ObjectContainer>::appendAliasesToPropertyCache( +inline QQmlJS::DiagnosticMessage QQmlPropertyCacheAliasCreator<ObjectContainer>::appendAliasesToPropertyCache( const CompiledObject &component, int objectIndex) { const CompiledObject &object = *objectContainer->objectAt(objectIndex); if (!object.aliasCount()) - return QQmlCompileError(); + return QQmlJS::DiagnosticMessage(); QQmlPropertyCache *propertyCache = propertyCaches->at(objectIndex); Q_ASSERT(propertyCache); @@ -810,8 +787,8 @@ inline QQmlCompileError QQmlPropertyCacheAliasCreator<ObjectContainer>::appendAl int type = 0; int minorVersion = 0; QQmlPropertyData::Flags propertyFlags; - QQmlCompileError error = propertyDataForAlias(component, *alias, &type, &minorVersion, &propertyFlags); - if (error.isSet()) + QQmlJS::DiagnosticMessage error = propertyDataForAlias(component, *alias, &type, &minorVersion, &propertyFlags); + if (error.isValid()) return error; const QString propertyName = objectContainer->stringAt(alias->nameIndex); @@ -823,7 +800,7 @@ inline QQmlCompileError QQmlPropertyCacheAliasCreator<ObjectContainer>::appendAl type, minorVersion, effectiveSignalIndex++); } - return QQmlCompileError(); + return QQmlJS::DiagnosticMessage(); } template <typename ObjectContainer> diff --git a/src/qml/qml/qqmlpropertyvalidator.cpp b/src/qml/qml/qqmlpropertyvalidator.cpp index 71d5318652..6bb00e438d 100644 --- a/src/qml/qml/qqmlpropertyvalidator.cpp +++ b/src/qml/qml/qqmlpropertyvalidator.cpp @@ -57,7 +57,7 @@ QQmlPropertyValidator::QQmlPropertyValidator(QQmlEnginePrivate *enginePrivate, c bindingPropertyDataPerObject->resize(compilationUnit->objectCount()); } -QVector<QQmlCompileError> QQmlPropertyValidator::validate() +QVector<QQmlJS::DiagnosticMessage> QQmlPropertyValidator::validate() { return validateObject(/*root object*/0, /*instantiatingBinding*/nullptr); } @@ -80,7 +80,8 @@ struct BindingFinder } }; -QVector<QQmlCompileError> QQmlPropertyValidator::validateObject(int objectIndex, const QV4::CompiledData::Binding *instantiatingBinding, bool populatingValueTypeGroupProperty) const +QVector<QQmlJS::DiagnosticMessage> QQmlPropertyValidator::validateObject( + int objectIndex, const QV4::CompiledData::Binding *instantiatingBinding, bool populatingValueTypeGroupProperty) const { const QV4::CompiledData::Object *obj = compilationUnit->objectAt(objectIndex); @@ -93,7 +94,7 @@ QVector<QQmlCompileError> QQmlPropertyValidator::validateObject(int objectIndex, QQmlPropertyCache *propertyCache = propertyCaches.at(objectIndex); if (!propertyCache) - return QVector<QQmlCompileError>(); + return QVector<QQmlJS::DiagnosticMessage>(); QQmlCustomParser *customParser = nullptr; if (auto typeRef = resolvedType(obj->inheritedTypeNameIndex)) { @@ -203,7 +204,7 @@ QVector<QQmlCompileError> QQmlPropertyValidator::validateObject(int objectIndex, = pd && QQmlValueTypeFactory::metaObjectForMetaType(pd->propType()) && !(binding->flags & QV4::CompiledData::Binding::IsOnAssignment); - const QVector<QQmlCompileError> subObjectValidatorErrors + const QVector<QQmlJS::DiagnosticMessage> subObjectValidatorErrors = validateObject(binding->value.objectIndex, binding, populatingValueTypeGroupProperty); if (!subObjectValidatorErrors.isEmpty()) @@ -260,12 +261,12 @@ QVector<QQmlCompileError> QQmlPropertyValidator::validateObject(int objectIndex, } if (binding->type < QV4::CompiledData::Binding::Type_Script) { - QQmlCompileError bindingError = validateLiteralBinding(propertyCache, pd, binding); - if (bindingError.isSet()) + QQmlJS::DiagnosticMessage bindingError = validateLiteralBinding(propertyCache, pd, binding); + if (bindingError.isValid()) return recordError(bindingError); } else if (binding->type == QV4::CompiledData::Binding::Type_Object) { - QQmlCompileError bindingError = validateObjectBinding(pd, name, binding); - if (bindingError.isSet()) + QQmlJS::DiagnosticMessage bindingError = validateObjectBinding(pd, name, binding); + if (bindingError.isValid()) return recordError(bindingError); } else if (binding->isGroupProperty()) { if (QQmlValueTypeFactory::isValueType(pd->propType())) { @@ -316,24 +317,24 @@ QVector<QQmlCompileError> QQmlPropertyValidator::validateObject(int objectIndex, customParser->validator = nullptr; customParser->engine = nullptr; customParser->imports = (QQmlImports*)nullptr; - QVector<QQmlCompileError> parserErrors = customParser->errors(); + QVector<QQmlJS::DiagnosticMessage> parserErrors = customParser->errors(); if (!parserErrors.isEmpty()) return parserErrors; } (*bindingPropertyDataPerObject)[objectIndex] = collectedBindingPropertyData; - QVector<QQmlCompileError> noError; + QVector<QQmlJS::DiagnosticMessage> noError; return noError; } -QQmlCompileError QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache *propertyCache, QQmlPropertyData *property, const QV4::CompiledData::Binding *binding) const +QQmlJS::DiagnosticMessage QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache *propertyCache, QQmlPropertyData *property, const QV4::CompiledData::Binding *binding) const { if (property->isQList()) { - return QQmlCompileError(binding->valueLocation, tr("Cannot assign primitives to lists")); + return qQmlCompileError(binding->valueLocation, tr("Cannot assign primitives to lists")); } - QQmlCompileError noError; + QQmlJS::DiagnosticMessage noError; if (property->isEnum()) { if (binding->flags & QV4::CompiledData::Binding::IsResolvedEnum) @@ -348,7 +349,7 @@ QQmlCompileError QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache p.enumerator().keyToValue(value.toUtf8().constData(), &ok); if (!ok) { - return QQmlCompileError(binding->valueLocation, tr("Invalid property assignment: unknown enumeration")); + return qQmlCompileError(binding->valueLocation, tr("Invalid property assignment: unknown enumeration")); } return noError; } @@ -365,7 +366,7 @@ QQmlCompileError QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache enginePrivate->warning(warning); return noError; } - return QQmlCompileError(binding->valueLocation, error); + return qQmlCompileError(binding->valueLocation, error); }; switch (property->propType()) { @@ -629,23 +630,23 @@ bool QQmlPropertyValidator::canCoerce(int to, QQmlPropertyCache *fromMo) const return false; } -QVector<QQmlCompileError> QQmlPropertyValidator::recordError(const QV4::CompiledData::Location &location, const QString &description) const +QVector<QQmlJS::DiagnosticMessage> QQmlPropertyValidator::recordError(const QV4::CompiledData::Location &location, const QString &description) const { - QVector<QQmlCompileError> errors; - errors.append(QQmlCompileError(location, description)); + QVector<QQmlJS::DiagnosticMessage> errors; + errors.append(qQmlCompileError(location, description)); return errors; } -QVector<QQmlCompileError> QQmlPropertyValidator::recordError(const QQmlCompileError &error) const +QVector<QQmlJS::DiagnosticMessage> QQmlPropertyValidator::recordError(const QQmlJS::DiagnosticMessage &error) const { - QVector<QQmlCompileError> errors; + QVector<QQmlJS::DiagnosticMessage> errors; errors.append(error); return errors; } -QQmlCompileError QQmlPropertyValidator::validateObjectBinding(QQmlPropertyData *property, const QString &propertyName, const QV4::CompiledData::Binding *binding) const +QQmlJS::DiagnosticMessage QQmlPropertyValidator::validateObjectBinding(QQmlPropertyData *property, const QString &propertyName, const QV4::CompiledData::Binding *binding) const { - QQmlCompileError noError; + QQmlJS::DiagnosticMessage noError; if (binding->flags & QV4::CompiledData::Binding::IsOnAssignment) { Q_ASSERT(binding->type == QV4::CompiledData::Binding::Type_Object); @@ -669,7 +670,7 @@ QQmlCompileError QQmlPropertyValidator::validateObjectBinding(QQmlPropertyData * } if (!isValueSource && !isPropertyInterceptor) { - return QQmlCompileError(binding->valueLocation, tr("\"%1\" cannot operate on \"%2\"").arg(stringAt(targetObject->inheritedTypeNameIndex)).arg(propertyName)); + return qQmlCompileError(binding->valueLocation, tr("\"%1\" cannot operate on \"%2\"").arg(stringAt(targetObject->inheritedTypeNameIndex)).arg(propertyName)); } return noError; @@ -687,7 +688,7 @@ QQmlCompileError QQmlPropertyValidator::validateObjectBinding(QQmlPropertyData * if (!QQmlMetaType::isInterface(listType)) { QQmlPropertyCache *source = propertyCaches.at(binding->value.objectIndex); if (!canCoerce(listType, source)) { - return QQmlCompileError(binding->valueLocation, tr("Cannot assign object to list property \"%1\"").arg(propertyName)); + return qQmlCompileError(binding->valueLocation, tr("Cannot assign object to list property \"%1\"").arg(propertyName)); } } return noError; @@ -695,11 +696,11 @@ QQmlCompileError QQmlPropertyValidator::validateObjectBinding(QQmlPropertyData * return noError; } else if (QQmlValueTypeFactory::isValueType(property->propType())) { auto typeName = QMetaType::typeName(property->propType()); - return QQmlCompileError(binding->location, tr("Can not assign value of type \"%1\" to property \"%2\", expecting an object") + return qQmlCompileError(binding->location, tr("Can not assign value of type \"%1\" to property \"%2\", expecting an object") .arg(typeName ? QString::fromLatin1(typeName) : QString::fromLatin1("<unknown type>")) .arg(propertyName)); } else if (property->propType() == qMetaTypeId<QQmlScriptString>()) { - return QQmlCompileError(binding->valueLocation, tr("Invalid property assignment: script expected")); + return qQmlCompileError(binding->valueLocation, tr("Invalid property assignment: script expected")); } else { // We want to use the raw metaObject here as the raw metaobject is the // actual property type before we applied any extensions that might @@ -719,7 +720,7 @@ QQmlCompileError QQmlPropertyValidator::validateObjectBinding(QQmlPropertyData * } if (!isAssignable) { - return QQmlCompileError(binding->valueLocation, tr("Cannot assign object of type \"%1\" to property of type \"%2\" as the former is neither the same as the latter nor a sub-class of it.") + return qQmlCompileError(binding->valueLocation, tr("Cannot assign object of type \"%1\" to property of type \"%2\" as the former is neither the same as the latter nor a sub-class of it.") .arg(stringAt(compilationUnit->objectAt(binding->value.objectIndex)->inheritedTypeNameIndex)).arg(QLatin1String(QMetaType::typeName(property->propType())))); } } diff --git a/src/qml/qml/qqmlpropertyvalidator_p.h b/src/qml/qml/qqmlpropertyvalidator_p.h index 8244b2df21..f2b892e978 100644 --- a/src/qml/qml/qqmlpropertyvalidator_p.h +++ b/src/qml/qml/qqmlpropertyvalidator_p.h @@ -60,17 +60,25 @@ class QQmlPropertyValidator public: QQmlPropertyValidator(QQmlEnginePrivate *enginePrivate, const QQmlImports &imports, const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit); - QVector<QQmlCompileError> validate(); + QVector<QQmlJS::DiagnosticMessage> validate(); private: - QVector<QQmlCompileError> validateObject(int objectIndex, const QV4::CompiledData::Binding *instantiatingBinding, bool populatingValueTypeGroupProperty = false) const; - QQmlCompileError validateLiteralBinding(QQmlPropertyCache *propertyCache, QQmlPropertyData *property, const QV4::CompiledData::Binding *binding) const; - QQmlCompileError validateObjectBinding(QQmlPropertyData *property, const QString &propertyName, const QV4::CompiledData::Binding *binding) const; + QVector<QQmlJS::DiagnosticMessage> validateObject( + int objectIndex, const QV4::CompiledData::Binding *instantiatingBinding, + bool populatingValueTypeGroupProperty = false) const; + QQmlJS::DiagnosticMessage validateLiteralBinding( + QQmlPropertyCache *propertyCache, QQmlPropertyData *property, + const QV4::CompiledData::Binding *binding) const; + QQmlJS::DiagnosticMessage validateObjectBinding( + QQmlPropertyData *property, const QString &propertyName, + const QV4::CompiledData::Binding *binding) const; bool canCoerce(int to, QQmlPropertyCache *fromMo) const; - Q_REQUIRED_RESULT QVector<QQmlCompileError> recordError(const QV4::CompiledData::Location &location, const QString &description) const; - Q_REQUIRED_RESULT QVector<QQmlCompileError> recordError(const QQmlCompileError &error) const; + Q_REQUIRED_RESULT QVector<QQmlJS::DiagnosticMessage> recordError( + const QV4::CompiledData::Location &location, const QString &description) const; + Q_REQUIRED_RESULT QVector<QQmlJS::DiagnosticMessage> recordError( + const QQmlJS::DiagnosticMessage &error) const; QString stringAt(int index) const { return compilationUnit->stringAt(index); } QV4::ResolvedTypeReference *resolvedType(int id) const { diff --git a/src/qml/qml/qqmlsourcecoordinate_p.h b/src/qml/qml/qqmlsourcecoordinate_p.h new file mode 100644 index 0000000000..55e11fd147 --- /dev/null +++ b/src/qml/qml/qqmlsourcecoordinate_p.h @@ -0,0 +1,95 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQMLSOURCECOORDINATE_P_H +#define QQMLSOURCECOORDINATE_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <QtCore/qglobal.h> + +#include <limits> + +QT_BEGIN_NAMESPACE + +// These methods are needed because in some public methods we historically interpret -1 as the +// invalid line or column, even though all the lines and columns are 1-based. Also, the different +// integer ranges may turn certain large values into invalid ones on conversion. + +template<typename From, typename To> +To qmlConvertSourceCoordinate(From n); + +template<> +inline quint16 qmlConvertSourceCoordinate<int, quint16>(int n) +{ + return (n > 0 && n <= int(std::numeric_limits<quint16>::max())) ? quint16(n) : 0; +} + +template<> +inline quint32 qmlConvertSourceCoordinate<int, quint32>(int n) +{ + return n > 0 ? quint32(n) : 0u; +} + +// TODO: In Qt6, change behavior and make the invalid coordinate 0 for the following two methods. + +template<> +inline int qmlConvertSourceCoordinate<quint16, int>(quint16 n) +{ + return (n == 0u) ? -1 : int(n); +} + +template<> +inline int qmlConvertSourceCoordinate<quint32, int>(quint32 n) +{ + return (n == 0u || n > quint32(std::numeric_limits<int>::max())) ? -1 : int(n); +} + +QT_END_NAMESPACE + +#endif // QQMLSOURCECOORDINATE_P_H diff --git a/src/qml/qml/qqmltype_p.h b/src/qml/qml/qqmltype_p.h index 1d65a08c8f..158fefad2c 100644 --- a/src/qml/qml/qqmltype_p.h +++ b/src/qml/qml/qqmltype_p.h @@ -51,6 +51,8 @@ // We mean it. // +#include <functional> + #include <private/qtqmlglobal_p.h> #include <private/qqmlrefcount_p.h> @@ -145,7 +147,7 @@ public: struct Q_QML_PRIVATE_EXPORT SingletonInstanceInfo { QJSValue (*scriptCallback)(QQmlEngine *, QJSEngine *) = nullptr; - QObject *(*qobjectCallback)(QQmlEngine *, QJSEngine *) = nullptr; + std::function<QObject *(QQmlEngine *, QJSEngine *)> qobjectCallback = {}; const QMetaObject *instanceMetaObject = nullptr; QString typeName; QUrl url; // used by composite singletons diff --git a/src/qml/qml/qqmltypecompiler.cpp b/src/qml/qml/qqmltypecompiler.cpp index 66320b8db9..6cbe81b4b8 100644 --- a/src/qml/qml/qqmltypecompiler.cpp +++ b/src/qml/qml/qqmltypecompiler.cpp @@ -83,8 +83,8 @@ QQmlRefPointer<QV4::ExecutableCompilationUnit> QQmlTypeCompiler::compile() { QQmlPropertyCacheCreator<QQmlTypeCompiler> propertyCacheBuilder(&m_propertyCaches, &pendingGroupPropertyBindings, engine, this, imports()); - QQmlCompileError error = propertyCacheBuilder.buildMetaObjects(); - if (error.isSet()) { + QQmlJS::DiagnosticMessage error = propertyCacheBuilder.buildMetaObjects(); + if (error.isValid()) { recordError(error); return nullptr; } @@ -173,12 +173,6 @@ QQmlRefPointer<QV4::ExecutableCompilationUnit> QQmlTypeCompiler::compile() return nullptr; } -void QQmlTypeCompiler::recordError(QQmlError error) -{ - error.setUrl(url()); - errors << error; -} - void QQmlTypeCompiler::recordError(const QV4::CompiledData::Location &location, const QString &description) { QQmlError error; @@ -189,9 +183,14 @@ void QQmlTypeCompiler::recordError(const QV4::CompiledData::Location &location, errors << error; } -void QQmlTypeCompiler::recordError(const QQmlCompileError &error) +void QQmlTypeCompiler::recordError(const QQmlJS::DiagnosticMessage &message) { - recordError(error.location, error.description); + QQmlError error; + error.setDescription(message.message); + error.setLine(message.line); + error.setColumn(message.column); + error.setUrl(url()); + errors << error; } QString QQmlTypeCompiler::stringAt(int idx) const @@ -1020,17 +1019,17 @@ bool QQmlComponentAndAliasResolver::resolveAliases(int componentIndex) for (int objectIndex: qAsConst(_objectsWithAliases)) { - QQmlCompileError error; + QQmlJS::DiagnosticMessage error; const auto result = resolveAliasesInObject(objectIndex, &error); - if (error.isSet()) { + if (error.isValid()) { recordError(error); return false; } if (result == AllAliasesResolved) { - QQmlCompileError error = aliasCacheCreator.appendAliasesToPropertyCache(*qmlObjects->at(componentIndex), objectIndex); - if (error.isSet()) { + QQmlJS::DiagnosticMessage error = aliasCacheCreator.appendAliasesToPropertyCache(*qmlObjects->at(componentIndex), objectIndex); + if (error.isValid()) { recordError(error); return false; } @@ -1058,7 +1057,9 @@ bool QQmlComponentAndAliasResolver::resolveAliases(int componentIndex) return true; } -QQmlComponentAndAliasResolver::AliasResolutionResult QQmlComponentAndAliasResolver::resolveAliasesInObject(int objectIndex, QQmlCompileError *error) +QQmlComponentAndAliasResolver::AliasResolutionResult +QQmlComponentAndAliasResolver::resolveAliasesInObject(int objectIndex, + QQmlJS::DiagnosticMessage *error) { const QmlIR::Object * const obj = qmlObjects->at(objectIndex); if (!obj->aliasCount()) @@ -1076,7 +1077,9 @@ QQmlComponentAndAliasResolver::AliasResolutionResult QQmlComponentAndAliasResolv const int idIndex = alias->idIndex; const int targetObjectIndex = _idToObjectIndex.value(idIndex, -1); if (targetObjectIndex == -1) { - *error = QQmlCompileError(alias->referenceLocation, tr("Invalid alias reference. Unable to find id \"%1\"").arg(stringAt(idIndex))); + *error = qQmlCompileError( + alias->referenceLocation, + tr("Invalid alias reference. Unable to find id \"%1\"").arg(stringAt(idIndex))); break; } @@ -1104,7 +1107,9 @@ QQmlComponentAndAliasResolver::AliasResolutionResult QQmlComponentAndAliasResolv } else { QQmlPropertyCache *targetCache = propertyCaches.at(targetObjectIndex); if (!targetCache) { - *error = QQmlCompileError(alias->referenceLocation, tr("Invalid alias target location: %1").arg(property.toString())); + *error = qQmlCompileError( + alias->referenceLocation, + tr("Invalid alias target location: %1").arg(property.toString())); break; } @@ -1139,7 +1144,9 @@ QQmlComponentAndAliasResolver::AliasResolutionResult QQmlComponentAndAliasResolv } if (!targetProperty || targetProperty->coreIndex() > 0x0000FFFF) { - *error = QQmlCompileError(alias->referenceLocation, tr("Invalid alias target location: %1").arg(property.toString())); + *error = qQmlCompileError( + alias->referenceLocation, + tr("Invalid alias target location: %1").arg(property.toString())); break; } @@ -1148,14 +1155,18 @@ QQmlComponentAndAliasResolver::AliasResolutionResult QQmlComponentAndAliasResolv if (!subProperty.isEmpty()) { const QMetaObject *valueTypeMetaObject = QQmlValueTypeFactory::metaObjectForMetaType(targetProperty->propType()); if (!valueTypeMetaObject) { - *error = QQmlCompileError(alias->referenceLocation, tr("Invalid alias target location: %1").arg(subProperty.toString())); + *error = qQmlCompileError( + alias->referenceLocation, + tr("Invalid alias target location: %1").arg(subProperty.toString())); break; } int valueTypeIndex = valueTypeMetaObject->indexOfProperty(subProperty.toString().toUtf8().constData()); if (valueTypeIndex == -1) { - *error = QQmlCompileError(alias->referenceLocation, tr("Invalid alias target location: %1").arg(subProperty.toString())); + *error = qQmlCompileError( + alias->referenceLocation, + tr("Invalid alias target location: %1").arg(subProperty.toString())); break; } Q_ASSERT(valueTypeIndex <= 0x0000FFFF); @@ -1345,10 +1356,8 @@ bool QQmlJSCodeGenerator::compileJavaScriptCodeInObjectsRecursively(int objectIn for (QmlIR::CompiledFunctionOrExpression *foe = object->functionsAndExpressions->first; foe; foe = foe->next) functionsToCompile << *foe; const QVector<int> runtimeFunctionIndices = v4CodeGen->generateJSCodeForFunctionsAndBindings(functionsToCompile); - const QList<QQmlError> jsErrors = v4CodeGen->qmlErrors(); - if (!jsErrors.isEmpty()) { - for (const QQmlError &e : jsErrors) - compiler->recordError(e); + if (v4CodeGen->hasError()) { + compiler->recordError(v4CodeGen->error()); return false; } diff --git a/src/qml/qml/qqmltypecompiler_p.h b/src/qml/qml/qqmltypecompiler_p.h index f588909c42..615694d4bc 100644 --- a/src/qml/qml/qqmltypecompiler_p.h +++ b/src/qml/qml/qqmltypecompiler_p.h @@ -97,9 +97,8 @@ public: QQmlRefPointer<QV4::ExecutableCompilationUnit> compile(); QList<QQmlError> compilationErrors() const { return errors; } - void recordError(QQmlError error); void recordError(const QV4::CompiledData::Location &location, const QString &description); - void recordError(const QQmlCompileError &error); + void recordError(const QQmlJS::DiagnosticMessage &error); int registerString(const QString &str); int registerConstant(QV4::ReturnedValue v); @@ -153,7 +152,7 @@ struct QQmlCompilePass protected: void recordError(const QV4::CompiledData::Location &location, const QString &description) const { compiler->recordError(location, description); } - void recordError(const QQmlCompileError &error) + void recordError(const QQmlJS::DiagnosticMessage &error) { compiler->recordError(error); } QV4::ResolvedTypeReference *resolvedType(int id) const @@ -276,7 +275,7 @@ protected: AllAliasesResolved }; - AliasResolutionResult resolveAliasesInObject(int objectIndex, QQmlCompileError *error); + AliasResolutionResult resolveAliasesInObject(int objectIndex, QQmlJS::DiagnosticMessage *error); QQmlEnginePrivate *enginePrivate; QQmlJS::MemoryPool *pool; diff --git a/src/qml/qml/qqmltypeloader.cpp b/src/qml/qml/qqmltypeloader.cpp index 1022412292..0bfdbdd2fa 100644 --- a/src/qml/qml/qqmltypeloader.cpp +++ b/src/qml/qml/qqmltypeloader.cpp @@ -47,7 +47,6 @@ #include <private/qv4codegen_p.h> #include <private/qqmlcomponent_p.h> #include <private/qqmlprofiler_p.h> -#include <private/qqmlmemoryprofiler_p.h> #include <private/qqmltypecompiler_p.h> #include <private/qqmlpropertyvalidator_p.h> #include <private/qqmlpropertycachecreator_p.h> @@ -459,25 +458,25 @@ void QQmlDataBlob::setError(const QList<QQmlError> &errors) tryDone(); } -void QQmlDataBlob::setError(const QQmlCompileError &error) +void QQmlDataBlob::setError(const QQmlJS::DiagnosticMessage &error) { QQmlError e; - e.setColumn(error.location.column); - e.setLine(error.location.line); - e.setDescription(error.description); + e.setColumn(error.column); + e.setLine(error.line); + e.setDescription(error.message); e.setUrl(url()); setError(e); } -void QQmlDataBlob::setError(const QVector<QQmlCompileError> &errors) +void QQmlDataBlob::setError(const QVector<QQmlJS::DiagnosticMessage> &errors) { QList<QQmlError> finalErrors; finalErrors.reserve(errors.count()); - for (const QQmlCompileError &error: errors) { + for (const auto &error : errors) { QQmlError e; - e.setColumn(error.location.column); - e.setLine(error.location.line); - e.setDescription(error.description); + e.setColumn(error.column); + e.setLine(error.line); + e.setDescription(error.message); e.setUrl(url()); finalErrors << e; } @@ -757,13 +756,13 @@ QQmlDataBlob::ThreadData::ThreadData() QQmlDataBlob::Status QQmlDataBlob::ThreadData::status() const { - return QQmlDataBlob::Status((_p.load() & TD_STATUS_MASK) >> TD_STATUS_SHIFT); + return QQmlDataBlob::Status((_p.loadRelaxed() & TD_STATUS_MASK) >> TD_STATUS_SHIFT); } void QQmlDataBlob::ThreadData::setStatus(QQmlDataBlob::Status status) { while (true) { - int d = _p.load(); + int d = _p.loadRelaxed(); int nd = (d & ~TD_STATUS_MASK) | ((status << TD_STATUS_SHIFT) & TD_STATUS_MASK); if (d == nd || _p.testAndSetOrdered(d, nd)) return; } @@ -771,13 +770,13 @@ void QQmlDataBlob::ThreadData::setStatus(QQmlDataBlob::Status status) bool QQmlDataBlob::ThreadData::isAsync() const { - return _p.load() & TD_ASYNC_MASK; + return _p.loadRelaxed() & TD_ASYNC_MASK; } void QQmlDataBlob::ThreadData::setIsAsync(bool v) { while (true) { - int d = _p.load(); + int d = _p.loadRelaxed(); int nd = (d & ~TD_ASYNC_MASK) | (v?TD_ASYNC_MASK:0); if (d == nd || _p.testAndSetOrdered(d, nd)) return; } @@ -785,13 +784,13 @@ void QQmlDataBlob::ThreadData::setIsAsync(bool v) quint8 QQmlDataBlob::ThreadData::progress() const { - return quint8((_p.load() & TD_PROGRESS_MASK) >> TD_PROGRESS_SHIFT); + return quint8((_p.loadRelaxed() & TD_PROGRESS_MASK) >> TD_PROGRESS_SHIFT); } void QQmlDataBlob::ThreadData::setProgress(quint8 v) { while (true) { - int d = _p.load(); + int d = _p.loadRelaxed(); int nd = (d & ~TD_PROGRESS_MASK) | ((v << TD_PROGRESS_SHIFT) & TD_PROGRESS_MASK); if (d == nd || _p.testAndSetOrdered(d, nd)) return; } @@ -921,7 +920,6 @@ void QQmlTypeLoaderThread::loadWithCachedUnitThread(QQmlDataBlob *b, const QV4:: void QQmlTypeLoaderThread::callCompletedMain(QQmlDataBlob *b) { - QML_MEMORY_SCOPE_URL(b->url()); #ifdef DATABLOB_DEBUG qWarning("QQmlTypeLoaderThread: %s completed() callback", qPrintable(b->urlString())); #endif @@ -1147,8 +1145,6 @@ void QQmlTypeLoader::loadThread(QQmlDataBlob *blob) return; } - QML_MEMORY_SCOPE_URL(blob->m_url); - if (QQmlFile::isSynchronous(blob->m_url)) { const QString fileName = QQmlFile::urlToLocalFileOrQrc(blob->m_url); if (!QQml_isFileCaseCorrect(fileName)) { @@ -1278,7 +1274,6 @@ void QQmlTypeLoader::initializeEngine(QQmlExtensionInterface *iface, void QQmlTypeLoader::setData(QQmlDataBlob *blob, const QByteArray &data) { - QML_MEMORY_SCOPE_URL(blob->url()); QQmlDataBlob::SourceCodeData d; d.inlineSourceCode = QString::fromUtf8(data); d.hasInlineSourceCode = true; @@ -1287,7 +1282,6 @@ void QQmlTypeLoader::setData(QQmlDataBlob *blob, const QByteArray &data) void QQmlTypeLoader::setData(QQmlDataBlob *blob, const QString &fileName) { - QML_MEMORY_SCOPE_URL(blob->url()); QQmlDataBlob::SourceCodeData d; d.fileInfo = QFileInfo(fileName); setData(blob, d); @@ -1295,7 +1289,6 @@ void QQmlTypeLoader::setData(QQmlDataBlob *blob, const QString &fileName) void QQmlTypeLoader::setData(QQmlDataBlob *blob, const QQmlDataBlob::SourceCodeData &d) { - QML_MEMORY_SCOPE_URL(blob->url()); QQmlCompilingProfiler prof(profiler(), blob); blob->m_inCallback = true; @@ -1315,7 +1308,6 @@ void QQmlTypeLoader::setData(QQmlDataBlob *blob, const QQmlDataBlob::SourceCodeD void QQmlTypeLoader::setCachedUnit(QQmlDataBlob *blob, const QV4::CompiledData::Unit *unit) { - QML_MEMORY_SCOPE_URL(blob->url()); QQmlCompilingProfiler prof(profiler(), blob); blob->m_inCallback = true; @@ -1584,7 +1576,17 @@ bool QQmlTypeLoaderQmldirContent::hasError() const QList<QQmlError> QQmlTypeLoaderQmldirContent::errors(const QString &uri) const { - return m_parser.errors(uri); + QList<QQmlError> errors; + const QUrl url(uri); + for (const auto parseError : m_parser.errors(uri)) { + QQmlError error; + error.setUrl(url); + error.setLine(parseError.line); + error.setColumn(parseError.column); + error.setDescription(parseError.message); + errors.append(error); + } + return errors; } QString QQmlTypeLoaderQmldirContent::typeNamespace() const @@ -1601,7 +1603,11 @@ void QQmlTypeLoaderQmldirContent::setContent(const QString &location, const QStr void QQmlTypeLoaderQmldirContent::setError(const QQmlError &error) { - m_parser.setError(error); + QQmlJS::DiagnosticMessage parseError; + parseError.line = error.line(); + parseError.column = error.column(); + parseError.message = error.description(); + m_parser.setError(parseError); } QQmlDirComponents QQmlTypeLoaderQmldirContent::components() const @@ -2248,8 +2254,8 @@ void QQmlTypeData::createTypeAndPropertyCaches( QQmlPropertyCacheCreator<QV4::ExecutableCompilationUnit> propertyCacheCreator( &m_compiledData->propertyCaches, &pendingGroupPropertyBindings, engine, m_compiledData.data(), &m_importCache); - QQmlCompileError error = propertyCacheCreator.buildMetaObjects(); - if (error.isSet()) { + QQmlJS::DiagnosticMessage error = propertyCacheCreator.buildMetaObjects(); + if (error.isValid()) { setError(error); return; } @@ -2350,8 +2356,8 @@ void QQmlTypeData::done() QQmlRefPointer<QQmlTypeNameCache> typeNameCache; QV4::ResolvedTypeReferenceMap resolvedTypeCache; { - QQmlCompileError error = buildTypeResolutionCaches(&typeNameCache, &resolvedTypeCache); - if (error.isSet()) { + QQmlJS::DiagnosticMessage error = buildTypeResolutionCaches(&typeNameCache, &resolvedTypeCache); + if (error.isValid()) { setError(error); return; } @@ -2391,7 +2397,7 @@ void QQmlTypeData::done() { // Sanity check property bindings QQmlPropertyValidator validator(enginePrivate, m_importCache, m_compiledData); - QVector<QQmlCompileError> errors = validator.validate(); + QVector<QQmlJS::DiagnosticMessage> errors = validator.validate(); if (!errors.isEmpty()) { setError(errors); return; @@ -2535,8 +2541,8 @@ bool QQmlTypeData::loadFromSource() for (const QQmlJS::DiagnosticMessage &msg : qAsConst(compiler.errors)) { QQmlError e; e.setUrl(url()); - e.setLine(msg.loc.startLine); - e.setColumn(msg.loc.startColumn); + e.setLine(msg.line); + e.setColumn(msg.column); e.setDescription(msg.message); errors << e; } @@ -2775,7 +2781,7 @@ void QQmlTypeData::resolveTypes() loadImplicitImport(); } -QQmlCompileError QQmlTypeData::buildTypeResolutionCaches( +QQmlJS::DiagnosticMessage QQmlTypeData::buildTypeResolutionCaches( QQmlRefPointer<QQmlTypeNameCache> *typeNameCache, QV4::ResolvedTypeReferenceMap *resolvedTypeCache ) const @@ -2798,7 +2804,7 @@ QQmlCompileError QQmlTypeData::buildTypeResolutionCaches( QQmlType qmlType = resolvedType->type; if (resolvedType->typeData) { if (resolvedType->needsCreation && qmlType.isCompositeSingleton()) { - return QQmlCompileError(resolvedType->location, tr("Composite Singleton Type %1 is not creatable.").arg(qmlType.qmlTypeName())); + return qQmlCompileError(resolvedType->location, tr("Composite Singleton Type %1 is not creatable.").arg(qmlType.qmlTypeName())); } ref->compilationUnit = resolvedType->typeData->compilationUnit(); } else if (qmlType.isValid()) { @@ -2809,7 +2815,7 @@ QQmlCompileError QQmlTypeData::buildTypeResolutionCaches( QString reason = ref->type.noCreationReason(); if (reason.isEmpty()) reason = tr("Element is not creatable."); - return QQmlCompileError(resolvedType->location, reason); + return qQmlCompileError(resolvedType->location, reason); } if (ref->type.containsRevisionedAttributes()) { @@ -2822,7 +2828,7 @@ QQmlCompileError QQmlTypeData::buildTypeResolutionCaches( ref->doDynamicTypeCheck(); resolvedTypeCache->insert(resolvedType.key(), ref.take()); } - QQmlCompileError noError; + QQmlJS::DiagnosticMessage noError; return noError; } diff --git a/src/qml/qml/qqmltypeloader_p.h b/src/qml/qml/qqmltypeloader_p.h index d87812d48e..3330d52e56 100644 --- a/src/qml/qml/qqmltypeloader_p.h +++ b/src/qml/qml/qqmltypeloader_p.h @@ -86,7 +86,6 @@ class QQmlTypeData; class QQmlTypeLoader; class QQmlExtensionInterface; class QQmlProfiler; -struct QQmlCompileError; namespace QmlIR { struct Document; @@ -154,8 +153,8 @@ protected: // Can be called from within callbacks void setError(const QQmlError &); void setError(const QList<QQmlError> &errors); - void setError(const QQmlCompileError &error); - void setError(const QVector<QQmlCompileError> &errors); + void setError(const QQmlJS::DiagnosticMessage &error); + void setError(const QVector<QQmlJS::DiagnosticMessage> &errors); void setError(const QString &description); void addDependency(QQmlDataBlob *); @@ -481,7 +480,7 @@ private: void restoreIR(QV4::CompiledData::CompilationUnit &&unit); void continueLoadFromIR(); void resolveTypes(); - QQmlCompileError buildTypeResolutionCaches( + QQmlJS::DiagnosticMessage buildTypeResolutionCaches( QQmlRefPointer<QQmlTypeNameCache> *typeNameCache, QV4::ResolvedTypeReferenceMap *resolvedTypeCache ) const; diff --git a/src/qml/qml/qqmltypemodule.cpp b/src/qml/qml/qqmltypemodule.cpp index 4d7553fbab..9c9bf3e48f 100644 --- a/src/qml/qml/qqmltypemodule.cpp +++ b/src/qml/qml/qqmltypemodule.cpp @@ -69,24 +69,24 @@ int QQmlTypeModule::majorVersion() const int QQmlTypeModule::minimumMinorVersion() const { - return d->minMinorVersion.load(); + return d->minMinorVersion.loadRelaxed(); } int QQmlTypeModule::maximumMinorVersion() const { - return d->maxMinorVersion.load(); + return d->maxMinorVersion.loadRelaxed(); } void QQmlTypeModule::addMinorVersion(int version) { - for (int oldVersion = d->minMinorVersion.load(); + for (int oldVersion = d->minMinorVersion.loadRelaxed(); oldVersion > version && !d->minMinorVersion.testAndSetOrdered(oldVersion, version); - oldVersion = d->minMinorVersion.load()) { + oldVersion = d->minMinorVersion.loadRelaxed()) { } - for (int oldVersion = d->maxMinorVersion.load(); + for (int oldVersion = d->maxMinorVersion.loadRelaxed(); oldVersion < version && !d->maxMinorVersion.testAndSetOrdered(oldVersion, version); - oldVersion = d->maxMinorVersion.load()) { + oldVersion = d->maxMinorVersion.loadRelaxed()) { } } @@ -125,12 +125,12 @@ void QQmlTypeModule::remove(const QQmlTypePrivate *type) bool QQmlTypeModule::isLocked() const { - return d->locked.load() != 0; + return d->locked.loadRelaxed() != 0; } void QQmlTypeModule::lock() { - d->locked.store(1); + d->locked.storeRelaxed(1); } QQmlType QQmlTypeModule::type(const QHashedStringRef &name, int minor) const diff --git a/src/qml/qml/qqmltypewrapper.cpp b/src/qml/qml/qqmltypewrapper.cpp index 9db089c330..57c4eec879 100644 --- a/src/qml/qml/qqmltypewrapper.cpp +++ b/src/qml/qml/qqmltypewrapper.cpp @@ -454,16 +454,16 @@ ReturnedValue QQmlTypeWrapper::virtualResolveLookupGetter(const Object *object, if (!includeEnums || !name->startsWithUpper()) { QQmlData *ddata = QQmlData::get(qobjectSingleton, false); if (ddata && ddata->propertyCache) { - ScopedValue val(scope, Value::fromReturnedValue(QV4::QObjectWrapper::wrap(engine, qobjectSingleton))); QQmlPropertyData *property = ddata->propertyCache->property(name.getPointer(), qobjectSingleton, qmlContext); if (property) { - lookup->qobjectLookup.ic = This->internalClass(); - lookup->qobjectLookup.staticQObject = static_cast<Heap::QObjectWrapper *>(val->heapObject()); + ScopedValue val(scope, Value::fromReturnedValue(QV4::QObjectWrapper::wrap(engine, qobjectSingleton))); + lookup->qobjectLookup.qmlTypeIc = This->internalClass(); + lookup->qobjectLookup.ic = val->objectValue()->internalClass(); lookup->qobjectLookup.propertyCache = ddata->propertyCache; lookup->qobjectLookup.propertyCache->addref(); lookup->qobjectLookup.propertyData = property; - lookup->getter = QV4::QObjectWrapper::lookupGetter; - return lookup->getter(lookup, engine, *This); + lookup->getter = QQmlTypeWrapper::lookupSingletonProperty; + return lookup->getter(lookup, engine, *object); } // Fall through to base implementation } @@ -485,6 +485,39 @@ bool QQmlTypeWrapper::virtualResolveLookupSetter(Object *object, ExecutionEngine return Object::virtualResolveLookupSetter(object, engine, lookup, value); } +ReturnedValue QQmlTypeWrapper::lookupSingletonProperty(Lookup *l, ExecutionEngine *engine, const Value &object) +{ + const auto revertLookup = [l, engine, &object]() { + l->qobjectLookup.propertyCache->release(); + l->qobjectLookup.propertyCache = nullptr; + l->getter = Lookup::getterGeneric; + return Lookup::getterGeneric(l, engine, object); + }; + + // we can safely cast to a QV4::Object here. If object is something else, + // the internal class won't match + Heap::Object *o = static_cast<Heap::Object *>(object.heapObject()); + if (!o || o->internalClass != l->qobjectLookup.qmlTypeIc) + return revertLookup(); + + Heap::QQmlTypeWrapper *This = static_cast<Heap::QQmlTypeWrapper *>(o); + + QQmlType type = This->type(); + if (!type.isValid()) + return revertLookup(); + + if (!type.isQObjectSingleton() && !type.isCompositeSingleton()) + return revertLookup(); + + QQmlEnginePrivate *e = QQmlEnginePrivate::get(engine->qmlEngine()); + QObject *qobjectSingleton = e->singletonInstance<QObject *>(type); + Q_ASSERT(qobjectSingleton); + + Scope scope(engine); + ScopedValue obj(scope, QV4::QObjectWrapper::wrap(engine, qobjectSingleton)); + return QObjectWrapper::lookupGetterImpl(l, engine, obj, /*useOriginalProperty*/ true, revertLookup); +} + void Heap::QQmlScopedEnumWrapper::destroy() { QQmlType::derefHandle(typePrivate); diff --git a/src/qml/qml/qqmltypewrapper_p.h b/src/qml/qml/qqmltypewrapper_p.h index c797a4ac10..6b51f421b3 100644 --- a/src/qml/qml/qqmltypewrapper_p.h +++ b/src/qml/qml/qqmltypewrapper_p.h @@ -114,6 +114,8 @@ struct Q_QML_EXPORT QQmlTypeWrapper : Object static ReturnedValue virtualResolveLookupGetter(const Object *object, ExecutionEngine *engine, Lookup *lookup); static bool virtualResolveLookupSetter(Object *object, ExecutionEngine *engine, Lookup *lookup, const Value &value); + static ReturnedValue lookupSingletonProperty(Lookup *l, ExecutionEngine *engine, const Value &base); + protected: static ReturnedValue virtualGet(const Managed *m, PropertyKey id, const Value *receiver, bool *hasProperty); static bool virtualPut(Managed *m, PropertyKey id, const Value &value, Value *receiver); diff --git a/src/qml/qml/qqmlvmemetaobject.cpp b/src/qml/qml/qqmlvmemetaobject.cpp index 2881e71805..458f26b465 100644 --- a/src/qml/qml/qqmlvmemetaobject.cpp +++ b/src/qml/qml/qqmlvmemetaobject.cpp @@ -57,6 +57,7 @@ #include <private/qv4scopedvalue_p.h> #include <private/qv4jscall_p.h> #include <private/qv4qobjectwrapper_p.h> +#include <private/qqmlpropertycachecreator_p.h> QT_BEGIN_NAMESPACE @@ -638,205 +639,170 @@ int QQmlVMEMetaObject::metaCall(QObject *o, QMetaObject::Call c, int _id, void * id -= propOffset(); if (id < propertyCount) { - const QV4::CompiledData::Property::Type t = static_cast<QV4::CompiledData::Property::Type>(qint32(compiledObject->propertyTable()[id].type)); - bool needActivate = false; - - if (t == QV4::CompiledData::Property::Var) { - // the context can be null if accessing var properties from cpp after re-parenting an item. - QQmlEnginePrivate *ep = (ctxt == nullptr || ctxt->engine == nullptr) ? nullptr : QQmlEnginePrivate::get(ctxt->engine); - if (ep) { - if (c == QMetaObject::ReadProperty) { - *reinterpret_cast<QVariant *>(a[0]) = readPropertyAsVariant(id); - } else if (c == QMetaObject::WriteProperty) { - writeProperty(id, *reinterpret_cast<QVariant *>(a[0])); - } - } else if (c == QMetaObject::ReadProperty) { - // if the context was disposed, we just return an invalid variant from read. - *reinterpret_cast<QVariant *>(a[0]) = QVariant(); - } + const QV4::CompiledData::Property &property = compiledObject->propertyTable()[id]; + const QV4::CompiledData::BuiltinType t = property.builtinType(); - } else { - int fallbackMetaType = QMetaType::UnknownType; + // the context can be null if accessing var properties from cpp after re-parenting an item. + QQmlEnginePrivate *ep = (ctxt == nullptr || ctxt->engine == nullptr) ? nullptr : QQmlEnginePrivate::get(ctxt->engine); + + const int fallbackMetaType = QQmlPropertyCacheCreatorBase::metaTypeForPropertyType(t); + + if (c == QMetaObject::ReadProperty) { switch (t) { - case QV4::CompiledData::Property::Font: - fallbackMetaType = QMetaType::QFont; + case QV4::CompiledData::BuiltinType::Int: + *reinterpret_cast<int *>(a[0]) = readPropertyAsInt(id); break; - case QV4::CompiledData::Property::Time: - fallbackMetaType = QMetaType::QTime; + case QV4::CompiledData::BuiltinType::Bool: + *reinterpret_cast<bool *>(a[0]) = readPropertyAsBool(id); break; - case QV4::CompiledData::Property::Color: - fallbackMetaType = QMetaType::QColor; + case QV4::CompiledData::BuiltinType::Real: + *reinterpret_cast<double *>(a[0]) = readPropertyAsDouble(id); break; - case QV4::CompiledData::Property::Vector2D: - fallbackMetaType = QMetaType::QVector2D; + case QV4::CompiledData::BuiltinType::String: + *reinterpret_cast<QString *>(a[0]) = readPropertyAsString(id); break; - case QV4::CompiledData::Property::Vector3D: - fallbackMetaType = QMetaType::QVector3D; + case QV4::CompiledData::BuiltinType::Url: + *reinterpret_cast<QUrl *>(a[0]) = readPropertyAsUrl(id); break; - case QV4::CompiledData::Property::Vector4D: - fallbackMetaType = QMetaType::QVector4D; + case QV4::CompiledData::BuiltinType::Date: + *reinterpret_cast<QDate *>(a[0]) = readPropertyAsDate(id); break; - case QV4::CompiledData::Property::Matrix4x4: - fallbackMetaType = QMetaType::QMatrix4x4; + case QV4::CompiledData::BuiltinType::DateTime: + *reinterpret_cast<QDateTime *>(a[0]) = readPropertyAsDateTime(id); break; - case QV4::CompiledData::Property::Quaternion: - fallbackMetaType = QMetaType::QQuaternion; + case QV4::CompiledData::BuiltinType::Rect: + *reinterpret_cast<QRectF *>(a[0]) = readPropertyAsRectF(id); break; - default: break; - } - - - if (c == QMetaObject::ReadProperty) { - switch (t) { - case QV4::CompiledData::Property::Int: - *reinterpret_cast<int *>(a[0]) = readPropertyAsInt(id); - break; - case QV4::CompiledData::Property::Bool: - *reinterpret_cast<bool *>(a[0]) = readPropertyAsBool(id); - break; - case QV4::CompiledData::Property::Real: - *reinterpret_cast<double *>(a[0]) = readPropertyAsDouble(id); - break; - case QV4::CompiledData::Property::String: - *reinterpret_cast<QString *>(a[0]) = readPropertyAsString(id); - break; - case QV4::CompiledData::Property::Url: - *reinterpret_cast<QUrl *>(a[0]) = readPropertyAsUrl(id); - break; - case QV4::CompiledData::Property::Date: - *reinterpret_cast<QDate *>(a[0]) = readPropertyAsDate(id); - break; - case QV4::CompiledData::Property::DateTime: - *reinterpret_cast<QDateTime *>(a[0]) = readPropertyAsDateTime(id); - break; - case QV4::CompiledData::Property::Rect: - *reinterpret_cast<QRectF *>(a[0]) = readPropertyAsRectF(id); - break; - case QV4::CompiledData::Property::Size: - *reinterpret_cast<QSizeF *>(a[0]) = readPropertyAsSizeF(id); - break; - case QV4::CompiledData::Property::Point: - *reinterpret_cast<QPointF *>(a[0]) = readPropertyAsPointF(id); - break; - case QV4::CompiledData::Property::Custom: - *reinterpret_cast<QObject **>(a[0]) = readPropertyAsQObject(id); - break; - case QV4::CompiledData::Property::Variant: + case QV4::CompiledData::BuiltinType::Size: + *reinterpret_cast<QSizeF *>(a[0]) = readPropertyAsSizeF(id); + break; + case QV4::CompiledData::BuiltinType::Point: + *reinterpret_cast<QPointF *>(a[0]) = readPropertyAsPointF(id); + break; + case QV4::CompiledData::BuiltinType::Variant: + *reinterpret_cast<QVariant *>(a[0]) = readPropertyAsVariant(id); + break; + case QV4::CompiledData::BuiltinType::Font: + case QV4::CompiledData::BuiltinType::Time: + case QV4::CompiledData::BuiltinType::Color: + case QV4::CompiledData::BuiltinType::Vector2D: + case QV4::CompiledData::BuiltinType::Vector3D: + case QV4::CompiledData::BuiltinType::Vector4D: + case QV4::CompiledData::BuiltinType::Matrix4x4: + case QV4::CompiledData::BuiltinType::Quaternion: + Q_ASSERT(fallbackMetaType != QMetaType::UnknownType); + if (QV4::MemberData *md = propertyAndMethodStorageAsMemberData()) { + QVariant propertyAsVariant; + if (const QV4::VariantObject *v = (md->data() + id)->as<QV4::VariantObject>()) + propertyAsVariant = v->d()->data(); + QQml_valueTypeProvider()->readValueType(propertyAsVariant, a[0], fallbackMetaType); + } + break; + case QV4::CompiledData::BuiltinType::Var: + if (ep) { *reinterpret_cast<QVariant *>(a[0]) = readPropertyAsVariant(id); - break; - case QV4::CompiledData::Property::CustomList: { + } else { + // if the context was disposed, we just return an invalid variant from read. + *reinterpret_cast<QVariant *>(a[0]) = QVariant(); + } + break; + case QV4::CompiledData::BuiltinType::InvalidBuiltin: + if (property.isList) { QList<QObject *> *list = readPropertyAsList(id); QQmlListProperty<QObject> *p = static_cast<QQmlListProperty<QObject> *>(a[0]); *p = QQmlListProperty<QObject>(object, list, - list_append, list_count, list_at, - list_clear); + list_append, list_count, list_at, + list_clear); p->dummy1 = this; p->dummy2 = reinterpret_cast<void *>(quintptr(methodOffset() + id)); - break; + } else { + *reinterpret_cast<QObject **>(a[0]) = readPropertyAsQObject(id); } - case QV4::CompiledData::Property::Font: - case QV4::CompiledData::Property::Time: - case QV4::CompiledData::Property::Color: - case QV4::CompiledData::Property::Vector2D: - case QV4::CompiledData::Property::Vector3D: - case QV4::CompiledData::Property::Vector4D: - case QV4::CompiledData::Property::Matrix4x4: - case QV4::CompiledData::Property::Quaternion: - Q_ASSERT(fallbackMetaType != QMetaType::UnknownType); - if (QV4::MemberData *md = propertyAndMethodStorageAsMemberData()) { - QVariant propertyAsVariant; - if (const QV4::VariantObject *v = (md->data() + id)->as<QV4::VariantObject>()) - propertyAsVariant = v->d()->data(); - QQml_valueTypeProvider()->readValueType(propertyAsVariant, a[0], fallbackMetaType); + } + + } else if (c == QMetaObject::WriteProperty) { + bool needActivate = false; + switch (t) { + case QV4::CompiledData::BuiltinType::Int: + needActivate = *reinterpret_cast<int *>(a[0]) != readPropertyAsInt(id); + writeProperty(id, *reinterpret_cast<int *>(a[0])); + break; + case QV4::CompiledData::BuiltinType::Bool: + needActivate = *reinterpret_cast<bool *>(a[0]) != readPropertyAsBool(id); + writeProperty(id, *reinterpret_cast<bool *>(a[0])); + break; + case QV4::CompiledData::BuiltinType::Real: + needActivate = *reinterpret_cast<double *>(a[0]) != readPropertyAsDouble(id); + writeProperty(id, *reinterpret_cast<double *>(a[0])); + break; + case QV4::CompiledData::BuiltinType::String: + needActivate = *reinterpret_cast<QString *>(a[0]) != readPropertyAsString(id); + writeProperty(id, *reinterpret_cast<QString *>(a[0])); + break; + case QV4::CompiledData::BuiltinType::Url: + needActivate = *reinterpret_cast<QUrl *>(a[0]) != readPropertyAsUrl(id); + writeProperty(id, *reinterpret_cast<QUrl *>(a[0])); + break; + case QV4::CompiledData::BuiltinType::Date: + needActivate = *reinterpret_cast<QDate *>(a[0]) != readPropertyAsDate(id); + writeProperty(id, *reinterpret_cast<QDate *>(a[0])); + break; + case QV4::CompiledData::BuiltinType::DateTime: + needActivate = *reinterpret_cast<QDateTime *>(a[0]) != readPropertyAsDateTime(id); + writeProperty(id, *reinterpret_cast<QDateTime *>(a[0])); + break; + case QV4::CompiledData::BuiltinType::Rect: + needActivate = *reinterpret_cast<QRectF *>(a[0]) != readPropertyAsRectF(id); + writeProperty(id, *reinterpret_cast<QRectF *>(a[0])); + break; + case QV4::CompiledData::BuiltinType::Size: + needActivate = *reinterpret_cast<QSizeF *>(a[0]) != readPropertyAsSizeF(id); + writeProperty(id, *reinterpret_cast<QSizeF *>(a[0])); + break; + case QV4::CompiledData::BuiltinType::Point: + needActivate = *reinterpret_cast<QPointF *>(a[0]) != readPropertyAsPointF(id); + writeProperty(id, *reinterpret_cast<QPointF *>(a[0])); + break; + case QV4::CompiledData::BuiltinType::Variant: + writeProperty(id, *reinterpret_cast<QVariant *>(a[0])); + break; + case QV4::CompiledData::BuiltinType::Font: + case QV4::CompiledData::BuiltinType::Time: + case QV4::CompiledData::BuiltinType::Color: + case QV4::CompiledData::BuiltinType::Vector2D: + case QV4::CompiledData::BuiltinType::Vector3D: + case QV4::CompiledData::BuiltinType::Vector4D: + case QV4::CompiledData::BuiltinType::Matrix4x4: + case QV4::CompiledData::BuiltinType::Quaternion: + Q_ASSERT(fallbackMetaType != QMetaType::UnknownType); + if (QV4::MemberData *md = propertyAndMethodStorageAsMemberData()) { + const QV4::VariantObject *v = (md->data() + id)->as<QV4::VariantObject>(); + if (!v) { + md->set(engine, id, engine->newVariantObject(QVariant())); + v = (md->data() + id)->as<QV4::VariantObject>(); + QQml_valueTypeProvider()->initValueType(fallbackMetaType, v->d()->data()); } - break; - case QV4::CompiledData::Property::Var: - Q_UNREACHABLE(); + needActivate = !QQml_valueTypeProvider()->equalValueType(fallbackMetaType, a[0], v->d()->data()); + QQml_valueTypeProvider()->writeValueType(fallbackMetaType, a[0], v->d()->data()); } - - } else if (c == QMetaObject::WriteProperty) { - - switch(t) { - case QV4::CompiledData::Property::Int: - needActivate = *reinterpret_cast<int *>(a[0]) != readPropertyAsInt(id); - writeProperty(id, *reinterpret_cast<int *>(a[0])); - break; - case QV4::CompiledData::Property::Bool: - needActivate = *reinterpret_cast<bool *>(a[0]) != readPropertyAsBool(id); - writeProperty(id, *reinterpret_cast<bool *>(a[0])); - break; - case QV4::CompiledData::Property::Real: - needActivate = *reinterpret_cast<double *>(a[0]) != readPropertyAsDouble(id); - writeProperty(id, *reinterpret_cast<double *>(a[0])); - break; - case QV4::CompiledData::Property::String: - needActivate = *reinterpret_cast<QString *>(a[0]) != readPropertyAsString(id); - writeProperty(id, *reinterpret_cast<QString *>(a[0])); - break; - case QV4::CompiledData::Property::Url: - needActivate = *reinterpret_cast<QUrl *>(a[0]) != readPropertyAsUrl(id); - writeProperty(id, *reinterpret_cast<QUrl *>(a[0])); - break; - case QV4::CompiledData::Property::Date: - needActivate = *reinterpret_cast<QDate *>(a[0]) != readPropertyAsDate(id); - writeProperty(id, *reinterpret_cast<QDate *>(a[0])); - break; - case QV4::CompiledData::Property::DateTime: - needActivate = *reinterpret_cast<QDateTime *>(a[0]) != readPropertyAsDateTime(id); - writeProperty(id, *reinterpret_cast<QDateTime *>(a[0])); - break; - case QV4::CompiledData::Property::Rect: - needActivate = *reinterpret_cast<QRectF *>(a[0]) != readPropertyAsRectF(id); - writeProperty(id, *reinterpret_cast<QRectF *>(a[0])); - break; - case QV4::CompiledData::Property::Size: - needActivate = *reinterpret_cast<QSizeF *>(a[0]) != readPropertyAsSizeF(id); - writeProperty(id, *reinterpret_cast<QSizeF *>(a[0])); - break; - case QV4::CompiledData::Property::Point: - needActivate = *reinterpret_cast<QPointF *>(a[0]) != readPropertyAsPointF(id); - writeProperty(id, *reinterpret_cast<QPointF *>(a[0])); - break; - case QV4::CompiledData::Property::Custom: - needActivate = *reinterpret_cast<QObject **>(a[0]) != readPropertyAsQObject(id); - writeProperty(id, *reinterpret_cast<QObject **>(a[0])); - break; - case QV4::CompiledData::Property::Variant: + break; + case QV4::CompiledData::BuiltinType::Var: + if (ep) writeProperty(id, *reinterpret_cast<QVariant *>(a[0])); - break; - case QV4::CompiledData::Property::CustomList: + break; + case QV4::CompiledData::BuiltinType::InvalidBuiltin: + if (property.isList) { // Writing such a property is not supported. Content is added through the list property // methods. - break; - case QV4::CompiledData::Property::Font: - case QV4::CompiledData::Property::Time: - case QV4::CompiledData::Property::Color: - case QV4::CompiledData::Property::Vector2D: - case QV4::CompiledData::Property::Vector3D: - case QV4::CompiledData::Property::Vector4D: - case QV4::CompiledData::Property::Matrix4x4: - case QV4::CompiledData::Property::Quaternion: - Q_ASSERT(fallbackMetaType != QMetaType::UnknownType); - if (QV4::MemberData *md = propertyAndMethodStorageAsMemberData()) { - const QV4::VariantObject *v = (md->data() + id)->as<QV4::VariantObject>(); - if (!v) { - md->set(engine, id, engine->newVariantObject(QVariant())); - v = (md->data() + id)->as<QV4::VariantObject>(); - QQml_valueTypeProvider()->initValueType(fallbackMetaType, v->d()->data()); - } - needActivate = !QQml_valueTypeProvider()->equalValueType(fallbackMetaType, a[0], v->d()->data()); - QQml_valueTypeProvider()->writeValueType(fallbackMetaType, a[0], v->d()->data()); - } - break; - case QV4::CompiledData::Property::Var: - Q_UNREACHABLE(); + } else { + needActivate = *reinterpret_cast<QObject **>(a[0]) != readPropertyAsQObject(id); + writeProperty(id, *reinterpret_cast<QObject **>(a[0])); } - } - } + } - if (c == QMetaObject::WriteProperty && needActivate) { - activate(object, methodOffset() + id, nullptr); + if (needActivate) + activate(object, methodOffset() + id, nullptr); } return -1; @@ -1000,7 +966,7 @@ QV4::ReturnedValue QQmlVMEMetaObject::method(int index) const QV4::ReturnedValue QQmlVMEMetaObject::readVarProperty(int id) const { - Q_ASSERT(compiledObject && compiledObject->propertyTable()[id].type == QV4::CompiledData::Property::Var); + Q_ASSERT(compiledObject && compiledObject->propertyTable()[id].builtinType() == QV4::CompiledData::BuiltinType::Var); QV4::MemberData *md = propertyAndMethodStorageAsMemberData(); if (md) @@ -1025,7 +991,7 @@ QVariant QQmlVMEMetaObject::readPropertyAsVariant(int id) const void QQmlVMEMetaObject::writeVarProperty(int id, const QV4::Value &value) { - Q_ASSERT(compiledObject && compiledObject->propertyTable()[id].type == QV4::CompiledData::Property::Var); + Q_ASSERT(compiledObject && compiledObject->propertyTable()[id].builtinType() == QV4::CompiledData::BuiltinType::Var); QV4::MemberData *md = propertyAndMethodStorageAsMemberData(); if (!md) @@ -1065,7 +1031,7 @@ void QQmlVMEMetaObject::writeVarProperty(int id, const QV4::Value &value) void QQmlVMEMetaObject::writeProperty(int id, const QVariant &value) { - if (compiledObject && compiledObject->propertyTable()[id].type == QV4::CompiledData::Property::Var) { + if (compiledObject && compiledObject->propertyTable()[id].builtinType() == QV4::CompiledData::BuiltinType::Var) { QV4::MemberData *md = propertyAndMethodStorageAsMemberData(); if (!md) return; |