aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/qml
diff options
context:
space:
mode:
Diffstat (limited to 'src/qml/qml')
-rw-r--r--src/qml/qml/ftw/qbipointer_p.h (renamed from src/qml/qml/ftw/qflagpointer_p.h)107
-rw-r--r--src/qml/qml/ftw/qdoubleendedlist_p.h42
-rw-r--r--src/qml/qml/ftw/qfieldlist_p.h43
-rw-r--r--src/qml/qml/ftw/qfinitestack_p.h42
-rw-r--r--src/qml/qml/ftw/qhashedstring.cpp40
-rw-r--r--src/qml/qml/ftw/qhashedstring_p.h70
-rw-r--r--src/qml/qml/ftw/qintrusivelist.cpp40
-rw-r--r--src/qml/qml/ftw/qintrusivelist_p.h326
-rw-r--r--src/qml/qml/ftw/qlazilyallocated_p.h42
-rw-r--r--src/qml/qml/ftw/qlinkedstringhash_p.h40
-rw-r--r--src/qml/qml/ftw/qpodvector_p.h42
-rw-r--r--src/qml/qml/ftw/qprimefornumbits_p.h40
-rw-r--r--src/qml/qml/ftw/qqmlnullablevalue_p.h113
-rw-r--r--src/qml/qml/ftw/qqmlrefcount_p.h147
-rw-r--r--src/qml/qml/ftw/qqmlthread.cpp142
-rw-r--r--src/qml/qml/ftw/qqmlthread_p.h268
-rw-r--r--src/qml/qml/ftw/qrecursionwatcher_p.h42
-rw-r--r--src/qml/qml/ftw/qrecyclepool_p.h76
-rw-r--r--src/qml/qml/ftw/qstringhash_p.h57
-rw-r--r--src/qml/qml/qqml.cpp2219
-rw-r--r--src/qml/qml/qqml.h487
-rw-r--r--src/qml/qml/qqmlabstractbinding.cpp174
-rw-r--r--src/qml/qml/qqmlabstractbinding_p.h89
-rw-r--r--src/qml/qml/qqmlabstracturlinterceptor.cpp40
-rw-r--r--src/qml/qml/qqmlabstracturlinterceptor.h43
-rw-r--r--src/qml/qml/qqmlanybinding_p.h184
-rw-r--r--src/qml/qml/qqmlapplicationengine.cpp191
-rw-r--r--src/qml/qml/qqmlapplicationengine.h44
-rw-r--r--src/qml/qml/qqmlapplicationengine_p.h47
-rw-r--r--src/qml/qml/qqmlbinding.cpp628
-rw-r--r--src/qml/qml/qqmlbinding_p.h107
-rw-r--r--src/qml/qml/qqmlboundsignal.cpp148
-rw-r--r--src/qml/qml/qqmlboundsignal_p.h53
-rw-r--r--src/qml/qml/qqmlbuiltinfunctions.cpp (renamed from src/qml/qml/v8/qqmlbuiltinfunctions.cpp)817
-rw-r--r--src/qml/qml/qqmlbuiltinfunctions_p.h (renamed from src/qml/qml/v8/qqmlbuiltinfunctions_p.h)100
-rw-r--r--src/qml/qml/qqmlcomponent.cpp836
-rw-r--r--src/qml/qml/qqmlcomponent.h68
-rw-r--r--src/qml/qml/qqmlcomponent_p.h275
-rw-r--r--src/qml/qml/qqmlcomponentandaliasresolver_p.h480
-rw-r--r--src/qml/qml/qqmlcomponentattached_p.h53
-rw-r--r--src/qml/qml/qqmlcontext.cpp309
-rw-r--r--src/qml/qml/qqmlcontext.h44
-rw-r--r--src/qml/qml/qqmlcontext_p.h48
-rw-r--r--src/qml/qml/qqmlcontextdata.cpp129
-rw-r--r--src/qml/qml/qqmlcontextdata_p.h136
-rw-r--r--src/qml/qml/qqmlcustomparser.cpp123
-rw-r--r--src/qml/qml/qqmlcustomparser_p.h49
-rw-r--r--src/qml/qml/qqmldata_p.h196
-rw-r--r--src/qml/qml/qqmldatablob.cpp85
-rw-r--r--src/qml/qml/qqmldatablob_p.h59
-rw-r--r--src/qml/qml/qqmldelayedcallqueue.cpp74
-rw-r--r--src/qml/qml/qqmldelayedcallqueue_p.h47
-rw-r--r--src/qml/qml/qqmldirdata.cpp68
-rw-r--r--src/qml/qml/qqmldirdata_p.h70
-rw-r--r--src/qml/qml/qqmlengine.cpp1319
-rw-r--r--src/qml/qml/qqmlengine.h65
-rw-r--r--src/qml/qml/qqmlengine_p.h363
-rw-r--r--src/qml/qml/qqmlenumdata_p.h40
-rw-r--r--src/qml/qml/qqmlenumvalue_p.h41
-rw-r--r--src/qml/qml/qqmlerror.cpp45
-rw-r--r--src/qml/qml/qqmlerror.h50
-rw-r--r--src/qml/qml/qqmlexpression.cpp56
-rw-r--r--src/qml/qml/qqmlexpression.h41
-rw-r--r--src/qml/qml/qqmlexpression_p.h42
-rw-r--r--src/qml/qml/qqmlextensioninterface.cpp17
-rw-r--r--src/qml/qml/qqmlextensioninterface.h46
-rw-r--r--src/qml/qml/qqmlextensionplugin.cpp107
-rw-r--r--src/qml/qml/qqmlextensionplugin.h52
-rw-r--r--src/qml/qml/qqmlextensionplugin_p.h42
-rw-r--r--src/qml/qml/qqmlfile.cpp418
-rw-r--r--src/qml/qml/qqmlfile.h46
-rw-r--r--src/qml/qml/qqmlfileselector.cpp54
-rw-r--r--src/qml/qml/qqmlfileselector.h40
-rw-r--r--src/qml/qml/qqmlfileselector_p.h46
-rw-r--r--src/qml/qml/qqmlfinalizer.cpp59
-rw-r--r--src/qml/qml/qqmlfinalizer_p.h34
-rw-r--r--src/qml/qml/qqmlglobal.cpp854
-rw-r--r--src/qml/qml/qqmlglobal_p.h132
-rw-r--r--src/qml/qml/qqmlguard_p.h162
-rw-r--r--src/qml/qml/qqmlguardedcontextdata_p.h46
-rw-r--r--src/qml/qml/qqmlimport.cpp1526
-rw-r--r--src/qml/qml/qqmlimport_p.h383
-rw-r--r--src/qml/qml/qqmlincubator.cpp189
-rw-r--r--src/qml/qml/qqmlincubator.h41
-rw-r--r--src/qml/qml/qqmlincubator_p.h66
-rw-r--r--src/qml/qml/qqmlinfo.cpp61
-rw-r--r--src/qml/qml/qqmlinfo.h40
-rw-r--r--src/qml/qml/qqmlirloader.cpp120
-rw-r--r--src/qml/qml/qqmlirloader_p.h42
-rw-r--r--src/qml/qml/qqmljavascriptexpression.cpp303
-rw-r--r--src/qml/qml/qqmljavascriptexpression_p.h77
-rw-r--r--src/qml/qml/qqmllist.cpp149
-rw-r--r--src/qml/qml/qqmllist.h100
-rw-r--r--src/qml/qml/qqmllist_p.h230
-rw-r--r--src/qml/qml/qqmllistwrapper.cpp749
-rw-r--r--src/qml/qml/qqmllistwrapper_p.h89
-rw-r--r--src/qml/qml/qqmllocale.cpp634
-rw-r--r--src/qml/qml/qqmllocale_p.h290
-rw-r--r--src/qml/qml/qqmlloggingcategory.cpp91
-rw-r--r--src/qml/qml/qqmlloggingcategory_p.h45
-rw-r--r--src/qml/qml/qqmlmetamoduleregistration.cpp26
-rw-r--r--src/qml/qml/qqmlmetaobject.cpp102
-rw-r--r--src/qml/qml/qqmlmetaobject_p.h155
-rw-r--r--src/qml/qml/qqmlmetatype.cpp1252
-rw-r--r--src/qml/qml/qqmlmetatype_p.h346
-rw-r--r--src/qml/qml/qqmlmetatypedata.cpp145
-rw-r--r--src/qml/qml/qqmlmetatypedata_p.h67
-rw-r--r--src/qml/qml/qqmlmoduleregistration.cpp40
-rw-r--r--src/qml/qml/qqmlmoduleregistration.h40
-rw-r--r--src/qml/qml/qqmlnetworkaccessmanagerfactory.cpp55
-rw-r--r--src/qml/qml/qqmlnetworkaccessmanagerfactory.h40
-rw-r--r--src/qml/qml/qqmlnotifier.cpp48
-rw-r--r--src/qml/qml/qqmlnotifier_p.h57
-rw-r--r--src/qml/qml/qqmlobjectcreator.cpp873
-rw-r--r--src/qml/qml/qqmlobjectcreator_p.h210
-rw-r--r--src/qml/qml/qqmlobjectorgadget.cpp40
-rw-r--r--src/qml/qml/qqmlobjectorgadget_p.h44
-rw-r--r--src/qml/qml/qqmlopenmetaobject.cpp130
-rw-r--r--src/qml/qml/qqmlopenmetaobject_p.h53
-rw-r--r--src/qml/qml/qqmlparserstatus.cpp40
-rw-r--r--src/qml/qml/qqmlparserstatus.h40
-rw-r--r--src/qml/qml/qqmlplatform.cpp40
-rw-r--r--src/qml/qml/qqmlplatform_p.h44
-rw-r--r--src/qml/qml/qqmlpluginimporter.cpp612
-rw-r--r--src/qml/qml/qqmlpluginimporter_p.h81
-rw-r--r--src/qml/qml/qqmlprivate.h475
-rw-r--r--src/qml/qml/qqmlproperty.cpp970
-rw-r--r--src/qml/qml/qqmlproperty.h55
-rw-r--r--src/qml/qml/qqmlproperty_p.h80
-rw-r--r--src/qml/qml/qqmlpropertybinding.cpp453
-rw-r--r--src/qml/qml/qqmlpropertybinding_p.h367
-rw-r--r--src/qml/qml/qqmlpropertycache.cpp583
-rw-r--r--src/qml/qml/qqmlpropertycache_p.h370
-rw-r--r--src/qml/qml/qqmlpropertycachecreator.cpp173
-rw-r--r--src/qml/qml/qqmlpropertycachecreator_p.h829
-rw-r--r--src/qml/qml/qqmlpropertycachemethodarguments_p.h51
-rw-r--r--src/qml/qml/qqmlpropertycachevector_p.h166
-rw-r--r--src/qml/qml/qqmlpropertydata_p.h217
-rw-r--r--src/qml/qml/qqmlpropertyindex_p.h40
-rw-r--r--src/qml/qml/qqmlpropertyresolver.cpp55
-rw-r--r--src/qml/qml/qqmlpropertyresolver_p.h50
-rw-r--r--src/qml/qml/qqmlpropertytopropertybinding.cpp128
-rw-r--r--src/qml/qml/qqmlpropertytopropertybinding_p.h64
-rw-r--r--src/qml/qml/qqmlpropertyvalidator.cpp279
-rw-r--r--src/qml/qml/qqmlpropertyvalidator_p.h59
-rw-r--r--src/qml/qml/qqmlpropertyvalueinterceptor.cpp57
-rw-r--r--src/qml/qml/qqmlpropertyvalueinterceptor_p.h44
-rw-r--r--src/qml/qml/qqmlpropertyvaluesource.cpp42
-rw-r--r--src/qml/qml/qqmlpropertyvaluesource.h40
-rw-r--r--src/qml/qml/qqmlproxymetaobject.cpp139
-rw-r--r--src/qml/qml/qqmlproxymetaobject_p.h70
-rw-r--r--src/qml/qml/qqmlregistration.h15
-rw-r--r--src/qml/qml/qqmlscriptblob.cpp142
-rw-r--r--src/qml/qml/qqmlscriptblob_p.h44
-rw-r--r--src/qml/qml/qqmlscriptdata.cpp60
-rw-r--r--src/qml/qml/qqmlscriptdata_p.h55
-rw-r--r--src/qml/qml/qqmlscriptstring.cpp64
-rw-r--r--src/qml/qml/qqmlscriptstring.h42
-rw-r--r--src/qml/qml/qqmlscriptstring_p.h41
-rw-r--r--src/qml/qml/qqmlsourcecoordinate_p.h42
-rw-r--r--src/qml/qml/qqmlstringconverters.cpp120
-rw-r--r--src/qml/qml/qqmlstringconverters_p.h131
-rw-r--r--src/qml/qml/qqmltype.cpp684
-rw-r--r--src/qml/qml/qqmltype_p.h101
-rw-r--r--src/qml/qml/qqmltype_p_p.h280
-rw-r--r--src/qml/qml/qqmltypecompiler.cpp856
-rw-r--r--src/qml/qml/qqmltypecompiler_p.h138
-rw-r--r--src/qml/qml/qqmltypedata.cpp685
-rw-r--r--src/qml/qml/qqmltypedata_p.h76
-rw-r--r--src/qml/qml/qqmltypeloader.cpp717
-rw-r--r--src/qml/qml/qqmltypeloader_p.h142
-rw-r--r--src/qml/qml/qqmltypeloadernetworkreplyproxy.cpp42
-rw-r--r--src/qml/qml/qqmltypeloadernetworkreplyproxy_p.h43
-rw-r--r--src/qml/qml/qqmltypeloaderqmldircontent.cpp44
-rw-r--r--src/qml/qml/qqmltypeloaderqmldircontent_p.h50
-rw-r--r--src/qml/qml/qqmltypeloaderthread.cpp104
-rw-r--r--src/qml/qml/qqmltypeloaderthread_p.h79
-rw-r--r--src/qml/qml/qqmltypemodule.cpp61
-rw-r--r--src/qml/qml/qqmltypemodule_p.h80
-rw-r--r--src/qml/qml/qqmltypemoduleversion.cpp40
-rw-r--r--src/qml/qml/qqmltypemoduleversion_p.h40
-rw-r--r--src/qml/qml/qqmltypenamecache.cpp169
-rw-r--r--src/qml/qml/qqmltypenamecache_p.h177
-rw-r--r--src/qml/qml/qqmltypenotavailable.cpp51
-rw-r--r--src/qml/qml/qqmltypenotavailable_p.h69
-rw-r--r--src/qml/qml/qqmltypewrapper.cpp342
-rw-r--r--src/qml/qml/qqmltypewrapper_p.h49
-rw-r--r--src/qml/qml/qqmlvaluetype.cpp103
-rw-r--r--src/qml/qml/qqmlvaluetype_p.h169
-rw-r--r--src/qml/qml/qqmlvaluetypeproxybinding.cpp45
-rw-r--r--src/qml/qml/qqmlvaluetypeproxybinding_p.h42
-rw-r--r--src/qml/qml/qqmlvaluetypewrapper.cpp624
-rw-r--r--src/qml/qml/qqmlvaluetypewrapper_p.h154
-rw-r--r--src/qml/qml/qqmlvme.cpp65
-rw-r--r--src/qml/qml/qqmlvme_p.h76
-rw-r--r--src/qml/qml/qqmlvmemetaobject.cpp920
-rw-r--r--src/qml/qml/qqmlvmemetaobject_p.h188
-rw-r--r--src/qml/qml/qqmlxmlhttprequest.cpp226
-rw-r--r--src/qml/qml/qqmlxmlhttprequest_p.h42
-rw-r--r--src/qml/qml/v8/qv4domerrors.cpp71
-rw-r--r--src/qml/qml/v8/qv4domerrors_p.h93
-rw-r--r--src/qml/qml/v8/qv4sqlerrors.cpp63
-rw-r--r--src/qml/qml/v8/qv4sqlerrors_p.h74
203 files changed, 20822 insertions, 18125 deletions
diff --git a/src/qml/qml/ftw/qflagpointer_p.h b/src/qml/qml/ftw/qbipointer_p.h
index c8824f3866..1597b9e4fc 100644
--- a/src/qml/qml/ftw/qflagpointer_p.h
+++ b/src/qml/qml/ftw/qbipointer_p.h
@@ -1,44 +1,8 @@
-/****************************************************************************
-**
-** 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 QFLAGPOINTER_P_H
-#define QFLAGPOINTER_P_H
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QBIPOINTER_P_H
+#define QBIPOINTER_P_H
//
// W A R N I N G
@@ -51,7 +15,9 @@
// We mean it.
//
-#include <QtCore/qglobal.h>
+#include <QtCore/private/qglobal_p.h>
+
+#include <QtCore/qhashfunctions.h>
QT_BEGIN_NAMESPACE
@@ -66,13 +32,30 @@ template <> struct QFlagPointerAlignment<void>
};
}
+/*!
+ \internal
+ \class template<typename T1, typename T2> QBiPointer<T1, T2>
+
+ \short QBiPointer can be thought of as a space-optimized std::variant<T1*, T2*>
+ with a nicer API to check the active pointer. Its other main feature is that
+ it only requires sizeof(void *) space.
+
+ \note It can also store one additional flag for a user defined purpose.
+ */
template<typename T, typename T2>
class QBiPointer {
public:
- inline QBiPointer();
- inline QBiPointer(T *);
- inline QBiPointer(T2 *);
- inline QBiPointer(const QBiPointer<T, T2> &o);
+ Q_NODISCARD_CTOR constexpr QBiPointer() noexcept = default;
+ ~QBiPointer() noexcept = default;
+ Q_NODISCARD_CTOR QBiPointer(const QBiPointer &o) noexcept = default;
+ Q_NODISCARD_CTOR QBiPointer(QBiPointer &&o) noexcept = default;
+ QBiPointer<T, T2> &operator=(const QBiPointer<T, T2> &o) noexcept = default;
+ QBiPointer<T, T2> &operator=(QBiPointer<T, T2> &&o) noexcept = default;
+
+ void swap(QBiPointer &other) noexcept { std::swap(ptr_value, other.ptr_value); }
+
+ Q_NODISCARD_CTOR inline QBiPointer(T *);
+ Q_NODISCARD_CTOR inline QBiPointer(T2 *);
inline bool isNull() const;
inline bool isT1() const;
@@ -83,7 +66,6 @@ public:
inline void clearFlag();
inline void setFlagValue(bool);
- inline QBiPointer<T, T2> &operator=(const QBiPointer<T, T2> &o);
inline QBiPointer<T, T2> &operator=(T *);
inline QBiPointer<T, T2> &operator=(T2 *);
@@ -102,14 +84,16 @@ public:
return !(ptr1 == ptr2);
}
- friend inline void swap(QBiPointer<T, T2> ptr1, QBiPointer<T, T2> ptr2)
- {
- qSwap(ptr1.ptr_value, ptr2.ptr_value);
- }
+ friend void swap(QBiPointer &lhs, QBiPointer &rhs) noexcept { lhs.swap(rhs); }
inline T *asT1() const;
inline T2 *asT2() const;
+ friend size_t qHash(const QBiPointer<T, T2> &ptr, size_t seed = 0)
+ {
+ return qHash(ptr.isNull() ? quintptr(0) : ptr.ptr_value, seed);
+ }
+
private:
quintptr ptr_value = 0;
@@ -118,10 +102,8 @@ private:
static const quintptr FlagsMask = FlagBit | Flag2Bit;
};
-template<typename T, typename T2>
-QBiPointer<T, T2>::QBiPointer()
-{
-}
+template <typename...Ts> // can't use commas in macros
+Q_DECLARE_TYPEINFO_BODY(QBiPointer<Ts...>, Q_PRIMITIVE_TYPE);
template<typename T, typename T2>
QBiPointer<T, T2>::QBiPointer(T *v)
@@ -142,12 +124,6 @@ QBiPointer<T, T2>::QBiPointer(T2 *v)
}
template<typename T, typename T2>
-QBiPointer<T, T2>::QBiPointer(const QBiPointer<T, T2> &o)
-: ptr_value(o.ptr_value)
-{
-}
-
-template<typename T, typename T2>
bool QBiPointer<T, T2>::isNull() const
{
return 0 == (ptr_value & (~FlagsMask));
@@ -191,13 +167,6 @@ void QBiPointer<T, T2>::setFlagValue(bool v)
}
template<typename T, typename T2>
-QBiPointer<T, T2> &QBiPointer<T, T2>::operator=(const QBiPointer<T, T2> &o)
-{
- ptr_value = o.ptr_value;
- return *this;
-}
-
-template<typename T, typename T2>
QBiPointer<T, T2> &QBiPointer<T, T2>::operator=(T *o)
{
Q_ASSERT((quintptr(o) & FlagsMask) == 0);
@@ -231,4 +200,4 @@ T2 *QBiPointer<T, T2>::asT2() const
QT_END_NAMESPACE
-#endif // QFLAGPOINTER_P_H
+#endif // QBIPOINTER_P_H
diff --git a/src/qml/qml/ftw/qdoubleendedlist_p.h b/src/qml/qml/ftw/qdoubleendedlist_p.h
index 33fe97502d..0a4d9f75d3 100644
--- a/src/qml/qml/ftw/qdoubleendedlist_p.h
+++ b/src/qml/qml/ftw/qdoubleendedlist_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 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$
-**
-****************************************************************************/
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QDOUBLEENDEDLIST_P_H
#define QDOUBLEENDEDLIST_P_H
@@ -51,7 +15,7 @@
// We mean it.
//
-#include <QtCore/qglobal.h>
+#include <QtCore/private/qglobal_p.h>
QT_BEGIN_NAMESPACE
diff --git a/src/qml/qml/ftw/qfieldlist_p.h b/src/qml/qml/ftw/qfieldlist_p.h
index b11fbcf40b..b4c6a55f1a 100644
--- a/src/qml/qml/ftw/qfieldlist_p.h
+++ b/src/qml/qml/ftw/qfieldlist_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QFIELDLIST_P_H
#define QFIELDLIST_P_H
@@ -51,10 +15,9 @@
// We mean it.
//
-#include <QtCore/qglobal.h>
+#include <QtCore/private/qglobal_p.h>
#include <QtCore/qtaggedpointer.h>
-#include <private/qflagpointer_p.h>
// QForwardFieldList is a super simple linked list that can only prepend
template<class N, N *N::*nextMember, typename Tag = QtPrivate::TagInfo<N>>
diff --git a/src/qml/qml/ftw/qfinitestack_p.h b/src/qml/qml/ftw/qfinitestack_p.h
index 9a74199137..3e206e205f 100644
--- a/src/qml/qml/ftw/qfinitestack_p.h
+++ b/src/qml/qml/ftw/qfinitestack_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QFINITESTACK_P_H
#define QFINITESTACK_P_H
@@ -51,7 +15,7 @@
// We mean it.
//
-#include <QtCore/qglobal.h>
+#include <QtCore/private/qglobal_p.h>
QT_BEGIN_NAMESPACE
diff --git a/src/qml/qml/ftw/qhashedstring.cpp b/src/qml/qml/ftw/qhashedstring.cpp
index b822e1b120..b963bc7984 100644
--- a/src/qml/qml/ftw/qhashedstring.cpp
+++ b/src/qml/qml/ftw/qhashedstring.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qhashedstring_p.h"
diff --git a/src/qml/qml/ftw/qhashedstring_p.h b/src/qml/qml/ftw/qhashedstring_p.h
index 8f0bd74c53..78ce738f3b 100644
--- a/src/qml/qml/ftw/qhashedstring_p.h
+++ b/src/qml/qml/ftw/qhashedstring_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QHASHEDSTRING_P_H
#define QHASHEDSTRING_P_H
@@ -55,8 +19,6 @@
#include <QtCore/qstring.h>
#include <private/qv4string_p.h>
-#include <private/qflagpointer_p.h>
-
#if defined(Q_OS_QNX)
#include <stdlib.h>
#endif
@@ -64,7 +26,7 @@
QT_BEGIN_NAMESPACE
class QHashedStringRef;
-class Q_QML_PRIVATE_EXPORT QHashedString : public QString
+class Q_QML_EXPORT QHashedString : public QString
{
public:
inline QHashedString();
@@ -94,7 +56,7 @@ private:
};
class QHashedCStringRef;
-class Q_QML_PRIVATE_EXPORT QHashedStringRef
+class Q_QML_EXPORT QHashedStringRef
{
public:
inline QHashedStringRef();
@@ -144,7 +106,7 @@ private:
mutable quint32 m_hash = 0;
};
-class Q_AUTOTEST_EXPORT QHashedCStringRef
+class QHashedCStringRef
{
public:
inline QHashedCStringRef();
@@ -157,7 +119,7 @@ public:
inline const char *constData() const;
inline int length() const;
- QString toUtf16() const;
+ Q_AUTOTEST_EXPORT QString toUtf16() const;
inline int utf16length() const;
inline void writeUtf16(QChar *) const;
inline void writeUtf16(quint16 *) const;
@@ -237,14 +199,18 @@ QHashedStringRef::QHashedStringRef()
{
}
+// QHashedStringRef is meant for identifiers, property names, etc.
+// Those should alsways be smaller than std::numeric_limits<int>::max())
QHashedStringRef::QHashedStringRef(const QString &str)
-: m_data(str.constData()), m_length(str.length()), m_hash(0)
+: m_data(str.constData()), m_length(int(str.size())), m_hash(0)
{
+ Q_ASSERT(str.size() <= std::numeric_limits<int>::max());
}
QHashedStringRef::QHashedStringRef(QStringView str)
-: m_data(str.constData()), m_length(str.length()), m_hash(0)
+: m_data(str.constData()), m_length(int(str.size())), m_hash(0)
{
+ Q_ASSERT(str.size() <= std::numeric_limits<int>::max());
}
QHashedStringRef::QHashedStringRef(const QChar *data, int length)
@@ -258,8 +224,9 @@ QHashedStringRef::QHashedStringRef(const QChar *data, int length, quint32 hash)
}
QHashedStringRef::QHashedStringRef(const QHashedString &string)
-: m_data(string.constData()), m_length(string.length()), m_hash(string.m_hash)
+: m_data(string.constData()), m_length(int(string.size())), m_hash(string.m_hash)
{
+ Q_ASSERT(string.size() <= std::numeric_limits<int>::max());
}
QHashedStringRef::QHashedStringRef(const QHashedStringRef &string)
@@ -286,7 +253,7 @@ bool QHashedStringRef::operator==(const QHashedString &string) const
if (m_hash && string.m_hash && m_hash != string.m_hash)
return false;
QStringView view {m_data, m_length};
- QStringView otherView {string.constData(), string.length()};
+ QStringView otherView {string.constData(), string.size()};
return view == otherView;
}
@@ -462,7 +429,12 @@ quint32 QHashedString::stringHash(const char *data, int length)
void QHashedString::computeHash() const
{
- m_hash = stringHash(constData(), length());
+ m_hash = stringHash(constData(), int(size()));
+}
+
+namespace QtPrivate {
+inline QString asString(const QHashedCStringRef &ref) { return ref.toUtf16(); }
+inline QString asString(const QHashedStringRef &ref) { return ref.toString(); }
}
QT_END_NAMESPACE
diff --git a/src/qml/qml/ftw/qintrusivelist.cpp b/src/qml/qml/ftw/qintrusivelist.cpp
index 2ebaffb375..a0a1ddb470 100644
--- a/src/qml/qml/ftw/qintrusivelist.cpp
+++ b/src/qml/qml/ftw/qintrusivelist.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qintrusivelist_p.h"
diff --git a/src/qml/qml/ftw/qintrusivelist_p.h b/src/qml/qml/ftw/qintrusivelist_p.h
index 8992be9f93..1170370fae 100644
--- a/src/qml/qml/ftw/qintrusivelist_p.h
+++ b/src/qml/qml/ftw/qintrusivelist_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QINTRUSIVELIST_P_H
#define QINTRUSIVELIST_P_H
@@ -51,220 +15,144 @@
// We mean it.
//
-#include <QtCore/qglobal.h>
+#include <QtCore/private/qglobal_p.h>
QT_BEGIN_NAMESPACE
-class QIntrusiveListNode;
-template<class N, QIntrusiveListNode N::*member>
-class QIntrusiveList
+class QIntrusiveListNode
{
public:
- inline QIntrusiveList();
- inline ~QIntrusiveList();
-
- inline bool isEmpty() const;
- inline void insert(N *n);
- inline void remove(N *n);
- inline bool contains(N *) const;
-
- class iterator {
- public:
- inline iterator();
- inline iterator(N *value);
-
- inline N *operator*() const;
- inline N *operator->() const;
- inline bool operator==(const iterator &other) const;
- inline bool operator!=(const iterator &other) const;
- inline iterator &operator++();
-
- inline iterator &erase();
-
- private:
- N *_value;
- };
- typedef iterator Iterator;
-
- inline N *first() const;
- static inline N *next(N *current);
+ ~QIntrusiveListNode() { remove(); }
+
+ void remove()
+ {
+ if (_prev) *_prev = _next;
+ if (_next) _next->_prev = _prev;
+ _prev = nullptr;
+ _next = nullptr;
+ }
- inline iterator begin();
- inline iterator end();
+ bool isInList() const { return _prev != nullptr; }
private:
- static inline N *nodeToN(QIntrusiveListNode *node);
-
- QIntrusiveListNode *__first = nullptr;
-};
-
-class QIntrusiveListNode
-{
-public:
- inline QIntrusiveListNode();
- inline ~QIntrusiveListNode();
-
- inline void remove();
- inline bool isInList() const;
+ template<class N, QIntrusiveListNode N::*member>
+ friend class QIntrusiveList;
QIntrusiveListNode *_next = nullptr;
QIntrusiveListNode**_prev = nullptr;
};
template<class N, QIntrusiveListNode N::*member>
-QIntrusiveList<N, member>::iterator::iterator()
-: _value(nullptr)
-{
-}
-
-template<class N, QIntrusiveListNode N::*member>
-QIntrusiveList<N, member>::iterator::iterator(N *value)
-: _value(value)
-{
-}
-
-template<class N, QIntrusiveListNode N::*member>
-N *QIntrusiveList<N, member>::iterator::operator*() const
-{
- return _value;
-}
-
-template<class N, QIntrusiveListNode N::*member>
-N *QIntrusiveList<N, member>::iterator::operator->() const
-{
- return _value;
-}
-
-template<class N, QIntrusiveListNode N::*member>
-bool QIntrusiveList<N, member>::iterator::operator==(const iterator &other) const
-{
- return other._value == _value;
-}
-
-template<class N, QIntrusiveListNode N::*member>
-bool QIntrusiveList<N, member>::iterator::operator!=(const iterator &other) const
-{
- return other._value != _value;
-}
-
-template<class N, QIntrusiveListNode N::*member>
-typename QIntrusiveList<N, member>::iterator &QIntrusiveList<N, member>::iterator::operator++()
-{
- _value = QIntrusiveList<N, member>::next(_value);
- return *this;
-}
-
-template<class N, QIntrusiveListNode N::*member>
-typename QIntrusiveList<N, member>::iterator &QIntrusiveList<N, member>::iterator::erase()
+class QIntrusiveList
{
- N *old = _value;
- _value = QIntrusiveList<N, member>::next(_value);
- (old->*member).remove();
- return *this;
-}
+private:
+ template<typename O>
+ class iterator_impl {
+ public:
+ iterator_impl() = default;
+ iterator_impl(O value) : _value(value) {}
+
+ O operator*() const { return _value; }
+ O operator->() const { return _value; }
+ bool operator==(const iterator_impl &other) const { return other._value == _value; }
+ bool operator!=(const iterator_impl &other) const { return other._value != _value; }
+ iterator_impl &operator++()
+ {
+ _value = QIntrusiveList<N, member>::next(_value);
+ return *this;
+ }
+
+ protected:
+ O _value = nullptr;
+ };
-template<class N, QIntrusiveListNode N::*member>
-QIntrusiveList<N, member>::QIntrusiveList()
+public:
+ class iterator : public iterator_impl<N *>
+ {
+ public:
+ iterator() = default;
+ iterator(N *value) : iterator_impl<N *>(value) {}
+
+ iterator &erase()
+ {
+ N *old = this->_value;
+ this->_value = QIntrusiveList<N, member>::next(this->_value);
+ (old->*member).remove();
+ return *this;
+ }
+ };
-{
-}
+ using const_iterator = iterator_impl<const N *>;
-template<class N, QIntrusiveListNode N::*member>
-QIntrusiveList<N, member>::~QIntrusiveList()
-{
- while (__first) __first->remove();
-}
+ using Iterator = iterator;
+ using ConstIterator = const_iterator;
-template<class N, QIntrusiveListNode N::*member>
-bool QIntrusiveList<N, member>::isEmpty() const
-{
- return __first == nullptr;
-}
+ ~QIntrusiveList() { while (__first) __first->remove(); }
-template<class N, QIntrusiveListNode N::*member>
-void QIntrusiveList<N, member>::insert(N *n)
-{
- QIntrusiveListNode *nnode = &(n->*member);
- nnode->remove();
+ bool isEmpty() const { return __first == nullptr; }
- nnode->_next = __first;
- if (nnode->_next) nnode->_next->_prev = &nnode->_next;
- __first = nnode;
- nnode->_prev = &__first;
-}
+ void insert(N *n)
+ {
+ QIntrusiveListNode *nnode = &(n->*member);
+ nnode->remove();
-template<class N, QIntrusiveListNode N::*member>
-void QIntrusiveList<N, member>::remove(N *n)
-{
- QIntrusiveListNode *nnode = &(n->*member);
- nnode->remove();
-}
+ nnode->_next = __first;
+ if (nnode->_next) nnode->_next->_prev = &nnode->_next;
+ __first = nnode;
+ nnode->_prev = &__first;
+ }
-template<class N, QIntrusiveListNode N::*member>
-bool QIntrusiveList<N, member>::contains(N *n) const
-{
- QIntrusiveListNode *nnode = __first;
- while (nnode) {
- if (nodeToN(nnode) == n)
- return true;
- nnode = nnode->_next;
+ void remove(N *n)
+ {
+ QIntrusiveListNode *nnode = &(n->*member);
+ nnode->remove();
}
- return false;
-}
-template<class N, QIntrusiveListNode N::*member>
-N *QIntrusiveList<N, member>::first() const
-{
- return __first?nodeToN(__first):nullptr;
-}
+ bool contains(const N *n) const
+ {
+ QIntrusiveListNode *nnode = __first;
+ while (nnode) {
+ if (nodeToN(nnode) == n)
+ return true;
+ nnode = nnode->_next;
+ }
+ return false;
+ }
-template<class N, QIntrusiveListNode N::*member>
-N *QIntrusiveList<N, member>::next(N *current)
-{
- QIntrusiveListNode *nextnode = (current->*member)._next;
- N *nextstruct = nextnode?nodeToN(nextnode):nullptr;
- return nextstruct;
-}
+ const N *first() const { return __first ? nodeToN(__first) : nullptr; }
+ N *first() { return __first ? nodeToN(__first) : nullptr; }
-template<class N, QIntrusiveListNode N::*member>
-typename QIntrusiveList<N, member>::iterator QIntrusiveList<N, member>::begin()
-{
- return __first?iterator(nodeToN(__first)):iterator();
-}
+ template<typename O>
+ static O next(O current)
+ {
+ QIntrusiveListNode *nextnode = (current->*member)._next;
+ return nextnode ? nodeToN(nextnode) : nullptr;
+ }
-template<class N, QIntrusiveListNode N::*member>
-typename QIntrusiveList<N, member>::iterator QIntrusiveList<N, member>::end()
-{
- return iterator();
-}
+ iterator begin() { return __first ? iterator(nodeToN(__first)) : iterator(); }
+ iterator end() { return iterator(); }
-template<class N, QIntrusiveListNode N::*member>
-N *QIntrusiveList<N, member>::nodeToN(QIntrusiveListNode *node)
-{
- return (N *)((char *)node - ((char *)&(((N *)nullptr)->*member) - (char *)nullptr));
-}
+ const_iterator begin() const
+ {
+ return __first ? const_iterator(nodeToN(__first)) : const_iterator();
+ }
-QIntrusiveListNode::QIntrusiveListNode()
-{
-}
+ const_iterator end() const { return const_iterator(); }
-QIntrusiveListNode::~QIntrusiveListNode()
-{
- remove();
-}
+private:
-void QIntrusiveListNode::remove()
-{
- if (_prev) *_prev = _next;
- if (_next) _next->_prev = _prev;
- _prev = nullptr;
- _next = nullptr;
-}
+ static N *nodeToN(QIntrusiveListNode *node)
+ {
+ QT_WARNING_PUSH
+#if defined(Q_CC_CLANG) && Q_CC_CLANG >= 1300
+ QT_WARNING_DISABLE_CLANG("-Wnull-pointer-subtraction")
+#endif
+ return (N *)((char *)node - ((char *)&(((N *)nullptr)->*member) - (char *)nullptr));
+ QT_WARNING_POP
+ }
-bool QIntrusiveListNode::isInList() const
-{
- return _prev != nullptr;
-}
+ QIntrusiveListNode *__first = nullptr;
+};
QT_END_NAMESPACE
diff --git a/src/qml/qml/ftw/qlazilyallocated_p.h b/src/qml/qml/ftw/qlazilyallocated_p.h
index 2bac84afb3..81f6ab7e89 100644
--- a/src/qml/qml/ftw/qlazilyallocated_p.h
+++ b/src/qml/qml/ftw/qlazilyallocated_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QLAZILYALLOCATED_P_H
#define QLAZILYALLOCATED_P_H
@@ -51,7 +15,7 @@
// We mean it.
//
-#include <QtCore/qglobal.h>
+#include <QtCore/private/qglobal_p.h>
#include <QtCore/qtaggedpointer.h>
QT_BEGIN_NAMESPACE
diff --git a/src/qml/qml/ftw/qlinkedstringhash_p.h b/src/qml/qml/ftw/qlinkedstringhash_p.h
index 495d78ea2f..a2309db717 100644
--- a/src/qml/qml/ftw/qlinkedstringhash_p.h
+++ b/src/qml/qml/ftw/qlinkedstringhash_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 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$
-**
-****************************************************************************/
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QLINKEDSTRINGHASH_P_H
#define QLINKEDSTRINGHASH_P_H
diff --git a/src/qml/qml/ftw/qpodvector_p.h b/src/qml/qml/ftw/qpodvector_p.h
index b2fb481793..6508071105 100644
--- a/src/qml/qml/ftw/qpodvector_p.h
+++ b/src/qml/qml/ftw/qpodvector_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QPODVECTOR_P_H
#define QPODVECTOR_P_H
@@ -51,7 +15,7 @@
// We mean it.
//
-#include <QtCore/qglobal.h>
+#include <QtCore/private/qglobal_p.h>
#include <QDebug>
QT_BEGIN_NAMESPACE
diff --git a/src/qml/qml/ftw/qprimefornumbits_p.h b/src/qml/qml/ftw/qprimefornumbits_p.h
index 6e9acbf7fd..82c9ea023e 100644
--- a/src/qml/qml/ftw/qprimefornumbits_p.h
+++ b/src/qml/qml/ftw/qprimefornumbits_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 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$
-**
-****************************************************************************/
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QPRIMEFORNUMBITS_P_H
#define QPRIMEFORNUMBITS_P_H
diff --git a/src/qml/qml/ftw/qqmlnullablevalue_p.h b/src/qml/qml/ftw/qqmlnullablevalue_p.h
index 5b3d2fc456..9a3f032b68 100644
--- a/src/qml/qml/ftw/qqmlnullablevalue_p.h
+++ b/src/qml/qml/ftw/qqmlnullablevalue_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLNULLABLEVALUE_P_H
#define QQMLNULLABLEVALUE_P_H
@@ -51,27 +15,76 @@
// We mean it.
//
+#include <QtCore/private/qglobal_p.h>
+
QT_BEGIN_NAMESPACE
template<typename T>
struct QQmlNullableValue
{
- QQmlNullableValue()
- : value(T()) {}
+ QQmlNullableValue() = default;
+
QQmlNullableValue(const QQmlNullableValue<T> &o)
- : isNull(o.isNull), value(o.value) {}
+ : m_value(o.m_value)
+ , m_isNull(o.m_isNull)
+ {}
+
+ QQmlNullableValue(QQmlNullableValue<T> &&o) noexcept
+ : m_value(std::move(o.value))
+ , m_isNull(std::exchange(o.m_isNull, true))
+ {}
+
QQmlNullableValue(const T &t)
- : isNull(false), value(t) {}
- QQmlNullableValue<T> &operator=(const T &t)
- { isNull = false; value = t; return *this; }
+ : m_value(t)
+ , m_isNull(false)
+ {}
+
+ QQmlNullableValue(T &&t) noexcept
+ : m_value(std::move(t))
+ , m_isNull(false)
+ {}
+
QQmlNullableValue<T> &operator=(const QQmlNullableValue<T> &o)
- { isNull = o.isNull; value = o.value; return *this; }
- operator T() const { return value; }
+ {
+ if (&o != this) {
+ m_value = o.m_value;
+ m_isNull = o.m_isNull;
+ }
+ return *this;
+ }
+
+ QQmlNullableValue<T> &operator=(QQmlNullableValue<T> &&o) noexcept
+ {
+ if (&o != this) {
+ m_value = std::move(o.m_value);
+ m_isNull = std::exchange(o.m_isNull, true);
+ }
+ return *this;
+ }
+
+ QQmlNullableValue<T> &operator=(const T &t)
+ {
+ m_value = t;
+ m_isNull = false;
+ return *this;
+ }
+
+ QQmlNullableValue<T> &operator=(T &&t) noexcept
+ {
+ m_value = std::move(t);
+ m_isNull = false;
+ return *this;
+ }
+
+ const T &value() const { return m_value; }
+ operator T() const { return m_value; }
+
+ void invalidate() { m_isNull = true; }
+ bool isValid() const { return !m_isNull; }
- void invalidate() { isNull = true; }
- bool isValid() const { return !isNull; }
- bool isNull = true;
- T value;
+private:
+ T m_value = T();
+ bool m_isNull = true;
};
QT_END_NAMESPACE
diff --git a/src/qml/qml/ftw/qqmlrefcount_p.h b/src/qml/qml/ftw/qqmlrefcount_p.h
index 1d016107e6..e7616915eb 100644
--- a/src/qml/qml/ftw/qqmlrefcount_p.h
+++ b/src/qml/qml/ftw/qqmlrefcount_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLREFCOUNT_P_H
#define QQMLREFCOUNT_P_H
@@ -57,23 +21,34 @@
QT_BEGIN_NAMESPACE
+template <typename T>
+class QQmlRefCounted;
-class Q_QML_PRIVATE_EXPORT QQmlRefCount
+class QQmlRefCount
{
Q_DISABLE_COPY_MOVE(QQmlRefCount)
public:
inline QQmlRefCount();
inline void addref() const;
- inline void release() const;
inline int count() const;
-protected:
- inline virtual ~QQmlRefCount();
+private:
+ inline ~QQmlRefCount();
+ template <typename T> friend class QQmlRefCounted;
private:
mutable QAtomicInt refCount;
};
+template <typename T>
+class QQmlRefCounted : public QQmlRefCount
+{
+public:
+ inline void release() const;
+protected:
+ inline ~QQmlRefCounted();
+};
+
template<class T>
class QQmlRefPointer
{
@@ -82,14 +57,16 @@ public:
AddRef,
Adopt
};
- inline QQmlRefPointer();
- inline QQmlRefPointer(T *, Mode m = AddRef);
- inline QQmlRefPointer(const QQmlRefPointer<T> &);
- inline QQmlRefPointer(QQmlRefPointer<T> &&);
+ Q_NODISCARD_CTOR inline QQmlRefPointer() noexcept;
+ Q_NODISCARD_CTOR inline QQmlRefPointer(T *, Mode m = AddRef);
+ Q_NODISCARD_CTOR inline QQmlRefPointer(const QQmlRefPointer &);
+ Q_NODISCARD_CTOR inline QQmlRefPointer(QQmlRefPointer &&) noexcept;
inline ~QQmlRefPointer();
+ void swap(QQmlRefPointer &other) noexcept { qt_ptr_swap(o, other.o); }
+
inline QQmlRefPointer<T> &operator=(const QQmlRefPointer<T> &o);
- inline QQmlRefPointer<T> &operator=(QQmlRefPointer<T> &&o);
+ inline QQmlRefPointer<T> &operator=(QQmlRefPointer<T> &&o) noexcept;
inline bool isNull() const { return !o; }
@@ -102,11 +79,54 @@ public:
inline T* take() { T *res = o; o = nullptr; return res; }
- friend bool operator==(const QQmlRefPointer &a, const QQmlRefPointer &b) { return a.o == b.o; }
+ friend bool operator==(const QQmlRefPointer &a, const QQmlRefPointer &b) noexcept
+ {
+ return a.o == b.o;
+ }
+
+ friend bool operator!=(const QQmlRefPointer &a, const QQmlRefPointer &b) noexcept
+ {
+ return !(a == b);
+ }
+
+ friend size_t qHash(const QQmlRefPointer &v, size_t seed = 0) noexcept
+ {
+ return qHash(v.o, seed);
+ }
+
+ void reset(T *t = nullptr)
+ {
+ if (t == o)
+ return;
+ if (o)
+ o->release();
+ if (t)
+ t->addref();
+ o = t;
+ }
+
private:
T *o;
};
+namespace QQml {
+/*!
+ \internal
+ Creates a QQmlRefPointer which takes ownership of a newly constructed T.
+ T must derive from QQmlRefCounted<T> (as we rely on an initial refcount of _1_).
+ T will be constructed by forwarding \a args to its constructor.
+ */
+template <typename T, typename ...Args>
+QQmlRefPointer<T> makeRefPointer(Args&&... args)
+{
+ static_assert(std::is_base_of_v<QQmlRefCount, T>);
+ return QQmlRefPointer<T>(new T(std::forward<Args>(args)...), QQmlRefPointer<T>::Adopt);
+}
+}
+
+template <typename T>
+Q_DECLARE_TYPEINFO_BODY(QQmlRefPointer<T>, Q_RELOCATABLE_TYPE);
+
QQmlRefCount::QQmlRefCount()
: refCount(1)
{
@@ -123,11 +143,22 @@ void QQmlRefCount::addref() const
refCount.ref();
}
-void QQmlRefCount::release() const
+template <typename T>
+void QQmlRefCounted<T>::release() const
{
+ static_assert(std::is_base_of_v<QQmlRefCounted, T>,
+ "QQmlRefCounted<T> must be a base of T (CRTP)");
Q_ASSERT(refCount.loadRelaxed() > 0);
if (!refCount.deref())
- delete this;
+ delete static_cast<const T *>(this);
+}
+
+template <typename T>
+QQmlRefCounted<T>::~QQmlRefCounted()
+{
+ static_assert(std::is_final_v<T> || std::has_virtual_destructor_v<T>,
+ "T must either be marked final or have a virtual dtor, "
+ "lest release() runs into UB.");
}
int QQmlRefCount::count() const
@@ -136,7 +167,7 @@ int QQmlRefCount::count() const
}
template<class T>
-QQmlRefPointer<T>::QQmlRefPointer()
+QQmlRefPointer<T>::QQmlRefPointer() noexcept
: o(nullptr)
{
}
@@ -157,7 +188,7 @@ QQmlRefPointer<T>::QQmlRefPointer(const QQmlRefPointer<T> &other)
}
template <class T>
-QQmlRefPointer<T>::QQmlRefPointer(QQmlRefPointer<T> &&other)
+QQmlRefPointer<T>::QQmlRefPointer(QQmlRefPointer<T> &&other) noexcept
: o(other.take())
{
}
@@ -171,17 +202,21 @@ QQmlRefPointer<T>::~QQmlRefPointer()
template<class T>
QQmlRefPointer<T> &QQmlRefPointer<T>::operator=(const QQmlRefPointer<T> &other)
{
- if (other.o) other.o->addref();
- if (o) o->release();
+ if (o == other.o)
+ return *this;
+ if (other.o)
+ other.o->addref();
+ if (o)
+ o->release();
o = other.o;
return *this;
}
template <class T>
-QQmlRefPointer<T> &QQmlRefPointer<T>::operator=(QQmlRefPointer<T> &&other)
+QQmlRefPointer<T> &QQmlRefPointer<T>::operator=(QQmlRefPointer<T> &&other) noexcept
{
QQmlRefPointer<T> m(std::move(other));
- qSwap(o, m.o);
+ swap(m);
return *this;
}
diff --git a/src/qml/qml/ftw/qqmlthread.cpp b/src/qml/qml/ftw/qqmlthread.cpp
index 0f7726ef65..57f91b6b4d 100644
--- a/src/qml/qml/ftw/qqmlthread.cpp
+++ b/src/qml/qml/ftw/qqmlthread.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qqmlthread_p.h"
@@ -47,6 +11,8 @@
#include <QtCore/qwaitcondition.h>
#include <QtCore/qcoreapplication.h>
+#include <QtCore/private/qthread_p.h>
+
QT_BEGIN_NAMESPACE
class QQmlThreadPrivate : public QThread
@@ -55,19 +21,16 @@ public:
QQmlThreadPrivate(QQmlThread *);
QQmlThread *q;
- void run() override;
-
inline QMutex &mutex() { return _mutex; }
inline void lock() { _mutex.lock(); }
inline void unlock() { _mutex.unlock(); }
inline void wait() { _wait.wait(&_mutex); }
inline void wakeOne() { _wait.wakeOne(); }
- inline void wakeAll() { _wait.wakeAll(); }
- quint32 m_threadProcessing:1; // Set when the thread is processing messages
- quint32 m_mainProcessing:1; // Set when the main thread is processing messages
- quint32 m_shutdown:1; // Set by main thread to request a shutdown
- quint32 m_mainThreadWaiting:1; // Set by main thread if it is waiting for the message queue to empty
+ bool m_threadProcessing; // Set when the thread is processing messages
+ bool m_mainProcessing; // Set when the main thread is processing messages
+ bool m_shutdown; // Set by main thread to request a shutdown
+ bool m_mainThreadWaiting; // Set by main thread if it is waiting for the message queue to empty
typedef QFieldList<QQmlThread::Message, &QQmlThread::Message::next> MessageList;
MessageList threadList;
@@ -143,19 +106,6 @@ bool QQmlThreadPrivate::event(QEvent *e)
return QThread::event(e);
}
-void QQmlThreadPrivate::run()
-{
- lock();
-
- wakeOne();
-
- unlock();
-
- q->startupThread();
- exec();
- q->shutdownThread();
-}
-
void QQmlThreadPrivate::mainEvent()
{
lock();
@@ -228,12 +178,13 @@ QQmlThread::~QQmlThread()
delete d;
}
+/*!
+ \internal
+ Starts the actual worker thread.
+ */
void QQmlThread::startup()
{
- d->lock();
d->start();
- d->wait();
- d->unlock();
d->moveToThread(d);
}
@@ -243,17 +194,6 @@ void QQmlThread::shutdown()
Q_ASSERT(!d->m_shutdown);
d->m_shutdown = true;
- for (;;) {
- if (d->mainSync || !d->mainList.isEmpty()) {
- d->unlock();
- d->mainEvent();
- d->lock();
- } else if (!d->threadList.isEmpty()) {
- d->wait();
- } else {
- break;
- }
- }
if (QCoreApplication::closingDown())
d->quit();
@@ -262,6 +202,10 @@ void QQmlThread::shutdown()
d->unlock();
d->QThread::wait();
+
+ // Discard all remaining messages.
+ // We don't need the lock anymore because the thread is dead.
+ discardMessages();
}
bool QQmlThread::isShutdown() const
@@ -289,11 +233,6 @@ void QQmlThread::wakeOne()
d->wakeOne();
}
-void QQmlThread::wakeAll()
-{
- d->wakeAll();
-}
-
void QQmlThread::wait()
{
d->wait();
@@ -301,7 +240,7 @@ void QQmlThread::wait()
bool QQmlThread::isThisThread() const
{
- return QThread::currentThread() == d;
+ return QThread::currentThreadId() == static_cast<QThreadPrivate *>(QObjectPrivate::get(d))->threadData.loadRelaxed()->threadId.loadRelaxed();
}
QThread *QQmlThread::thread() const
@@ -309,16 +248,6 @@ QThread *QQmlThread::thread() const
return const_cast<QThread *>(static_cast<const QThread *>(d));
}
-// Called when the thread starts. Do startup stuff in here.
-void QQmlThread::startupThread()
-{
-}
-
-// Called when the thread shuts down. Do cleanup in here.
-void QQmlThread::shutdownThread()
-{
-}
-
void QQmlThread::internalCallMethodInThread(Message *message)
{
#if !QT_CONFIG(thread)
@@ -356,6 +285,13 @@ void QQmlThread::internalCallMethodInThread(Message *message)
d->unlock();
}
+/*!
+ \internal
+ \note This method needs to run in the worker/QQmlThread
+
+ This runs \a message in the main thread, and blocks the
+ worker thread until the call has completed
+ */
void QQmlThread::internalCallMethodInMain(Message *message)
{
#if !QT_CONFIG(thread)
@@ -419,12 +355,22 @@ void QQmlThread::internalPostMethodToMain(Message *message)
d->unlock();
}
+/*!
+ \internal
+ \note This method must be called in the main thread
+ \warning This method requires that the lock is held!
+
+ A call to this method will either:
+ - run a message requested to run synchronously on the main thread if there is one
+ (and return afterrwards),
+ - wait for the worker thread to notify it if the worker thread has pending work,
+ - or simply return if neither of the conditions above hold
+ */
void QQmlThread::waitForNextMessage()
{
#if QT_CONFIG(thread)
Q_ASSERT(!isThisThread());
#endif
- d->lock();
Q_ASSERT(d->m_mainThreadWaiting == false);
d->m_mainThreadWaiting = true;
@@ -444,8 +390,24 @@ void QQmlThread::waitForNextMessage()
}
d->m_mainThreadWaiting = false;
- d->unlock();
}
+/*!
+ \internal
+ \note This method must be called in the main thread
+ \warning This method requires that the lock is held!
+
+ Clear all pending events, for either thread.
+*/
+void QQmlThread::discardMessages()
+{
+ Q_ASSERT(!isThisThread());
+ if (Message *mainSync = std::exchange(d->mainSync, nullptr))
+ delete mainSync;
+ while (!d->mainList.isEmpty())
+ delete d->mainList.takeFirst();
+ while (!d->threadList.isEmpty())
+ delete d->threadList.takeFirst();
+}
QT_END_NAMESPACE
diff --git a/src/qml/qml/ftw/qqmlthread_p.h b/src/qml/qml/ftw/qqmlthread_p.h
index b5c580fe8b..35f586f7e7 100644
--- a/src/qml/qml/ftw/qqmlthread_p.h
+++ b/src/qml/qml/ftw/qqmlthread_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLTHREAD_P_H
#define QQMLTHREAD_P_H
@@ -76,51 +40,31 @@ public:
void lock();
void unlock();
void wakeOne();
- void wakeAll();
void wait();
QThread *thread() const;
bool isThisThread() const;
// Synchronously invoke a method in the thread
- template<class O>
- inline void callMethodInThread(void (O::*Member)());
- template<typename T, class V, class O>
- inline void callMethodInThread(void (O::*Member)(V), const T &);
- template<typename T, typename T2, class V, class V2, class O>
- inline void callMethodInThread(void (O::*Member)(V, V2), const T &, const T2 &);
+ template<typename Method, typename ...Args>
+ void callMethodInThread(Method &&method, Args &&...args);
// Synchronously invoke a method in the main thread. If the main thread is
// blocked in a callMethodInThread() call, the call is made from within that
// call.
- template<class O>
- inline void callMethodInMain(void (O::*Member)());
- template<typename T, class V, class O>
- inline void callMethodInMain(void (O::*Member)(V), const T &);
- template<typename T, typename T2, class V, class V2, class O>
- inline void callMethodInMain(void (O::*Member)(V, V2), const T &, const T2 &);
+ template<typename Method, typename ...Args>
+ void callMethodInMain(Method &&method, Args &&...args);
// Asynchronously invoke a method in the thread.
- template<class O>
- inline void postMethodToThread(void (O::*Member)());
- template<typename T, class V, class O>
- inline void postMethodToThread(void (O::*Member)(V), const T &);
- template<typename T, typename T2, class V, class V2, class O>
- inline void postMethodToThread(void (O::*Member)(V, V2), const T &, const T2 &);
+ template<typename Method, typename ...Args>
+ void postMethodToThread(Method &&method, Args &&...args);
// Asynchronously invoke a method in the main thread.
- template<class O>
- inline void postMethodToMain(void (O::*Member)());
- template<typename T, class V, class O>
- inline void postMethodToMain(void (O::*Member)(V), const T &);
- template<typename T, typename T2, class V, class V2, class O>
- inline void postMethodToMain(void (O::*Member)(V, V2), const T &, const T2 &);
+ template<typename Method, typename ...Args>
+ void postMethodToMain(Method &&method, Args &&...args);
void waitForNextMessage();
-
-protected:
- virtual void startupThread();
- virtual void shutdownThread();
+ void discardMessages();
private:
friend class QQmlThreadPrivate;
@@ -131,6 +75,8 @@ private:
Message *next;
virtual void call(QQmlThread *) = 0;
};
+ template<typename Method, typename ...Args>
+ Message *createMessageFromMethod(Method &&method, Args &&...args);
void internalCallMethodInThread(Message *);
void internalCallMethodInMain(Message *);
void internalPostMethodToThread(Message *);
@@ -138,184 +84,58 @@ private:
QQmlThreadPrivate *d;
};
-template<class O>
-void QQmlThread::callMethodInThread(void (O::*Member)())
-{
- struct I : public Message {
- void (O::*Member)();
- I(void (O::*Member)()) : Member(Member) {}
- void call(QQmlThread *thread) override {
- O *me = static_cast<O *>(thread);
- (me->*Member)();
- }
- };
- internalCallMethodInThread(new I(Member));
-}
-
-template<typename T, class V, class O>
-void QQmlThread::callMethodInThread(void (O::*Member)(V), const T &arg)
-{
- struct I : public Message {
- void (O::*Member)(V);
- T arg;
- I(void (O::*Member)(V), const T &arg) : Member(Member), arg(arg) {}
- void call(QQmlThread *thread) override {
- O *me = static_cast<O *>(thread);
- (me->*Member)(arg);
- }
- };
- internalCallMethodInThread(new I(Member, arg));
-}
-
-template<typename T, typename T2, class V, class V2, class O>
-void QQmlThread::callMethodInThread(void (O::*Member)(V, V2), const T &arg, const T2 &arg2)
-{
- struct I : public Message {
- void (O::*Member)(V, V2);
- T arg;
- T2 arg2;
- I(void (O::*Member)(V, V2), const T &arg, const T2 &arg2) : Member(Member), arg(arg), arg2(arg2) {}
- void call(QQmlThread *thread) override {
- O *me = static_cast<O *>(thread);
- (me->*Member)(arg, arg2);
- }
- };
- internalCallMethodInThread(new I(Member, arg, arg2));
-}
-
-template<class O>
-void QQmlThread::callMethodInMain(void (O::*Member)())
-{
- struct I : public Message {
- void (O::*Member)();
- I(void (O::*Member)()) : Member(Member) {}
- void call(QQmlThread *thread) override {
- O *me = static_cast<O *>(thread);
- (me->*Member)();
- }
- };
- internalCallMethodInMain(new I(Member));
-}
+namespace QtPrivate {
+template <typename> struct member_function_traits;
-template<typename T, class V, class O>
-void QQmlThread::callMethodInMain(void (O::*Member)(V), const T &arg)
+template <typename Return, typename Object, typename... Args>
+struct member_function_traits<Return (Object::*)(Args...)>
{
- struct I : public Message {
- void (O::*Member)(V);
- T arg;
- I(void (O::*Member)(V), const T &arg) : Member(Member), arg(arg) {}
- void call(QQmlThread *thread) override {
- O *me = static_cast<O *>(thread);
- (me->*Member)(arg);
- }
- };
- internalCallMethodInMain(new I(Member, arg));
+ using class_type = Object;
+};
}
-template<typename T, typename T2, class V, class V2, class O>
-void QQmlThread::callMethodInMain(void (O::*Member)(V, V2), const T &arg, const T2 &arg2)
+template<typename Method, typename ...Args>
+QQmlThread::Message *QQmlThread::createMessageFromMethod(Method &&method, Args &&...args)
{
struct I : public Message {
- void (O::*Member)(V, V2);
- T arg;
- T2 arg2;
- I(void (O::*Member)(V, V2), const T &arg, const T2 &arg2) : Member(Member), arg(arg), arg2(arg2) {}
+ Method m;
+ std::tuple<std::decay_t<Args>...> arguments;
+ I(Method &&method, Args&& ...args) : m(std::forward<Method>(method)), arguments(std::forward<Args>(args)...) {}
void call(QQmlThread *thread) override {
- O *me = static_cast<O *>(thread);
- (me->*Member)(arg, arg2);
+ using class_type = typename QtPrivate::member_function_traits<Method>::class_type;
+ class_type *me = static_cast<class_type *>(thread);
+ std::apply(m, std::tuple_cat(std::make_tuple(me), arguments));
}
};
- internalCallMethodInMain(new I(Member, arg, arg2));
+ return new I(std::forward<Method>(method), std::forward<Args>(args)...);
}
-template<class O>
-void QQmlThread::postMethodToThread(void (O::*Member)())
+template<typename Method, typename ...Args>
+void QQmlThread::callMethodInMain(Method &&method, Args&& ...args)
{
- struct I : public Message {
- void (O::*Member)();
- I(void (O::*Member)()) : Member(Member) {}
- void call(QQmlThread *thread) override {
- O *me = static_cast<O *>(thread);
- (me->*Member)();
- }
- };
- internalPostMethodToThread(new I(Member));
+ Message *m = createMessageFromMethod(std::forward<Method>(method), std::forward<Args>(args)...);
+ internalCallMethodInMain(m);
}
-template<typename T, class V, class O>
-void QQmlThread::postMethodToThread(void (O::*Member)(V), const T &arg)
+template<typename Method, typename ...Args>
+void QQmlThread::callMethodInThread(Method &&method, Args&& ...args)
{
- struct I : public Message {
- void (O::*Member)(V);
- T arg;
- I(void (O::*Member)(V), const T &arg) : Member(Member), arg(arg) {}
- void call(QQmlThread *thread) override {
- O *me = static_cast<O *>(thread);
- (me->*Member)(arg);
- }
- };
- internalPostMethodToThread(new I(Member, arg));
+ Message *m = createMessageFromMethod(std::forward<Method>(method), std::forward<Args>(args)...);
+ internalCallMethodInThread(m);
}
-template<typename T, typename T2, class V, class V2, class O>
-void QQmlThread::postMethodToThread(void (O::*Member)(V, V2), const T &arg, const T2 &arg2)
+template<typename Method, typename ...Args>
+void QQmlThread::postMethodToThread(Method &&method, Args&& ...args)
{
- struct I : public Message {
- void (O::*Member)(V, V2);
- T arg;
- T2 arg2;
- I(void (O::*Member)(V, V2), const T &arg, const T2 &arg2) : Member(Member), arg(arg), arg2(arg2) {}
- void call(QQmlThread *thread) override {
- O *me = static_cast<O *>(thread);
- (me->*Member)(arg, arg2);
- }
- };
- internalPostMethodToThread(new I(Member, arg, arg2));
+ Message *m = createMessageFromMethod(std::forward<Method>(method), std::forward<Args>(args)...);
+ internalPostMethodToThread(m);
}
-template<class O>
-void QQmlThread::postMethodToMain(void (O::*Member)())
+template<typename Method, typename ...Args>
+void QQmlThread::postMethodToMain(Method &&method, Args&& ...args)
{
- struct I : public Message {
- void (O::*Member)();
- I(void (O::*Member)()) : Member(Member) {}
- void call(QQmlThread *thread) override {
- O *me = static_cast<O *>(thread);
- (me->*Member)();
- }
- };
- internalPostMethodToMain(new I(Member));
-}
-
-template<typename T, class V, class O>
-void QQmlThread::postMethodToMain(void (O::*Member)(V), const T &arg)
-{
- struct I : public Message {
- void (O::*Member)(V);
- T arg;
- I(void (O::*Member)(V), const T &arg) : Member(Member), arg(arg) {}
- void call(QQmlThread *thread) override {
- O *me = static_cast<O *>(thread);
- (me->*Member)(arg);
- }
- };
- internalPostMethodToMain(new I(Member, arg));
-}
-
-template<typename T, typename T2, class V, class V2, class O>
-void QQmlThread::postMethodToMain(void (O::*Member)(V, V2), const T &arg, const T2 &arg2)
-{
- struct I : public Message {
- void (O::*Member)(V, V2);
- T arg;
- T2 arg2;
- I(void (O::*Member)(V, V2), const T &arg, const T2 &arg2) : Member(Member), arg(arg), arg2(arg2) {}
- void call(QQmlThread *thread) override {
- O *me = static_cast<O *>(thread);
- (me->*Member)(arg, arg2);
- }
- };
- internalPostMethodToMain(new I(Member, arg, arg2));
+ Message *m = createMessageFromMethod(std::forward<Method>(method), std::forward<Args>(args)...);
+ internalPostMethodToMain(m);
}
QT_END_NAMESPACE
diff --git a/src/qml/qml/ftw/qrecursionwatcher_p.h b/src/qml/qml/ftw/qrecursionwatcher_p.h
index 56b714f922..668695877e 100644
--- a/src/qml/qml/ftw/qrecursionwatcher_p.h
+++ b/src/qml/qml/ftw/qrecursionwatcher_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QRECURSIONWATCHER_P_H
#define QRECURSIONWATCHER_P_H
@@ -51,7 +15,7 @@
// We mean it.
//
-#include <QtCore/qglobal.h>
+#include <QtCore/private/qglobal_p.h>
QT_BEGIN_NAMESPACE
diff --git a/src/qml/qml/ftw/qrecyclepool_p.h b/src/qml/qml/ftw/qrecyclepool_p.h
index 39f4f88512..6661c88631 100644
--- a/src/qml/qml/ftw/qrecyclepool_p.h
+++ b/src/qml/qml/ftw/qrecyclepool_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QRECYCLEPOOL_P_H
#define QRECYCLEPOOL_P_H
@@ -51,6 +15,10 @@
// We mean it.
//
+#include <QtCore/private/qglobal_p.h>
+
+#include <QtCore/q20memory.h>
+
QT_BEGIN_NAMESPACE
#define QRECYCLEPOOLCOOKIE 0x33218ADF
@@ -101,11 +69,8 @@ public:
inline QRecyclePool();
inline ~QRecyclePool();
- inline T *New();
- template<typename T1>
- inline T *New(const T1 &);
- template<typename T1>
- inline T *New(T1 &);
+ template<typename...Args>
+ [[nodiscard]] inline T *New(Args&&...args);
static inline void Delete(T *);
@@ -127,29 +92,10 @@ QRecyclePool<T, Step>::~QRecyclePool()
}
template<typename T, int Step>
-T *QRecyclePool<T, Step>::New()
-{
- T *rv = d->allocate();
- new (rv) T;
- return rv;
-}
-
-template<typename T, int Step>
-template<typename T1>
-T *QRecyclePool<T, Step>::New(const T1 &a)
+template<typename...Args>
+T *QRecyclePool<T, Step>::New(Args&&...args)
{
- T *rv = d->allocate();
- new (rv) T(a);
- return rv;
-}
-
-template<typename T, int Step>
-template<typename T1>
-T *QRecyclePool<T, Step>::New(T1 &a)
-{
- T *rv = d->allocate();
- new (rv) T(a);
- return rv;
+ return q20::construct_at(d->allocate(), std::forward<Args>(args)...);
}
template<typename T, int Step>
diff --git a/src/qml/qml/ftw/qstringhash_p.h b/src/qml/qml/ftw/qstringhash_p.h
index 25d66f81d1..c431a4d6b3 100644
--- a/src/qml/qml/ftw/qstringhash_p.h
+++ b/src/qml/qml/ftw/qstringhash_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2020 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$
-**
-****************************************************************************/
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QSTRINGHASH_P_H
#define QSTRINGHASH_P_H
@@ -74,10 +38,11 @@ public:
}
QStringHashNode(const QHashedString &key)
- : length(key.length()), hash(key.hash()), symbolId(0)
+ : length(int(key.size())), hash(key.hash()), symbolId(0)
, arrayData(mutableStringData(key).d_ptr())
, strData(mutableStringData(key).data())
{
+ Q_ASSERT(key.size() <= std::numeric_limits<int>::max());
if (arrayData)
arrayData->ref();
setQString(true);
@@ -268,13 +233,21 @@ class QStringHashBase
{
public:
static HashedForm<QString>::Type hashedString(const QString &s) { return QHashedString(s);}
- static HashedForm<QStringView>::Type hashedString(QStringView s) { return QHashedStringRef(s.constData(), s.size());}
+ static HashedForm<QStringView>::Type hashedString(QStringView s)
+ {
+ Q_ASSERT(s.size() <= std::numeric_limits<int>::max());
+ return QHashedStringRef(s.constData(), int(s.size()));
+ }
static HashedForm<QHashedString>::Type hashedString(const QHashedString &s) { return s; }
static HashedForm<QV4::String *>::Type hashedString(QV4::String *s) { return s; }
static HashedForm<const QV4::String *>::Type hashedString(const QV4::String *s) { return s; }
static HashedForm<QHashedStringRef>::Type hashedString(const QHashedStringRef &s) { return s; }
- static HashedForm<QLatin1String>::Type hashedString(const QLatin1String &s) { return QHashedCStringRef(s.data(), s.size()); }
+ static HashedForm<QLatin1StringView>::Type hashedString(QLatin1StringView s)
+ {
+ Q_ASSERT(s.size() <= std::numeric_limits<int>::max());
+ return QHashedCStringRef(s.data(), int(s.size()));
+ }
static HashedForm<QHashedCStringRef>::Type hashedString(const QHashedCStringRef &s) { return s; }
static const QString &toQString(const QString &s) { return s; }
@@ -527,7 +500,7 @@ int QStringHash<T>::numBuckets() const
template<class T>
void QStringHash<T>::initializeNode(Node *node, const QHashedString &key)
{
- node->length = key.length();
+ node->length = key.size();
node->hash = key.hash();
node->arrayData = mutableStringData(key).d_ptr();
node->strData = mutableStringData(key).data();
diff --git a/src/qml/qml/qqml.cpp b/src/qml/qml/qqml.cpp
index cb55c0d834..eb716671b1 100644
--- a/src/qml/qml/qqml.cpp
+++ b/src/qml/qml/qqml.cpp
@@ -1,78 +1,75 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 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$
-**
-****************************************************************************/
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qqml.h"
#include <QtQml/qqmlprivate.h>
#include <private/qjsvalue_p.h>
+#include <private/qqmlbuiltinfunctions_p.h>
+#include <private/qqmlcomponent_p.h>
#include <private/qqmlengine_p.h>
+#include <private/qqmlfinalizer_p.h>
+#include <private/qqmlloggingcategory_p.h>
#include <private/qqmlmetatype_p.h>
#include <private/qqmlmetatypedata_p.h>
#include <private/qqmltype_p_p.h>
#include <private/qqmltypemodule_p.h>
-#include <private/qqmltypenotavailable_p.h>
-#include <private/qqmlcomponent_p.h>
+#include <private/qqmltypewrapper_p.h>
+#include <private/qqmlvaluetypewrapper_p.h>
+#include <private/qv4dateobject_p.h>
+#include <private/qv4errorobject_p.h>
+#include <private/qv4identifiertable_p.h>
+#include <private/qv4lookup_p.h>
+#include <private/qv4qobjectwrapper_p.h>
#include <QtCore/qmutex.h>
QT_BEGIN_NAMESPACE
+Q_DECLARE_LOGGING_CATEGORY(lcQml);
+Q_DECLARE_LOGGING_CATEGORY(lcJs);
/*!
\internal
+
+ This method completes the setup of all deferred properties of \a object.
+ Deferred properties are declared with
+ Q_CLASSINFO("DeferredPropertyNames", "comma,separated,property,list");
+
+ Any binding to a deferred property is not executed when the object is instantiated,
+ but only when completion is requested with qmlExecuteDeferred, or by manually
+ calling QQmlComponentPrivate::beginDeferred and completeDeferred.
+
+ \sa QV4::CompiledData::Binding::IsDeferredBinding,
+ QV4::CompiledData::Object::HasDeferredBindings,
+ QQmlData::deferData,
+ QQmlObjectCreator::setupBindings
*/
void qmlExecuteDeferred(QObject *object)
{
QQmlData *data = QQmlData::get(object);
- if (data && !data->deferredData.isEmpty() && !data->wasDeleted(object)) {
- QQmlEnginePrivate *ep = QQmlEnginePrivate::get(data->context->engine());
+ if (!data
+ || !data->context
+ || !data->context->engine()
+ || data->deferredData.isEmpty()
+ || data->wasDeleted(object)) {
+ return;
+ }
- QQmlComponentPrivate::DeferredState state;
- QQmlComponentPrivate::beginDeferred(ep, object, &state);
+ if (!data->propertyCache)
+ data->propertyCache = QQmlMetaType::propertyCache(object->metaObject());
- // Release the reference for the deferral action (we still have one from construction)
- data->releaseDeferredData();
+ QQmlEnginePrivate *ep = QQmlEnginePrivate::get(data->context->engine());
- QQmlComponentPrivate::completeDeferred(ep, &state);
- }
+ QQmlComponentPrivate::DeferredState state;
+ QQmlComponentPrivate::beginDeferred(ep, object, &state);
+
+ // Release the reference for the deferral action (we still have one from construction)
+ data->releaseDeferredData();
+
+ QQmlComponentPrivate::completeDeferred(ep, &state);
}
QQmlContext *qmlContext(const QObject *obj)
@@ -82,7 +79,7 @@ QQmlContext *qmlContext(const QObject *obj)
QQmlEngine *qmlEngine(const QObject *obj)
{
- QQmlData *data = QQmlData::get(obj, false);
+ QQmlData *data = QQmlData::get(obj);
if (!data || !data->context)
return nullptr;
return data->context->engine();
@@ -129,13 +126,79 @@ QObject *qmlAttachedPropertiesObject(QObject *object, QQmlAttachedPropertiesFunc
return resolveAttachedProperties(func, data, object, create);
}
+QObject *qmlExtendedObject(QObject *object)
+{
+ return QQmlPrivate::qmlExtendedObject(object, 0);
+}
+
+QObject *QQmlPrivate::qmlExtendedObject(QObject *object, int index)
+{
+ if (!object)
+ return nullptr;
+
+ void *result = nullptr;
+ QObjectPrivate *d = QObjectPrivate::get(object);
+ if (!d->metaObject)
+ return nullptr;
+
+ const int id = d->metaObject->metaCall(
+ object, QMetaObject::CustomCall,
+ QQmlProxyMetaObject::extensionObjectId(index), &result);
+ if (id != QQmlProxyMetaObject::extensionObjectId(index))
+ return nullptr;
+
+ return static_cast<QObject *>(result);
+}
+
+void QQmlPrivate::qmlRegistrationWarning(
+ QQmlPrivate::QmlRegistrationWarning warning, QMetaType metaType)
+{
+ switch (warning) {
+ case UnconstructibleType:
+ qWarning().nospace()
+ << metaType.name()
+ << " is neither a default constructible QObject, nor a default- "
+ << "and copy-constructible Q_GADGET, nor marked as uncreatable.\n"
+ << "You should not use it as a QML type.";
+ break;
+ case UnconstructibleSingleton:
+ qWarning()
+ << "Singleton" << metaType.name()
+ << "needs to be a concrete class with either a default constructor"
+ << "or, when adding a default constructor is infeasible, a public static"
+ << "create(QQmlEngine *, QJSEngine *) method.";
+ break;
+ case NonQObjectWithAtached:
+ qWarning()
+ << metaType.name()
+ << "is not a QObject, but has attached properties. This won't work.";
+ break;
+ }
+}
+
+QMetaType QQmlPrivate::compositeMetaType(
+ QV4::ExecutableCompilationUnit *unit, const QString &elementName)
+{
+ return QQmlTypePrivate::compositeQmlType(
+ unit->baseCompilationUnit(), unit->engine->typeLoader(), elementName)
+ .typeId();
+}
+
+QMetaType QQmlPrivate::compositeListMetaType(
+ QV4::ExecutableCompilationUnit *unit, const QString &elementName)
+{
+ return QQmlTypePrivate::compositeQmlType(
+ unit->baseCompilationUnit(), unit->engine->typeLoader(), elementName)
+ .qListTypeId();
+}
+
int qmlRegisterUncreatableMetaObject(const QMetaObject &staticMetaObject,
const char *uri, int versionMajor,
int versionMinor, const char *qmlName,
const QString& reason)
{
QQmlPrivate::RegisterType type = {
- 0,
+ QQmlPrivate::RegisterType::CurrentVersion,
QMetaType(),
QMetaType(),
0,
@@ -149,14 +212,16 @@ int qmlRegisterUncreatableMetaObject(const QMetaObject &staticMetaObject,
QQmlAttachedPropertiesFunc(),
nullptr,
- 0,
- 0,
- 0,
+ -1,
+ -1,
+ -1,
nullptr, nullptr,
nullptr,
- QTypeRevision::zero()
+ QTypeRevision::zero(),
+ -1,
+ QQmlPrivate::ValueTypeCreationMethod::None
};
return QQmlPrivate::qmlregister(QQmlPrivate::TypeRegistration, &type);
@@ -202,6 +267,7 @@ static QTypeRevision resolveModuleVersion(int moduleMajor)
/*!
* \enum QQmlModuleImportSpecialVersions
+ * \relates QQmlEngine
*
* Defines some special values that can be passed to the version arguments of
* qmlRegisterModuleImport() and qmlUnregisterModuleImport().
@@ -220,25 +286,26 @@ static QTypeRevision resolveModuleVersion(int moduleMajor)
*/
/*!
- * Registers an implicit import for module \a uri of major version \a majorVersion.
+ * \relates QQmlEngine
+ * Registers a qmldir-import for module \a uri of major version \a moduleMajor.
*
* This has the same effect as an \c import statement in a qmldir file: Whenever
* \a uri of version \a moduleMajor is imported, \a import of version
* \a importMajor. \a importMinor is automatically imported, too. If
- * \a importMajor is \l QmlModuleImportLatest the latest version
+ * \a importMajor is \l QQmlModuleImportLatest the latest version
* available of that module is imported, and \a importMinor does not matter. If
- * \a importMinor is \l QmlModuleImportLatest the latest minor version of a
- * \a importMajor is chosen. If \a importMajor is \l QmlModuleImportAuto the
+ * \a importMinor is \l QQmlModuleImportLatest the latest minor version of a
+ * \a importMajor is chosen. If \a importMajor is \l QQmlModuleImportAuto the
* version of \a import is version of \a uri being imported, and \a importMinor
- * does not matter. If \a moduleMajor is \a QmlModuleImportModuleAny the module
+ * does not matter. If \a moduleMajor is \l QQmlModuleImportModuleAny the module
* import is applied for any major version of \a uri. For example, you may
* specify that whenever any version of MyModule is imported, the latest version
* of MyOtherModule should be imported. Then, the following call would be
* appropriate:
*
* \code
- * qmlRegisterModuleImport("MyModule", QmlModuleImportModuleAny,
- * "MyOtherModule", QmlModuleImportLatest);
+ * qmlRegisterModuleImport("MyModule", QQmlModuleImportModuleAny,
+ * "MyOtherModule", QQmlModuleImportLatest);
* \endcode
*
* Or, you may specify that whenever major version 5 of "MyModule" is imported,
@@ -252,8 +319,8 @@ static QTypeRevision resolveModuleVersion(int moduleMajor)
* imported whenever "MyModule" is imported, specify the following:
*
* \code
- * qmlRegisterModuleImport("MyModule", QmlModuleImportModuleAny,
- * "MyOtherModule", QmlModuleImportAuto);
+ * qmlRegisterModuleImport("MyModule", QQmlModuleImportModuleAny,
+ * "MyOtherModule", QQmlModuleImportAuto);
* \endcode
*
* \sa qmlUnregisterModuleImport()
@@ -268,6 +335,7 @@ void qmlRegisterModuleImport(const char *uri, int moduleMajor,
/*!
+ * \relates QQmlEngine
* Removes a module import previously registered with qmlRegisterModuleImport()
*
* Calling this function makes sure that \a import of version
@@ -291,30 +359,63 @@ int qmlTypeId(const char *uri, int versionMajor, int versionMinor, const char *q
return QQmlMetaType::typeId(uri, QTypeRevision::fromVersion(versionMajor, versionMinor), qmlName);
}
+static bool checkSingletonInstance(QQmlEngine *engine, QObject *instance)
+{
+ if (!instance) {
+ QQmlError error;
+ error.setDescription(QStringLiteral("The registered singleton has already been deleted. "
+ "Ensure that it outlives the engine."));
+ QQmlEnginePrivate::get(engine)->warning(engine, error);
+ return false;
+ }
+
+ if (engine->thread() != instance->thread()) {
+ QQmlError error;
+ error.setDescription(QStringLiteral("Registered object must live in the same thread "
+ "as the engine it was registered with"));
+ QQmlEnginePrivate::get(engine)->warning(engine, error);
+ return false;
+ }
+
+ return true;
+}
+
// From qqmlprivate.h
+#if QT_DEPRECATED_SINCE(6, 3)
QObject *QQmlPrivate::SingletonFunctor::operator()(QQmlEngine *qeng, QJSEngine *)
{
- if (!m_object) {
- QQmlError error;
- error.setDescription(QLatin1String("The registered singleton has already been deleted. Ensure that it outlives the engine."));
- QQmlEnginePrivate::get(qeng)->warning(qeng, error);
+ if (!checkSingletonInstance(qeng, m_object))
return nullptr;
- }
- if (qeng->thread() != m_object->thread()) {
+ if (alreadyCalled) {
QQmlError error;
- error.setDescription(QLatin1String("Registered object must live in the same thread as the engine it was registered with"));
+ error.setDescription(QStringLiteral("Singleton registered by registerSingletonInstance "
+ "must only be accessed from one engine"));
QQmlEnginePrivate::get(qeng)->warning(qeng, error);
return nullptr;
}
- if (alreadyCalled) {
+
+ alreadyCalled = true;
+ QJSEngine::setObjectOwnership(m_object, QQmlEngine::CppOwnership);
+ return m_object;
+};
+#endif
+
+QObject *QQmlPrivate::SingletonInstanceFunctor::operator()(QQmlEngine *qeng, QJSEngine *)
+{
+ if (!checkSingletonInstance(qeng, m_object))
+ return nullptr;
+
+ if (!m_engine) {
+ m_engine = qeng;
+ QJSEngine::setObjectOwnership(m_object, QQmlEngine::CppOwnership);
+ } else if (m_engine != qeng) {
QQmlError error;
error.setDescription(QLatin1String("Singleton registered by registerSingletonInstance must only be accessed from one engine"));
QQmlEnginePrivate::get(qeng)->warning(qeng, error);
return nullptr;
}
- alreadyCalled = true;
- qeng->setObjectOwnership(m_object, QQmlEngine::CppOwnership);
+
return m_object;
};
@@ -325,9 +426,9 @@ static QVector<QTypeRevision> availableRevisions(const QMetaObject *metaObject)
return revisions;
const int propertyOffset = metaObject->propertyOffset();
const int propertyCount = metaObject->propertyCount();
- for (int propertyIndex = propertyOffset, propertyEnd = propertyOffset + propertyCount;
- propertyIndex < propertyEnd; ++propertyIndex) {
- const QMetaProperty property = metaObject->property(propertyIndex);
+ for (int coreIndex = propertyOffset, propertyEnd = propertyOffset + propertyCount;
+ coreIndex < propertyEnd; ++coreIndex) {
+ const QMetaProperty property = metaObject->property(coreIndex);
if (int revision = property.revision())
revisions.append(QTypeRevision::fromEncodedVersion(revision));
}
@@ -395,13 +496,280 @@ static void uniqueRevisions(QVector<QTypeRevision> *revisions, QTypeRevision def
revisions->erase(it, revisions->end());
}
+static QQmlType::SingletonInstanceInfo::ConstPtr singletonInstanceInfo(
+ const QQmlPrivate::RegisterSingletonType &type)
+{
+ QQmlType::SingletonInstanceInfo::Ptr siinfo = QQmlType::SingletonInstanceInfo::create();
+ siinfo->scriptCallback = type.scriptApi;
+ siinfo->qobjectCallback = type.qObjectApi;
+ siinfo->typeName = type.typeName;
+ return QQmlType::SingletonInstanceInfo::ConstPtr(
+ siinfo.take(), QQmlType::SingletonInstanceInfo::ConstPtr::Adopt);
+}
+
+static QQmlType::SingletonInstanceInfo::ConstPtr singletonInstanceInfo(
+ const QQmlPrivate::RegisterCompositeSingletonType &type)
+{
+ QQmlType::SingletonInstanceInfo::Ptr siinfo = QQmlType::SingletonInstanceInfo::create();
+ siinfo->url = QQmlTypeLoader::normalize(type.url);
+ siinfo->typeName = type.typeName;
+ return QQmlType::SingletonInstanceInfo::ConstPtr(
+ siinfo.take(), QQmlType::SingletonInstanceInfo::ConstPtr::Adopt);
+}
+
+static int finalizeType(const QQmlType &dtype)
+{
+ if (!dtype.isValid())
+ return -1;
+
+ QQmlMetaType::registerUndeletableType(dtype);
+ return dtype.index();
+}
+
+using ElementNames = QVarLengthArray<const char *, 8>;
+static ElementNames classElementNames(const QMetaObject *metaObject)
+{
+ Q_ASSERT(metaObject);
+ const char *key = "QML.Element";
+
+ const int offset = metaObject->classInfoOffset();
+ const int start = metaObject->classInfoCount() + offset - 1;
+
+ ElementNames elementNames;
+
+ for (int i = start; i >= offset; --i) {
+ const QMetaClassInfo classInfo = metaObject->classInfo(i);
+ if (qstrcmp(key, classInfo.name()) == 0) {
+ const char *elementName = classInfo.value();
+
+ if (qstrcmp(elementName, "auto") == 0) {
+ const char *strippedClassName = metaObject->className();
+ for (const char *c = strippedClassName; *c != '\0'; c++) {
+ if (*c == ':')
+ strippedClassName = c + 1;
+ }
+ elementName = strippedClassName;
+ } else if (qstrcmp(elementName, "anonymous") == 0) {
+ if (elementNames.isEmpty())
+ elementNames.push_back(nullptr);
+ else if (elementNames[0] != nullptr)
+ qWarning() << metaObject->className() << "is both anonymous and named";
+ continue;
+ }
+
+ if (!elementNames.isEmpty() && elementNames[0] == nullptr) {
+ qWarning() << metaObject->className() << "is both anonymous and named";
+ elementNames[0] = elementName;
+ } else {
+ elementNames.push_back(elementName);
+ }
+ }
+ }
+
+ return elementNames;
+}
+
+struct AliasRegistrar
+{
+ AliasRegistrar(const ElementNames *elementNames) : elementNames(elementNames) {}
+
+ void registerAliases(int typeId)
+ {
+ if (elementNames) {
+ for (int i = 1, end = elementNames->length(); i < end; ++i)
+ otherNames.append(QString::fromUtf8(elementNames->at(i)));
+ elementNames = nullptr;
+ }
+
+ for (const QString &otherName : std::as_const(otherNames))
+ QQmlMetaType::registerTypeAlias(typeId, otherName);
+ }
+
+private:
+ const ElementNames *elementNames;
+ QVarLengthArray<QString, 8> otherNames;
+};
+
+
+static void doRegisterTypeAndRevisions(
+ const QQmlPrivate::RegisterTypeAndRevisions &type,
+ const ElementNames &elementNames)
+{
+ using namespace QQmlPrivate;
+
+ const bool isValueType = !(type.typeId.flags() & QMetaType::PointerToQObject);
+ const bool creatable = (elementNames[0] != nullptr || isValueType)
+ && boolClassInfo(type.classInfoMetaObject, "QML.Creatable", true);
+
+ QString noCreateReason;
+ ValueTypeCreationMethod creationMethod = ValueTypeCreationMethod::None;
+
+ if (!creatable) {
+ noCreateReason = QString::fromUtf8(
+ classInfo(type.classInfoMetaObject, "QML.UncreatableReason"));
+ if (noCreateReason.isEmpty())
+ noCreateReason = QLatin1String("Type cannot be created in QML.");
+ } else if (isValueType) {
+ const char *method = classInfo(type.classInfoMetaObject, "QML.CreationMethod");
+ if (qstrcmp(method, "structured") == 0)
+ creationMethod = ValueTypeCreationMethod::Structured;
+ else if (qstrcmp(method, "construct") == 0)
+ creationMethod = ValueTypeCreationMethod::Construct;
+ }
+
+ RegisterType typeRevision = {
+ QQmlPrivate::RegisterType::CurrentVersion,
+ type.typeId,
+ type.listId,
+ creatable ? type.objectSize : 0,
+ nullptr,
+ nullptr,
+ noCreateReason,
+ type.createValueType,
+ type.uri,
+ type.version,
+ nullptr,
+ type.metaObject,
+ type.attachedPropertiesFunction,
+ type.attachedPropertiesMetaObject,
+ type.parserStatusCast,
+ type.valueSourceCast,
+ type.valueInterceptorCast,
+ type.extensionObjectCreate,
+ type.extensionMetaObject,
+ nullptr,
+ QTypeRevision(),
+ type.structVersion > 0 ? type.finalizerCast : -1,
+ creationMethod
+ };
+
+ QQmlPrivate::RegisterSequentialContainer sequenceRevision = {
+ 0,
+ type.uri,
+ type.version,
+ nullptr,
+ type.listId,
+ type.structVersion > 1 ? type.listMetaSequence : QMetaSequence(),
+ QTypeRevision(),
+ };
+
+ const QTypeRevision added = revisionClassInfo(
+ type.classInfoMetaObject, "QML.AddedInVersion",
+ QTypeRevision::fromVersion(type.version.majorVersion(), 0));
+ const QTypeRevision removed = revisionClassInfo(
+ type.classInfoMetaObject, "QML.RemovedInVersion");
+ const QList<QTypeRevision> furtherRevisions = revisionClassInfos(type.classInfoMetaObject,
+ "QML.ExtraVersion");
+
+ auto revisions = prepareRevisions(type.metaObject, added) + furtherRevisions;
+ if (type.attachedPropertiesMetaObject)
+ revisions += availableRevisions(type.attachedPropertiesMetaObject);
+ uniqueRevisions(&revisions, type.version, added);
+
+ AliasRegistrar aliasRegistrar(&elementNames);
+ for (QTypeRevision revision : revisions) {
+ if (revision.hasMajorVersion() && revision.majorVersion() > type.version.majorVersion())
+ break;
+
+ assignVersions(&typeRevision, revision, type.version);
+
+ // When removed or before added, we still add revisions, but anonymous ones
+ if (typeRevision.version < added
+ || (removed.isValid() && !(typeRevision.version < removed))) {
+ typeRevision.elementName = nullptr;
+ typeRevision.create = nullptr;
+ typeRevision.userdata = nullptr;
+ } else {
+ typeRevision.elementName = elementNames[0];
+ typeRevision.create = creatable ? type.create : nullptr;
+ typeRevision.userdata = type.userdata;
+ }
+
+ typeRevision.customParser = type.customParserFactory();
+ const int id = qmlregister(TypeRegistration, &typeRevision);
+ if (type.qmlTypeIds)
+ type.qmlTypeIds->append(id);
+
+ if (typeRevision.elementName)
+ aliasRegistrar.registerAliases(id);
+
+ if (sequenceRevision.metaSequence != QMetaSequence()) {
+ sequenceRevision.version = typeRevision.version;
+ sequenceRevision.revision = typeRevision.revision;
+ const int id = QQmlPrivate::qmlregister(
+ QQmlPrivate::SequentialContainerRegistration, &sequenceRevision);
+ if (type.qmlTypeIds)
+ type.qmlTypeIds->append(id);
+ }
+ }
+}
+
+static void doRegisterSingletonAndRevisions(
+ const QQmlPrivate::RegisterSingletonTypeAndRevisions &type,
+ const ElementNames &elementNames)
+{
+ using namespace QQmlPrivate;
+
+ RegisterSingletonType revisionRegistration = {
+ 0,
+ type.uri,
+ type.version,
+ elementNames[0],
+ nullptr,
+ type.qObjectApi,
+ type.instanceMetaObject,
+ type.typeId,
+ type.extensionObjectCreate,
+ type.extensionMetaObject,
+ QTypeRevision()
+ };
+ const QQmlType::SingletonInstanceInfo::ConstPtr siinfo
+ = singletonInstanceInfo(revisionRegistration);
+
+ const QTypeRevision added = revisionClassInfo(
+ type.classInfoMetaObject, "QML.AddedInVersion",
+ QTypeRevision::fromVersion(type.version.majorVersion(), 0));
+ const QTypeRevision removed = revisionClassInfo(
+ type.classInfoMetaObject, "QML.RemovedInVersion");
+ const QList<QTypeRevision> furtherRevisions = revisionClassInfos(type.classInfoMetaObject,
+ "QML.ExtraVersion");
+
+ auto revisions = prepareRevisions(type.instanceMetaObject, added) + furtherRevisions;
+ uniqueRevisions(&revisions, type.version, added);
+
+ AliasRegistrar aliasRegistrar(&elementNames);
+ for (QTypeRevision revision : std::as_const(revisions)) {
+ if (revision.hasMajorVersion() && revision.majorVersion() > type.version.majorVersion())
+ break;
+
+ assignVersions(&revisionRegistration, revision, type.version);
+
+ // When removed or before added, we still add revisions, but anonymous ones
+ if (revisionRegistration.version < added
+ || (removed.isValid() && !(revisionRegistration.version < removed))) {
+ revisionRegistration.typeName = nullptr;
+ revisionRegistration.qObjectApi = nullptr;
+ } else {
+ revisionRegistration.typeName = elementNames[0];
+ revisionRegistration.qObjectApi = type.qObjectApi;
+ }
+
+ const int id = finalizeType(
+ QQmlMetaType::registerSingletonType(revisionRegistration, siinfo));
+ if (type.qmlTypeIds)
+ type.qmlTypeIds->append(id);
+
+ if (revisionRegistration.typeName)
+ aliasRegistrar.registerAliases(id);
+ }
+}
+
/*
This method is "over generalized" to allow us to (potentially) register more types of things in
the future without adding exported symbols.
*/
int QQmlPrivate::qmlregister(RegistrationType type, void *data)
{
- QQmlType dtype;
switch (type) {
case AutoParentRegistration:
return QQmlMetaType::registerAutoParentFunction(
@@ -411,135 +779,40 @@ int QQmlPrivate::qmlregister(RegistrationType type, void *data)
*reinterpret_cast<RegisterQmlUnitCacheHook *>(data));
case TypeAndRevisionsRegistration: {
const RegisterTypeAndRevisions &type = *reinterpret_cast<RegisterTypeAndRevisions *>(data);
- const char *elementName = classElementName(type.classInfoMetaObject);
- const bool creatable = (elementName != nullptr)
- && boolClassInfo(type.classInfoMetaObject, "QML.Creatable", true);
-
- QString noCreateReason;
-
- if (!creatable) {
- noCreateReason = QString::fromUtf8(classInfo(type.classInfoMetaObject, "QML.UncreatableReason"));
- if (noCreateReason.isEmpty())
- noCreateReason = QLatin1String("Type cannot be created in QML.");
- }
-
- RegisterType revisionRegistration = {
- 0,
- type.typeId,
- type.listId,
- creatable ? type.objectSize : 0,
- nullptr,
- nullptr,
- noCreateReason,
- type.createValueType,
- type.uri,
- type.version,
- nullptr,
- type.metaObject,
- type.attachedPropertiesFunction,
- type.attachedPropertiesMetaObject,
- type.parserStatusCast,
- type.valueSourceCast,
- type.valueInterceptorCast,
- type.extensionObjectCreate,
- type.extensionMetaObject,
- nullptr,
- QTypeRevision()
- };
-
- const QTypeRevision added = revisionClassInfo(
- type.classInfoMetaObject, "QML.AddedInVersion",
- QTypeRevision::fromMinorVersion(0));
- const QTypeRevision removed = revisionClassInfo(
- type.classInfoMetaObject, "QML.RemovedInVersion");
-
- auto revisions = prepareRevisions(type.metaObject, added);
- if (type.attachedPropertiesMetaObject)
- revisions += availableRevisions(type.attachedPropertiesMetaObject);
- uniqueRevisions(&revisions, type.version, added);
-
- for (QTypeRevision revision : revisions) {
- if (revision < added)
- continue;
- if (revision.hasMajorVersion() && revision.majorVersion() > type.version.majorVersion())
- break;
-
- // When removed, we still add revisions, but anonymous ones
- if (removed.isValid() && !(revision < removed)) {
- revisionRegistration.elementName = nullptr;
- revisionRegistration.create = nullptr;
+ if (type.structVersion > 1 && type.forceAnonymous) {
+ doRegisterTypeAndRevisions(type, {nullptr});
+ } else {
+ const ElementNames names = classElementNames(type.classInfoMetaObject);
+ if (names.isEmpty()) {
+ qWarning().nospace() << "Missing QML.Element class info for "
+ << type.classInfoMetaObject->className();
} else {
- revisionRegistration.elementName = elementName;
- revisionRegistration.create = creatable ? type.create : nullptr;
- revisionRegistration.userdata = type.userdata;
+ doRegisterTypeAndRevisions(type, names);
}
- assignVersions(&revisionRegistration, revision, type.version);
- revisionRegistration.customParser = type.customParserFactory();
- const int id = qmlregister(TypeRegistration, &revisionRegistration);
- if (type.qmlTypeIds)
- type.qmlTypeIds->append(id);
}
break;
}
case SingletonAndRevisionsRegistration: {
const RegisterSingletonTypeAndRevisions &type
= *reinterpret_cast<RegisterSingletonTypeAndRevisions *>(data);
- const char *elementName = classElementName(type.classInfoMetaObject);
- RegisterSingletonType revisionRegistration = {
- 0,
- type.uri,
- type.version,
- elementName,
- nullptr,
- type.qObjectApi,
- type.instanceMetaObject,
- type.typeId,
- type.extensionObjectCreate,
- type.extensionMetaObject,
- QTypeRevision()
- };
-
- const QTypeRevision added = revisionClassInfo(
- type.classInfoMetaObject, "QML.AddedInVersion",
- QTypeRevision::fromMinorVersion(0));
- const QTypeRevision removed = revisionClassInfo(
- type.classInfoMetaObject, "QML.RemovedInVersion");
-
- auto revisions = prepareRevisions(type.instanceMetaObject, added);
- uniqueRevisions(&revisions, type.version, added);
-
- for (QTypeRevision revision : qAsConst(revisions)) {
- if (revision < added)
- continue;
- if (revision.hasMajorVersion() && revision.majorVersion() > type.version.majorVersion())
- break;
-
- // When removed, we still add revisions, but anonymous ones
- if (removed.isValid() && !(revision < removed)) {
- revisionRegistration.typeName = nullptr;
- revisionRegistration.qObjectApi = nullptr;
- } else {
- revisionRegistration.typeName = elementName;
- revisionRegistration.qObjectApi = type.qObjectApi;
- }
-
- assignVersions(&revisionRegistration, revision, type.version);
- const int id = qmlregister(SingletonRegistration, &revisionRegistration);
- if (type.qmlTypeIds)
- type.qmlTypeIds->append(id);
+ const ElementNames names = classElementNames(type.classInfoMetaObject);
+ if (names.isEmpty()) {
+ qWarning().nospace() << "Missing QML.Element class info for "
+ << type.classInfoMetaObject->className();
+ } else {
+ doRegisterSingletonAndRevisions(type, names);
}
break;
}
case SequentialContainerAndRevisionsRegistration: {
const RegisterSequentialContainerAndRevisions &type
= *reinterpret_cast<RegisterSequentialContainerAndRevisions *>(data);
- const char *elementName = classElementName(type.classInfoMetaObject);
RegisterSequentialContainer revisionRegistration = {
0,
type.uri,
type.version,
- elementName,
+ nullptr,
type.typeId,
type.metaSequence,
QTypeRevision()
@@ -548,24 +821,17 @@ int QQmlPrivate::qmlregister(RegistrationType type, void *data)
const QTypeRevision added = revisionClassInfo(
type.classInfoMetaObject, "QML.AddedInVersion",
QTypeRevision::fromMinorVersion(0));
- const QTypeRevision removed = revisionClassInfo(
- type.classInfoMetaObject, "QML.RemovedInVersion");
-
- QVector<QTypeRevision> revisions = { added };
+ QList<QTypeRevision> revisions = revisionClassInfos(
+ type.classInfoMetaObject, "QML.ExtraVersion");
+ revisions.append(added);
uniqueRevisions(&revisions, type.version, added);
- for (QTypeRevision revision : qAsConst(revisions)) {
+ for (QTypeRevision revision : std::as_const(revisions)) {
if (revision < added)
continue;
if (revision.hasMajorVersion() && revision.majorVersion() > type.version.majorVersion())
break;
- // When removed, we still add revisions, but anonymous ones
- if (removed.isValid() && !(revision < removed))
- revisionRegistration.typeName = nullptr;
- else
- revisionRegistration.typeName = elementName;
-
assignVersions(&revisionRegistration, revision, type.version);
const int id = qmlregister(SequentialContainerRegistration, &revisionRegistration);
if (type.qmlTypeIds)
@@ -574,32 +840,30 @@ int QQmlPrivate::qmlregister(RegistrationType type, void *data)
break;
}
case TypeRegistration:
- dtype = QQmlMetaType::registerType(*reinterpret_cast<RegisterType *>(data));
- break;
+ return finalizeType(
+ QQmlMetaType::registerType(*reinterpret_cast<RegisterType *>(data)));
case InterfaceRegistration:
- dtype = QQmlMetaType::registerInterface(*reinterpret_cast<RegisterInterface *>(data));
- break;
+ return finalizeType(
+ QQmlMetaType::registerInterface(*reinterpret_cast<RegisterInterface *>(data)));
case SingletonRegistration:
- dtype = QQmlMetaType::registerSingletonType(*reinterpret_cast<RegisterSingletonType *>(data));
- break;
+ return finalizeType(QQmlMetaType::registerSingletonType(
+ *reinterpret_cast<RegisterSingletonType *>(data),
+ singletonInstanceInfo(*reinterpret_cast<RegisterSingletonType *>(data))));
case CompositeRegistration:
- dtype = QQmlMetaType::registerCompositeType(*reinterpret_cast<RegisterCompositeType *>(data));
- break;
+ return finalizeType(QQmlMetaType::registerCompositeType(
+ *reinterpret_cast<RegisterCompositeType *>(data)));
case CompositeSingletonRegistration:
- dtype = QQmlMetaType::registerCompositeSingletonType(*reinterpret_cast<RegisterCompositeSingletonType *>(data));
- break;
+ return finalizeType(QQmlMetaType::registerCompositeSingletonType(
+ *reinterpret_cast<RegisterCompositeSingletonType *>(data),
+ singletonInstanceInfo(*reinterpret_cast<RegisterCompositeSingletonType *>(data))));
case SequentialContainerRegistration:
- dtype = QQmlMetaType::registerSequentialContainer(*reinterpret_cast<RegisterSequentialContainer *>(data));
- break;
+ return finalizeType(QQmlMetaType::registerSequentialContainer(
+ *reinterpret_cast<RegisterSequentialContainer *>(data)));
default:
return -1;
}
- if (!dtype.isValid())
- return -1;
-
- QQmlMetaType::registerUndeletableType(dtype);
- return dtype.index();
+ return -1;
}
void QQmlPrivate::qmlunregister(RegistrationType type, quintptr data)
@@ -634,53 +898,1520 @@ void QQmlPrivate::qmlunregister(RegistrationType type, quintptr data)
}
}
+QList<QTypeRevision> QQmlPrivate::revisionClassInfos(const QMetaObject *metaObject,
+ const char *key)
+{
+ QList<QTypeRevision> revisions;
+ for (int index = indexOfOwnClassInfo(metaObject, key); index != -1;
+ index = indexOfOwnClassInfo(metaObject, key, index - 1)) {
+ revisions.push_back(QTypeRevision::fromEncodedVersion(
+ QLatin1StringView(metaObject->classInfo(index).value()).toInt()));
+ }
+ return revisions;
+}
+
+int qmlRegisterTypeNotAvailable(
+ const char *uri, int versionMajor, int versionMinor,
+ const char *qmlName, const QString &message)
+{
+ return qmlRegisterUncreatableType<QQmlTypeNotAvailable>(
+ uri, versionMajor, versionMinor, qmlName, message);
+}
+
namespace QQmlPrivate {
- template<>
- void qmlRegisterTypeAndRevisions<QQmlTypeNotAvailable, void>(
- const char *uri, int versionMajor, const QMetaObject *classInfoMetaObject,
- QVector<int> *qmlTypeIds, const QMetaObject *extension)
- {
- using T = QQmlTypeNotAvailable;
+template<>
+void qmlRegisterTypeAndRevisions<QQmlTypeNotAvailable, void>(
+ const char *uri, int versionMajor, const QMetaObject *classInfoMetaObject,
+ QVector<int> *qmlTypeIds, const QMetaObject *extension, bool)
+{
+ using T = QQmlTypeNotAvailable;
- RegisterTypeAndRevisions type = {
- 0,
- QMetaType::fromType<T *>(),
- QMetaType::fromType<QQmlListProperty<T>>(),
- 0,
- nullptr,
- nullptr,
- nullptr,
+ RegisterTypeAndRevisions type = {
+ 3,
+ QmlMetaType<T>::self(),
+ QmlMetaType<T>::list(),
+ 0,
+ nullptr,
+ nullptr,
+ nullptr,
- uri,
- QTypeRevision::fromMajorVersion(versionMajor),
+ uri,
+ QTypeRevision::fromMajorVersion(versionMajor),
- &QQmlTypeNotAvailable::staticMetaObject,
- classInfoMetaObject,
+ &QQmlTypeNotAvailable::staticMetaObject,
+ classInfoMetaObject,
- attachedPropertiesFunc<T>(),
- attachedPropertiesMetaObject<T>(),
+ attachedPropertiesFunc<T>(),
+ attachedPropertiesMetaObject<T>(),
- StaticCastSelector<T, QQmlParserStatus>::cast(),
- StaticCastSelector<T, QQmlPropertyValueSource>::cast(),
- StaticCastSelector<T, QQmlPropertyValueInterceptor>::cast(),
+ StaticCastSelector<T, QQmlParserStatus>::cast(),
+ StaticCastSelector<T, QQmlPropertyValueSource>::cast(),
+ StaticCastSelector<T, QQmlPropertyValueInterceptor>::cast(),
- nullptr, extension, qmlCreateCustomParser<T>, qmlTypeIds
- };
+ nullptr,
+ extension,
+ qmlCreateCustomParser<T>,
+ qmlTypeIds,
+ QQmlPrivate::StaticCastSelector<T, QQmlFinalizerHook>::cast(),
+ false,
+ QmlMetaType<T>::sequence(),
+ };
- qmlregister(TypeAndRevisionsRegistration, &type);
- }
+ qmlregister(TypeAndRevisionsRegistration, &type);
+}
+
+QObject *AOTCompiledContext::thisObject() const
+{
+ return static_cast<QV4::MetaTypesStackFrame *>(engine->handle()->currentStackFrame)
+ ->thisObject();
}
-QJSValue QQmlPrivate::AOTCompiledContext::jsMetaType(int index) const
+QQmlEngine *AOTCompiledContext::qmlEngine() const
+{
+ return engine->handle()->qmlEngine();
+}
+
+static QQmlPropertyCapture *propertyCapture(const AOTCompiledContext *aotContext)
+{
+ QQmlEngine *engine = aotContext->qmlEngine();
+ return engine ? QQmlEnginePrivate::get(aotContext->qmlEngine())->propertyCapture : nullptr;
+}
+
+QJSValue AOTCompiledContext::jsMetaType(int index) const
{
return QJSValuePrivate::fromReturnedValue(
compilationUnit->runtimeClasses[index]->asReturnedValue());
}
-void QQmlPrivate::AOTCompiledContext::setInstructionPointer(int offset) const
+void AOTCompiledContext::setInstructionPointer(int offset) const
{
if (auto *frame = engine->handle()->currentStackFrame)
frame->instructionPointer = offset;
}
+void AOTCompiledContext::setReturnValueUndefined() const
+{
+ if (auto *frame = engine->handle()->currentStackFrame) {
+ Q_ASSERT(frame->isMetaTypesFrame());
+ static_cast<QV4::MetaTypesStackFrame *>(frame)->setReturnValueUndefined();
+ }
+}
+
+static void captureFallbackProperty(
+ QObject *object, int coreIndex, int notifyIndex, bool isConstant,
+ const AOTCompiledContext *aotContext)
+{
+ if (isConstant)
+ return;
+
+ if (QQmlPropertyCapture *capture = propertyCapture(aotContext))
+ capture->captureProperty(object, coreIndex, notifyIndex);
+}
+
+static void captureObjectProperty(
+ QObject *object, const QQmlPropertyCache *propertyCache,
+ const QQmlPropertyData *property, const AOTCompiledContext *aotContext)
+{
+ if (property->isConstant())
+ return;
+
+ if (QQmlPropertyCapture *capture = propertyCapture(aotContext))
+ capture->captureProperty(object, propertyCache, property);
+}
+
+static bool inherits(const QQmlPropertyCache *descendent, const QQmlPropertyCache *ancestor)
+{
+ for (const QQmlPropertyCache *cache = descendent; cache; cache = cache->parent().data()) {
+ if (cache == ancestor)
+ return true;
+ }
+ return false;
+}
+
+enum class ObjectPropertyResult { OK, NeedsInit, Deleted };
+
+struct ObjectPropertyQmlData
+{
+ QQmlData *qmlData;
+ ObjectPropertyResult result;
+};
+
+template<bool StrictType>
+ObjectPropertyQmlData findObjectPropertyQmlData(QV4::Lookup *l, QObject *object)
+{
+ QQmlData *qmlData = QQmlData::get(object);
+ if (!qmlData)
+ return {qmlData, ObjectPropertyResult::NeedsInit};
+ if (qmlData->isQueuedForDeletion)
+ return {qmlData, ObjectPropertyResult::Deleted};
+ Q_ASSERT(!QQmlData::wasDeleted(object));
+ const QQmlPropertyCache *propertyCache = l->qobjectLookup.propertyCache;
+ if (StrictType) {
+ if (qmlData->propertyCache.data() != propertyCache)
+ return {qmlData, ObjectPropertyResult::NeedsInit};
+ } else if (!inherits(qmlData->propertyCache.data(), propertyCache)) {
+ return {qmlData, ObjectPropertyResult::NeedsInit};
+ }
+ return {qmlData, ObjectPropertyResult::OK};
+}
+
+template<bool StrictType = false>
+ObjectPropertyResult loadObjectProperty(
+ QV4::Lookup *l, QObject *object, void *target, const AOTCompiledContext *aotContext)
+{
+ const ObjectPropertyQmlData data = findObjectPropertyQmlData<StrictType>(l, object);
+ if (data.result != ObjectPropertyResult::OK)
+ return data.result;
+
+ const QQmlPropertyData *propertyData = l->qobjectLookup.propertyData;
+ const int coreIndex = propertyData->coreIndex();
+ if (data.qmlData->hasPendingBindingBit(coreIndex))
+ data.qmlData->flushPendingBinding(coreIndex);
+
+ captureObjectProperty(object, l->qobjectLookup.propertyCache, propertyData, aotContext);
+ propertyData->readProperty(object, target);
+ return ObjectPropertyResult::OK;
+}
+
+template<bool StrictType = false>
+ObjectPropertyResult writeBackObjectProperty(QV4::Lookup *l, QObject *object, void *source)
+{
+ const ObjectPropertyQmlData data = findObjectPropertyQmlData<StrictType>(l, object);
+ if (data.result != ObjectPropertyResult::OK)
+ return data.result;
+
+ l->qobjectLookup.propertyData->writeProperty(object, source, {});
+ return ObjectPropertyResult::OK;
+}
+
+struct FallbackPropertyQmlData
+{
+ QQmlData *qmlData;
+ const QMetaObject *metaObject;
+ ObjectPropertyResult result;
+};
+
+static FallbackPropertyQmlData findFallbackPropertyQmlData(QV4::Lookup *l, QObject *object)
+{
+ QQmlData *qmlData = QQmlData::get(object);
+ if (qmlData && qmlData->isQueuedForDeletion)
+ return {qmlData, nullptr, ObjectPropertyResult::Deleted};
+
+ Q_ASSERT(!QQmlData::wasDeleted(object));
+
+ const QMetaObject *metaObject
+ = reinterpret_cast<const QMetaObject *>(l->qobjectFallbackLookup.metaObject - 1);
+ if (!metaObject || metaObject != object->metaObject())
+ return {qmlData, nullptr, ObjectPropertyResult::NeedsInit};
+
+ return {qmlData, metaObject, ObjectPropertyResult::OK};
+}
+
+static ObjectPropertyResult loadFallbackProperty(
+ QV4::Lookup *l, QObject *object, void *target, const AOTCompiledContext *aotContext)
+{
+ const FallbackPropertyQmlData data = findFallbackPropertyQmlData(l, object);
+ if (data.result != ObjectPropertyResult::OK)
+ return data.result;
+
+ const int coreIndex = l->qobjectFallbackLookup.coreIndex;
+ if (data.qmlData && data.qmlData->hasPendingBindingBit(coreIndex))
+ data.qmlData->flushPendingBinding(coreIndex);
+
+ captureFallbackProperty(object, coreIndex, l->qobjectFallbackLookup.notifyIndex,
+ l->qobjectFallbackLookup.isConstant, aotContext);
+
+ void *a[] = { target, nullptr };
+ data.metaObject->metacall(object, QMetaObject::ReadProperty, coreIndex, a);
+
+ return ObjectPropertyResult::OK;
+}
+
+static ObjectPropertyResult writeBackFallbackProperty(QV4::Lookup *l, QObject *object, void *source)
+{
+ const FallbackPropertyQmlData data = findFallbackPropertyQmlData(l, object);
+ if (data.result != ObjectPropertyResult::OK)
+ return data.result;
+
+ void *a[] = { source, nullptr };
+ data.metaObject->metacall(
+ object, QMetaObject::WriteProperty, l->qobjectFallbackLookup.coreIndex, a);
+
+ return ObjectPropertyResult::OK;
+}
+
+ObjectPropertyResult loadObjectAsVariant(
+ QV4::Lookup *l, QObject *object, void *target, const AOTCompiledContext *aotContext)
+{
+ QVariant *variant = static_cast<QVariant *>(target);
+ const QMetaType propType = l->qobjectLookup.propertyData->propType();
+ if (propType == QMetaType::fromType<QVariant>())
+ return loadObjectProperty<true>(l, object, variant, aotContext);
+
+ *variant = QVariant(propType);
+ return loadObjectProperty<true>(l, object, variant->data(), aotContext);
+}
+
+ObjectPropertyResult writeBackObjectAsVariant(QV4::Lookup *l, QObject *object, void *source)
+{
+ QVariant *variant = static_cast<QVariant *>(source);
+ const QMetaType propType = l->qobjectLookup.propertyData->propType();
+ if (propType == QMetaType::fromType<QVariant>())
+ return writeBackObjectProperty<true>(l, object, variant);
+
+ Q_ASSERT(variant->metaType() == propType);
+ return writeBackObjectProperty<true>(l, object, variant->data());
+}
+
+ObjectPropertyResult loadFallbackAsVariant(
+ QV4::Lookup *l, QObject *object, void *target, const AOTCompiledContext *aotContext)
+{
+ const QMetaObject *metaObject
+ = reinterpret_cast<const QMetaObject *>(l->qobjectFallbackLookup.metaObject - 1);
+ Q_ASSERT(metaObject);
+
+ QVariant *variant = static_cast<QVariant *>(target);
+ const QMetaType propType = metaObject->property(l->qobjectFallbackLookup.coreIndex).metaType();
+ if (propType == QMetaType::fromType<QVariant>())
+ return loadFallbackProperty(l, object, variant, aotContext);
+
+ *variant = QVariant(propType);
+ return loadFallbackProperty(l, object, variant->data(), aotContext);
+}
+
+ObjectPropertyResult writeBackFallbackAsVariant(QV4::Lookup *l, QObject *object, void *source)
+{
+ const QMetaObject *metaObject
+ = reinterpret_cast<const QMetaObject *>(l->qobjectFallbackLookup.metaObject - 1);
+ Q_ASSERT(metaObject);
+
+ QVariant *variant = static_cast<QVariant *>(source);
+ const QMetaType propType = metaObject->property(l->qobjectFallbackLookup.coreIndex).metaType();
+ if (propType == QMetaType::fromType<QVariant>())
+ return writeBackFallbackProperty(l, object, variant);
+
+ Q_ASSERT(variant->metaType() == propType);
+ return writeBackFallbackProperty(l, object, variant->data());
+}
+
+template<bool StrictType, typename Op>
+static ObjectPropertyResult changeObjectProperty(QV4::Lookup *l, QObject *object, Op op)
+{
+ const ObjectPropertyQmlData data = findObjectPropertyQmlData<StrictType>(l, object);
+ if (data.result != ObjectPropertyResult::OK)
+ return data.result;
+
+ const QQmlPropertyData *property = l->qobjectLookup.propertyData;
+ QQmlPropertyPrivate::removeBinding(object, QQmlPropertyIndex(property->coreIndex()));
+ op(property);
+ return ObjectPropertyResult::OK;
+}
+
+template<bool StrictType = false>
+static ObjectPropertyResult resetObjectProperty(
+ QV4::Lookup *l, QObject *object, QV4::ExecutionEngine *v4)
+{
+ return changeObjectProperty<StrictType>(l, object, [&](const QQmlPropertyData *property) {
+ if (property->isResettable()) {
+ property->resetProperty(object, {});
+ } else {
+ v4->throwError(
+ QLatin1String("Cannot assign [undefined] to ") +
+ QLatin1String(property->propType().name()));
+ }
+ });
+}
+
+template<bool StrictType = false>
+static ObjectPropertyResult storeObjectProperty(QV4::Lookup *l, QObject *object, void *value)
+{
+ return changeObjectProperty<StrictType>(l, object, [&](const QQmlPropertyData *property) {
+ property->writeProperty(object, value, {});
+ });
+}
+
+template<typename Op>
+static ObjectPropertyResult changeFallbackProperty(QV4::Lookup *l, QObject *object, Op op)
+{
+ const FallbackPropertyQmlData data = findFallbackPropertyQmlData(l, object);
+ if (data.result != ObjectPropertyResult::OK)
+ return data.result;
+
+ const int coreIndex = l->qobjectFallbackLookup.coreIndex;
+ QQmlPropertyPrivate::removeBinding(object, QQmlPropertyIndex(coreIndex));
+
+ op(data.metaObject, coreIndex);
+ return ObjectPropertyResult::OK;
+}
+
+static ObjectPropertyResult storeFallbackProperty(QV4::Lookup *l, QObject *object, void *value)
+{
+ return changeFallbackProperty(l, object, [&](const QMetaObject *metaObject, int coreIndex) {
+ void *args[] = { value, nullptr };
+ metaObject->metacall(object, QMetaObject::WriteProperty, coreIndex, args);
+ });
+}
+
+static ObjectPropertyResult resetFallbackProperty(
+ QV4::Lookup *l, QObject *object, const QMetaProperty *property, QV4::ExecutionEngine *v4)
+{
+ return changeFallbackProperty(l, object, [&](const QMetaObject *metaObject, int coreIndex) {
+ if (property->isResettable()) {
+ void *args[] = { nullptr };
+ metaObject->metacall(object, QMetaObject::ResetProperty, coreIndex, args);
+ } else {
+ v4->throwError(
+ QLatin1String("Cannot assign [undefined] to ") +
+ QLatin1String(property->typeName()));
+ }
+ });
+}
+
+static bool isTypeCompatible(QMetaType lookupType, QMetaType propertyType)
+{
+ if (!lookupType.isValid()) {
+ // If type is invalid, then the calling code depends on the lookup
+ // to be set up in order to query the type, via lookupResultMetaType.
+ // We cannot verify the type in this case.
+ } else if ((lookupType.flags() & QMetaType::IsQmlList)
+ && (propertyType.flags() & QMetaType::IsQmlList)) {
+ // We want to check the value types here, but we cannot easily do it.
+ // Internally those are all QObject* lists, though.
+ } else if (lookupType.flags() & QMetaType::PointerToQObject) {
+ // We accept any base class as type, too
+
+ const QMetaObject *typeMetaObject = lookupType.metaObject();
+ const QMetaObject *foundMetaObject = propertyType.metaObject();
+ if (!foundMetaObject)
+ foundMetaObject = QQmlMetaType::metaObjectForType(propertyType).metaObject();
+
+ while (foundMetaObject && foundMetaObject != typeMetaObject)
+ foundMetaObject = foundMetaObject->superClass();
+
+ if (!foundMetaObject)
+ return false;
+ } else if (propertyType.flags() & QMetaType::IsEnumeration) {
+ if (propertyType == lookupType)
+ return true;
+
+ // You can pass the underlying type of an enum.
+ // We don't want to check for the actual underlying type because
+ // moc and qmltyperegistrar are not very precise about it. Especially
+ // the long and longlong types can be ambiguous.
+
+ const bool isUnsigned = propertyType.flags() & QMetaType::IsUnsignedEnumeration;
+ switch (propertyType.sizeOf()) {
+ case 1:
+ return isUnsigned
+ ? lookupType == QMetaType::fromType<quint8>()
+ : lookupType == QMetaType::fromType<qint8>();
+ case 2:
+ return isUnsigned
+ ? lookupType == QMetaType::fromType<ushort>()
+ : lookupType == QMetaType::fromType<short>();
+ case 4:
+ // The default type, if moc doesn't know the actual enum type, is int.
+ // However, the compiler can still decide to encode the enum in uint.
+ // Therefore, we also accept int for uint enums.
+ // TODO: This is technically UB.
+ return isUnsigned
+ ? (lookupType == QMetaType::fromType<int>()
+ || lookupType == QMetaType::fromType<uint>())
+ : lookupType == QMetaType::fromType<int>();
+ case 8:
+ return isUnsigned
+ ? lookupType == QMetaType::fromType<qulonglong>()
+ : lookupType == QMetaType::fromType<qlonglong>();
+ }
+
+ return false;
+ } else if (propertyType != lookupType) {
+ return false;
+ }
+ return true;
+}
+
+static ObjectPropertyResult storeObjectAsVariant(
+ QV4::ExecutionEngine *v4, QV4::Lookup *l, QObject *object, void *value)
+{
+ QVariant *variant = static_cast<QVariant *>(value);
+ const QMetaType propType = l->qobjectLookup.propertyData->propType();
+ if (propType == QMetaType::fromType<QVariant>())
+ return storeObjectProperty<true>(l, object, variant);
+
+ if (!variant->isValid())
+ return resetObjectProperty<true>(l, object, v4);
+
+ if (isTypeCompatible(variant->metaType(), propType))
+ return storeObjectProperty<true>(l, object, variant->data());
+
+ QVariant converted(propType);
+ v4->metaTypeFromJS(v4->fromVariant(*variant), propType, converted.data());
+ return storeObjectProperty<true>(l, object, converted.data());
+}
+
+static ObjectPropertyResult storeFallbackAsVariant(
+ QV4::ExecutionEngine *v4, QV4::Lookup *l, QObject *object, void *value)
+{
+ QVariant *variant = static_cast<QVariant *>(value);
+
+ const QMetaObject *metaObject
+ = reinterpret_cast<const QMetaObject *>(l->qobjectFallbackLookup.metaObject - 1);
+ Q_ASSERT(metaObject);
+
+ const QMetaProperty property = metaObject->property(l->qobjectFallbackLookup.coreIndex);
+ const QMetaType propType = property.metaType();
+ if (propType == QMetaType::fromType<QVariant>())
+ return storeFallbackProperty(l, object, variant);
+
+ if (!variant->isValid())
+ return resetFallbackProperty(l, object, &property, v4);
+
+ if (isTypeCompatible(variant->metaType(), propType))
+ return storeFallbackProperty(l, object, variant->data());
+
+ QVariant converted(propType);
+ v4->metaTypeFromJS(v4->fromVariant(*variant), propType, converted.data());
+ return storeFallbackProperty(l, object, converted.data());
+}
+
+enum class ObjectLookupResult {
+ Failure,
+ Object,
+ Fallback,
+ ObjectAsVariant,
+ FallbackAsVariant,
+};
+
+static ObjectLookupResult initObjectLookup(
+ const AOTCompiledContext *aotContext, QV4::Lookup *l, QObject *object, QMetaType type)
+{
+ QV4::Scope scope(aotContext->engine->handle());
+ QV4::PropertyKey id = scope.engine->identifierTable->asPropertyKey(
+ aotContext->compilationUnit->runtimeStrings[l->nameIndex]);
+
+ Q_ASSERT(id.isString());
+
+ QV4::ScopedString name(scope, id.asStringOrSymbol());
+
+ Q_ASSERT(!name->equals(scope.engine->id_toString()));
+ Q_ASSERT(!name->equals(scope.engine->id_destroy()));
+
+ QQmlData *ddata = QQmlData::get(object, true);
+ Q_ASSERT(ddata);
+ if (ddata->isQueuedForDeletion)
+ return ObjectLookupResult::Failure;
+
+ const QQmlPropertyData *property;
+ if (!ddata->propertyCache) {
+ property = QQmlPropertyCache::property(object, name, aotContext->qmlContext, nullptr);
+ } else {
+ property = ddata->propertyCache->property(
+ name.getPointer(), object, aotContext->qmlContext);
+ }
+
+ const bool doVariantLookup = type == QMetaType::fromType<QVariant>();
+ if (!property) {
+ const QMetaObject *metaObject = object->metaObject();
+ if (!metaObject)
+ return ObjectLookupResult::Failure;
+
+ const int coreIndex = metaObject->indexOfProperty(
+ name->toQStringNoThrow().toUtf8().constData());
+ if (coreIndex < 0)
+ return ObjectLookupResult::Failure;
+
+ const QMetaProperty property = metaObject->property(coreIndex);
+ if (!doVariantLookup && !isTypeCompatible(type, property.metaType()))
+ return ObjectLookupResult::Failure;
+
+ l->releasePropertyCache();
+ // & 1 to tell the gc that this is not heap allocated; see markObjects in qv4lookup_p.h
+ l->qobjectFallbackLookup.metaObject = quintptr(metaObject) + 1;
+ l->qobjectFallbackLookup.coreIndex = coreIndex;
+ l->qobjectFallbackLookup.notifyIndex =
+ QMetaObjectPrivate::signalIndex(property.notifySignal());
+ l->qobjectFallbackLookup.isConstant = property.isConstant() ? 1 : 0;
+ return doVariantLookup
+ ? ObjectLookupResult::FallbackAsVariant
+ : ObjectLookupResult::Fallback;
+ }
+
+ if (!doVariantLookup && !isTypeCompatible(type, property->propType()))
+ return ObjectLookupResult::Failure;
+
+ Q_ASSERT(ddata->propertyCache);
+
+ QV4::setupQObjectLookup(l, ddata, property);
+
+ return doVariantLookup
+ ? ObjectLookupResult::ObjectAsVariant
+ : ObjectLookupResult::Object;
+}
+
+static bool initValueLookup(QV4::Lookup *l, QV4::ExecutableCompilationUnit *compilationUnit,
+ const QMetaObject *metaObject, QMetaType type)
+{
+ Q_ASSERT(metaObject);
+ const QByteArray name = compilationUnit->runtimeStrings[l->nameIndex]->toQString().toUtf8();
+ const int coreIndex = metaObject->indexOfProperty(name.constData());
+ QMetaType lookupType = metaObject->property(coreIndex).metaType();
+ if (!isTypeCompatible(type, lookupType))
+ return false;
+ l->qgadgetLookup.metaObject = quintptr(metaObject) + 1;
+ l->qgadgetLookup.coreIndex = coreIndex;
+ l->qgadgetLookup.metaType = lookupType.iface();
+ return true;
+}
+
+static void amendException(QV4::ExecutionEngine *engine)
+{
+ const int missingLineNumber = engine->currentStackFrame->missingLineNumber();
+ const int lineNumber = engine->currentStackFrame->lineNumber();
+ Q_ASSERT(missingLineNumber != lineNumber);
+
+ auto amendStackTrace = [&](QV4::StackTrace *stackTrace) {
+ for (auto it = stackTrace->begin(), end = stackTrace->end(); it != end; ++it) {
+ if (it->line == missingLineNumber) {
+ it->line = lineNumber;
+ break;
+ }
+ }
+ };
+
+ amendStackTrace(&engine->exceptionStackTrace);
+
+ QV4::Scope scope(engine);
+ QV4::Scoped<QV4::ErrorObject> error(scope, *engine->exceptionValue);
+ if (error) // else some other value was thrown
+ amendStackTrace(error->d()->stackTrace);
+}
+
+
+bool AOTCompiledContext::captureLookup(uint index, QObject *object) const
+{
+ if (!object)
+ return false;
+
+ QV4::Lookup *l = compilationUnit->runtimeLookups + index;
+ if (l->getter == QV4::QQmlTypeWrapper::lookupSingletonProperty
+ || l->getter == QV4::Lookup::getterQObject
+ || l->getter == QV4::Lookup::getterQObjectAsVariant) {
+ const QQmlPropertyData *property = l->qobjectLookup.propertyData;
+ QQmlData::flushPendingBinding(object, property->coreIndex());
+ captureObjectProperty(object, l->qobjectLookup.propertyCache, property, this);
+ return true;
+ }
+
+ if (l->getter == QV4::Lookup::getterFallback
+ || l->getter == QV4::Lookup::getterFallbackAsVariant) {
+ const int coreIndex = l->qobjectFallbackLookup.coreIndex;
+ QQmlData::flushPendingBinding(object, coreIndex);
+ captureFallbackProperty(
+ object, coreIndex, l->qobjectFallbackLookup.notifyIndex,
+ l->qobjectFallbackLookup.isConstant, this);
+ return true;
+ }
+
+ return false;
+}
+
+bool AOTCompiledContext::captureQmlContextPropertyLookup(uint index) const
+{
+ QV4::Lookup *l = compilationUnit->runtimeLookups + index;
+ if (l->qmlContextPropertyGetter == QV4::QQmlContextWrapper::lookupScopeObjectProperty
+ && l->qmlContextPropertyGetter == QV4::QQmlContextWrapper::lookupContextObjectProperty) {
+ const QQmlPropertyData *property = l->qobjectLookup.propertyData;
+ QQmlData::flushPendingBinding(qmlScopeObject, property->coreIndex());
+ captureObjectProperty(qmlScopeObject, l->qobjectLookup.propertyCache, property, this);
+ return true;
+ }
+
+ if (l->qmlContextPropertyGetter == QV4::QQmlContextWrapper::lookupScopeFallbackProperty) {
+ const int coreIndex = l->qobjectFallbackLookup.coreIndex;
+ QQmlData::flushPendingBinding(qmlScopeObject, coreIndex);
+ captureFallbackProperty(qmlScopeObject, coreIndex, l->qobjectFallbackLookup.notifyIndex,
+ l->qobjectFallbackLookup.isConstant, this);
+ return true;
+ }
+
+ return false;
+}
+
+void AOTCompiledContext::captureTranslation() const
+{
+ if (QQmlPropertyCapture *capture = propertyCapture(this))
+ capture->captureTranslation();
+}
+
+QString AOTCompiledContext::translationContext() const
+{
+#if QT_CONFIG(translation)
+ return QV4::GlobalExtensions::currentTranslationContext(engine->handle());
+#else
+ return QString();
+#endif
+}
+
+QMetaType AOTCompiledContext::lookupResultMetaType(uint index) const
+{
+ QV4::Lookup *l = compilationUnit->runtimeLookups + index;
+ if (l->qmlContextPropertyGetter == QV4::QQmlContextWrapper::lookupScopeObjectProperty
+ || l->qmlContextPropertyGetter == QV4::QQmlContextWrapper::lookupContextObjectProperty
+ || l->getter == QV4::QQmlTypeWrapper::lookupSingletonProperty
+ || l->getter == QV4::Lookup::getterQObject
+ || l->setter == QV4::Lookup::setterQObject
+ || l->getter == QV4::Lookup::getterQObjectAsVariant
+ || l->setter == QV4::Lookup::setterQObjectAsVariant) {
+ return l->qobjectLookup.propertyData->propType();
+ } else if (l->getter == QV4::QQmlValueTypeWrapper::lookupGetter) {
+ return QMetaType(l->qgadgetLookup.metaType);
+ } else if (l->getter == QV4::QQmlTypeWrapper::lookupEnumValue) {
+ return QMetaType::fromType<int>();
+ } else if (l->qmlContextPropertyGetter == QV4::QQmlContextWrapper::lookupIdObject
+ || l->qmlContextPropertyGetter == QV4::QQmlContextWrapper::lookupType
+ || l->qmlContextPropertyGetter == QV4::QQmlContextWrapper::lookupSingleton
+ || l->getter == QV4::QObjectWrapper::lookupAttached) {
+ return QMetaType::fromType<QObject *>();
+ } else if (l->getter == QV4::Lookup::getterFallback
+ || l->setter == QV4::Lookup::setterFallback
+ || l->getter == QV4::Lookup::getterFallbackAsVariant
+ || l->setter == QV4::Lookup::setterFallbackAsVariant
+ || l->qmlContextPropertyGetter
+ == QV4::QQmlContextWrapper::lookupScopeFallbackProperty) {
+ const QMetaObject *metaObject
+ = reinterpret_cast<const QMetaObject *>(l->qobjectFallbackLookup.metaObject - 1);
+ const int coreIndex = l->qobjectFallbackLookup.coreIndex;
+ return metaObject->property(coreIndex).metaType();
+ }
+ return QMetaType();
+}
+
+static bool isUndefined(const void *value, QMetaType type)
+{
+ if (type == QMetaType::fromType<QVariant>())
+ return !static_cast<const QVariant *>(value)->isValid();
+ if (type == QMetaType::fromType<QJSValue>())
+ return static_cast<const QJSValue *>(value)->isUndefined();
+ if (type == QMetaType::fromType<QJSPrimitiveValue>()) {
+ return static_cast<const QJSPrimitiveValue *>(value)->type()
+ == QJSPrimitiveValue::Undefined;
+ }
+ return false;
+}
+
+void AOTCompiledContext::storeNameSloppy(uint nameIndex, void *value, QMetaType type) const
+{
+ // We don't really use any part of the lookup machinery here.
+ // The QV4::Lookup is created on the stack to conveniently get the property cache, and through
+ // the property cache we store a value into the property.
+
+ QV4::Lookup l;
+ memset(&l, 0, sizeof(QV4::Lookup));
+ l.nameIndex = nameIndex;
+ l.forCall = false;
+ ObjectPropertyResult storeResult = ObjectPropertyResult::NeedsInit;
+ switch (initObjectLookup(this, &l, qmlScopeObject, QMetaType())) {
+ case ObjectLookupResult::ObjectAsVariant:
+ case ObjectLookupResult::Object: {
+ const QMetaType propType = l.qobjectLookup.propertyData->propType();
+ if (isTypeCompatible(type, propType)) {
+ storeResult = storeObjectProperty(&l, qmlScopeObject, value);
+ } else if (isUndefined(value, type)) {
+ storeResult = resetObjectProperty(&l, qmlScopeObject, engine->handle());
+ } else {
+ QVariant var(propType);
+ QV4::ExecutionEngine *v4 = engine->handle();
+ v4->metaTypeFromJS(v4->metaTypeToJS(type, value), propType, var.data());
+ storeResult = storeObjectProperty(&l, qmlScopeObject, var.data());
+ }
+
+ l.qobjectLookup.propertyCache->release();
+ break;
+ }
+ case ObjectLookupResult::FallbackAsVariant:
+ case ObjectLookupResult::Fallback: {
+ const QMetaObject *metaObject
+ = reinterpret_cast<const QMetaObject *>(l.qobjectFallbackLookup.metaObject - 1);
+ const QMetaProperty property = metaObject->property(l.qobjectFallbackLookup.coreIndex);
+ const QMetaType propType = property.metaType();
+ if (isTypeCompatible(type, propType)) {
+ storeResult = storeFallbackProperty(&l, qmlScopeObject, value);
+ } else if (isUndefined(value, type)) {
+ storeResult = resetFallbackProperty(&l, qmlScopeObject, &property, engine->handle());
+ } else {
+ QVariant var(propType);
+ QV4::ExecutionEngine *v4 = engine->handle();
+ v4->metaTypeFromJS(v4->metaTypeToJS(type, value), propType, var.data());
+ storeResult = storeFallbackProperty(&l, qmlScopeObject, var.data());
+ }
+ break;
+ }
+ case ObjectLookupResult::Failure:
+ engine->handle()->throwTypeError();
+ return;
+ }
+
+ switch (storeResult) {
+ case ObjectPropertyResult::NeedsInit:
+ engine->handle()->throwTypeError();
+ break;
+ case ObjectPropertyResult::Deleted:
+ engine->handle()->throwTypeError(
+ QStringLiteral("Value is null and could not be converted to an object"));
+ break;
+ case ObjectPropertyResult::OK:
+ break;
+ }
+}
+
+QJSValue AOTCompiledContext::javaScriptGlobalProperty(uint nameIndex) const
+{
+ QV4::Scope scope(engine->handle());
+ QV4::ScopedString name(scope, compilationUnit->runtimeStrings[nameIndex]);
+ QV4::ScopedObject global(scope, scope.engine->globalObject);
+ return QJSValuePrivate::fromReturnedValue(global->get(name->toPropertyKey()));
+}
+
+const QLoggingCategory *AOTCompiledContext::resolveLoggingCategory(QObject *wrapper, bool *ok) const
+{
+ if (wrapper) {
+ // We have to check this here because you may pass a plain QObject that only
+ // turns out to be a QQmlLoggingCategory at run time.
+ if (QQmlLoggingCategory *qQmlLoggingCategory
+ = qobject_cast<QQmlLoggingCategory *>(wrapper)) {
+ QLoggingCategory *loggingCategory = qQmlLoggingCategory->category();
+ *ok = true;
+ if (!loggingCategory) {
+ engine->handle()->throwError(
+ QStringLiteral("A QmlLoggingCatgory was provided without a valid name"));
+ }
+ return loggingCategory;
+ }
+ }
+
+ *ok = false;
+ return qmlEngine() ? &lcQml() : &lcJs();
+}
+
+void AOTCompiledContext::writeToConsole(
+ QtMsgType type, const QString &message, const QLoggingCategory *loggingCategory) const
+{
+ Q_ASSERT(loggingCategory->isEnabled(type));
+
+ const QV4::CppStackFrame *frame = engine->handle()->currentStackFrame;
+ Q_ASSERT(frame);
+
+ const QByteArray source(frame->source().toUtf8());
+ const QByteArray function(frame->function().toUtf8());
+ QMessageLogger logger(source.constData(), frame->lineNumber(),
+ function.constData(), loggingCategory->categoryName());
+
+ switch (type) {
+ case QtDebugMsg:
+ logger.debug("%s", qUtf8Printable(message));
+ break;
+ case QtInfoMsg:
+ logger.info("%s", qUtf8Printable(message));
+ break;
+ case QtWarningMsg:
+ logger.warning("%s", qUtf8Printable(message));
+ break;
+ case QtCriticalMsg:
+ logger.critical("%s", qUtf8Printable(message));
+ break;
+ default:
+ break;
+ }
+}
+
+QVariant AOTCompiledContext::constructValueType(
+ QMetaType resultMetaType, const QMetaObject *resultMetaObject,
+ int ctorIndex, void *ctorArg) const
+{
+ return QQmlValueTypeProvider::constructValueType(
+ resultMetaType, resultMetaObject, ctorIndex, ctorArg);
+}
+
+QDateTime AOTCompiledContext::constructDateTime(double timestamp) const
+{
+ return QV4::DateObject::timestampToDateTime(timestamp);
+}
+
+QDateTime AOTCompiledContext::constructDateTime(const QString &string) const
+{
+ return QV4::DateObject::stringToDateTime(string, engine->handle());
+}
+
+QDateTime AOTCompiledContext::constructDateTime(
+ double year, double month, double day, double hours,
+ double minutes, double seconds, double msecs) const
+{
+ return constructDateTime(QV4::DateObject::componentsToTimestamp(
+ year, month, day, hours, minutes, seconds, msecs, engine->handle()));
+}
+
+bool AOTCompiledContext::callQmlContextPropertyLookup(
+ uint index, void **args, const QMetaType *types, int argc) const
+{
+ QV4::Lookup *l = compilationUnit->runtimeLookups + index;
+ QV4::Scope scope(engine->handle());
+ QV4::ScopedValue thisObject(scope);
+ QV4::ScopedFunctionObject function(
+ scope, l->qmlContextPropertyGetter(l, scope.engine, thisObject));
+ if (!function) {
+ scope.engine->throwTypeError(
+ QStringLiteral("Property '%1' of object [null] is not a function").arg(
+ compilationUnit->runtimeStrings[l->nameIndex]->toQString()));
+ return false;
+ }
+
+ function->call(qmlScopeObject, args, types, argc);
+ return !scope.hasException();
+}
+
+void AOTCompiledContext::initCallQmlContextPropertyLookup(uint index) const
+{
+ Q_UNUSED(index);
+ Q_ASSERT(engine->hasError());
+ amendException(engine->handle());
+}
+
+bool AOTCompiledContext::loadContextIdLookup(uint index, void *target) const
+{
+ QV4::Lookup *l = compilationUnit->runtimeLookups + index;
+ int objectId = -1;
+ QQmlContextData *context = nullptr;
+ Q_ASSERT(qmlContext);
+
+ if (l->qmlContextPropertyGetter == QV4::QQmlContextWrapper::lookupIdObject) {
+ objectId = l->qmlContextIdObjectLookup.objectId;
+ context = qmlContext;
+ } else if (l->qmlContextPropertyGetter
+ == QV4::QQmlContextWrapper::lookupIdObjectInParentContext) {
+ QV4::Scope scope(engine->handle());
+ QV4::ScopedString name(scope, compilationUnit->runtimeStrings[l->nameIndex]);
+ for (context = qmlContext; context; context = context->parent().data()) {
+ objectId = context->propertyIndex(name);
+ if (objectId != -1 && objectId < context->numIdValues())
+ break;
+ }
+ } else {
+ return false;
+ }
+
+ Q_ASSERT(objectId >= 0);
+ Q_ASSERT(context != nullptr);
+ QQmlEnginePrivate *engine = QQmlEnginePrivate::get(qmlEngine());
+ if (QQmlPropertyCapture *capture = engine->propertyCapture)
+ capture->captureProperty(context->idValueBindings(objectId));
+ *static_cast<QObject **>(target) = context->idValue(objectId);
+ return true;
+}
+
+void AOTCompiledContext::initLoadContextIdLookup(uint index) const
+{
+ Q_ASSERT(!engine->hasError());
+ QV4::Lookup *l = compilationUnit->runtimeLookups + index;
+ QV4::Scope scope(engine->handle());
+ QV4::ScopedString name(scope, compilationUnit->runtimeStrings[l->nameIndex]);
+ const QQmlRefPointer<QQmlContextData> ownContext = qmlContext;
+ for (auto context = ownContext; context; context = context->parent()) {
+ const int propertyIdx = context->propertyIndex(name);
+ if (propertyIdx == -1 || propertyIdx >= context->numIdValues())
+ continue;
+
+ if (context.data() == ownContext.data()) {
+ l->qmlContextIdObjectLookup.objectId = propertyIdx;
+ l->qmlContextPropertyGetter = QV4::QQmlContextWrapper::lookupIdObject;
+ } else {
+ l->qmlContextPropertyGetter = QV4::QQmlContextWrapper::lookupIdObjectInParentContext;
+ }
+
+ return;
+ }
+
+ Q_UNREACHABLE();
+}
+
+bool AOTCompiledContext::callObjectPropertyLookup(
+ uint index, QObject *object, void **args, const QMetaType *types, int argc) const
+{
+ QV4::Lookup *l = compilationUnit->runtimeLookups + index;
+ QV4::Scope scope(engine->handle());
+ QV4::ScopedValue thisObject(scope, QV4::QObjectWrapper::wrap(scope.engine, object));
+ QV4::ScopedFunctionObject function(scope, l->getter(l, engine->handle(), thisObject));
+ if (!function) {
+ scope.engine->throwTypeError(
+ QStringLiteral("Property '%1' of object [object Object] is not a function")
+ .arg(compilationUnit->runtimeStrings[l->nameIndex]->toQString()));
+ return false;
+ }
+
+ function->call(object, args, types, argc);
+ return !scope.hasException();
+}
+
+void AOTCompiledContext::initCallObjectPropertyLookup(uint index) const
+{
+ Q_UNUSED(index);
+ Q_ASSERT(engine->hasError());
+ amendException(engine->handle());
+}
+
+bool AOTCompiledContext::callGlobalLookup(
+ uint index, void **args, const QMetaType *types, int argc) const
+{
+ QV4::Lookup *l = compilationUnit->runtimeLookups + index;
+ QV4::Scope scope(engine->handle());
+ QV4::ScopedFunctionObject function(scope, l->globalGetter(l, scope.engine));
+ if (!function) {
+ scope.engine->throwTypeError(
+ QStringLiteral("Property '%1' of object [null] is not a function")
+ .arg(compilationUnit->runtimeStrings[l->nameIndex]->toQString()));
+ return false;
+ }
+
+ function->call(nullptr, args, types, argc);
+ return true;
+}
+
+void AOTCompiledContext::initCallGlobalLookup(uint index) const
+{
+ Q_UNUSED(index);
+ Q_ASSERT(engine->hasError());
+ amendException(engine->handle());
+}
+
+bool AOTCompiledContext::loadGlobalLookup(uint index, void *target, QMetaType type) const
+{
+ QV4::Lookup *l = compilationUnit->runtimeLookups + index;
+ if (!QV4::ExecutionEngine::metaTypeFromJS(l->globalGetter(l, engine->handle()), type, target)) {
+ engine->handle()->throwTypeError();
+ return false;
+ }
+ return true;
+}
+
+void AOTCompiledContext::initLoadGlobalLookup(uint index) const
+{
+ Q_UNUSED(index);
+ Q_ASSERT(engine->hasError());
+ amendException(engine->handle());
+}
+
+bool AOTCompiledContext::loadScopeObjectPropertyLookup(uint index, void *target) const
+{
+ QV4::Lookup *l = compilationUnit->runtimeLookups + index;
+
+ if (!qmlScopeObject) {
+ engine->handle()->throwReferenceError(
+ compilationUnit->runtimeStrings[l->nameIndex]->toQString());
+ return false;
+ }
+
+ ObjectPropertyResult result = ObjectPropertyResult::NeedsInit;
+ if (l->qmlContextPropertyGetter == QV4::QQmlContextWrapper::lookupScopeObjectProperty)
+ result = loadObjectProperty(l, qmlScopeObject, target, this);
+ else if (l->qmlContextPropertyGetter == QV4::QQmlContextWrapper::lookupScopeFallbackProperty)
+ result = loadFallbackProperty(l, qmlScopeObject, target, this);
+ else
+ return false;
+
+ switch (result) {
+ case ObjectPropertyResult::NeedsInit:
+ return false;
+ case ObjectPropertyResult::Deleted:
+ engine->handle()->throwTypeError(
+ QStringLiteral("Cannot read property '%1' of null")
+ .arg(compilationUnit->runtimeStrings[l->nameIndex]->toQString()));
+ return false;
+ case ObjectPropertyResult::OK:
+ return true;
+ }
+
+ Q_UNREACHABLE_RETURN(false);
+}
+
+bool AOTCompiledContext::writeBackScopeObjectPropertyLookup(uint index, void *source) const
+{
+ QV4::Lookup *l = compilationUnit->runtimeLookups + index;
+
+ ObjectPropertyResult result = ObjectPropertyResult::NeedsInit;
+ if (l->qmlContextPropertyGetter == QV4::QQmlContextWrapper::lookupScopeObjectProperty)
+ result = writeBackObjectProperty(l, qmlScopeObject, source);
+ else if (l->qmlContextPropertyGetter == QV4::QQmlContextWrapper::lookupScopeFallbackProperty)
+ result = writeBackFallbackProperty(l, qmlScopeObject, source);
+ else
+ return false;
+
+ switch (result) {
+ case ObjectPropertyResult::NeedsInit:
+ return false;
+ case ObjectPropertyResult::Deleted: // Silently omit the write back. Same as interpreter
+ case ObjectPropertyResult::OK:
+ return true;
+ }
+
+ Q_UNREACHABLE_RETURN(false);
+}
+
+void AOTCompiledContext::initLoadScopeObjectPropertyLookup(uint index, QMetaType type) const
+{
+ QV4::ExecutionEngine *v4 = engine->handle();
+ QV4::Lookup *l = compilationUnit->runtimeLookups + index;
+
+ if (v4->hasException) {
+ amendException(v4);
+ return;
+ }
+
+ switch (initObjectLookup(this, l, qmlScopeObject, type)) {
+ case ObjectLookupResult::ObjectAsVariant:
+ case ObjectLookupResult::Object:
+ l->qmlContextPropertyGetter = QV4::QQmlContextWrapper::lookupScopeObjectProperty;
+ break;
+ case ObjectLookupResult::FallbackAsVariant:
+ case ObjectLookupResult::Fallback:
+ l->qmlContextPropertyGetter = QV4::QQmlContextWrapper::lookupScopeFallbackProperty;
+ break;
+ case ObjectLookupResult::Failure:
+ v4->throwTypeError();
+ break;
+ }
+}
+
+bool AOTCompiledContext::loadSingletonLookup(uint index, void *target) const
+{
+ QV4::Lookup *l = compilationUnit->runtimeLookups + index;
+ QV4::Scope scope(engine->handle());
+
+ if (l->qmlContextPropertyGetter == QV4::QQmlContextWrapper::lookupSingleton) {
+ QV4::Scoped<QV4::QQmlTypeWrapper> wrapper(
+ scope, l->qmlContextSingletonLookup.singletonObject);
+
+ // We don't handle non-QObject singletons (as those can't be declared in qmltypes anyway)
+ Q_ASSERT(wrapper);
+ *static_cast<QObject **>(target) = wrapper->object();
+ return true;
+ }
+
+ return false;
+}
+
+using QmlContextPropertyGetter
+ = QV4::ReturnedValue (*)(QV4::Lookup *l, QV4::ExecutionEngine *engine, QV4::Value *thisObject);
+
+template<QmlContextPropertyGetter qmlContextPropertyGetter>
+static void initTypeWrapperLookup(
+ const AOTCompiledContext *context, QV4::Lookup *l, uint importNamespace)
+{
+ Q_ASSERT(!context->engine->hasError());
+ if (importNamespace != AOTCompiledContext::InvalidStringId) {
+ QV4::Scope scope(context->engine->handle());
+ QV4::ScopedString import(scope, context->compilationUnit->runtimeStrings[importNamespace]);
+
+ QQmlTypeLoader *typeLoader = scope.engine->typeLoader();
+ Q_ASSERT(typeLoader);
+ if (const QQmlImportRef *importRef
+ = context->qmlContext->imports()->query(import, typeLoader).importNamespace) {
+
+ QV4::Scoped<QV4::QQmlTypeWrapper> wrapper(
+ scope, QV4::QQmlTypeWrapper::create(
+ scope.engine, nullptr, context->qmlContext->imports(), importRef));
+ wrapper = l->qmlContextPropertyGetter(l, context->engine->handle(), wrapper);
+ l->qmlContextPropertyGetter = qmlContextPropertyGetter;
+ if (qmlContextPropertyGetter == QV4::QQmlContextWrapper::lookupSingleton)
+ l->qmlContextSingletonLookup.singletonObject.set(scope.engine, wrapper->heapObject());
+ else if (qmlContextPropertyGetter == QV4::QQmlContextWrapper::lookupType)
+ l->qmlTypeLookup.qmlTypeWrapper.set(scope.engine, wrapper->heapObject());
+ return;
+ }
+ scope.engine->throwTypeError();
+ } else {
+ QV4::ExecutionEngine *v4 = context->engine->handle();
+ l->qmlContextPropertyGetter(l, v4, nullptr);
+ if (l->qmlContextPropertyGetter != qmlContextPropertyGetter) {
+ const QString error
+ = QLatin1String(qmlContextPropertyGetter
+ == QV4::QQmlContextWrapper::lookupSingleton
+ ? "%1 was a singleton at compile time, "
+ "but is not a singleton anymore."
+ : "%1 was not a singleton at compile time, "
+ "but is a singleton now.")
+ .arg(context->compilationUnit->runtimeStrings[l->nameIndex]->toQString());
+ v4->throwTypeError(error);
+ }
+ }
+}
+
+void AOTCompiledContext::initLoadSingletonLookup(uint index, uint importNamespace) const
+{
+ QV4::Lookup *l = compilationUnit->runtimeLookups + index;
+ initTypeWrapperLookup<QV4::QQmlContextWrapper::lookupSingleton>(this, l, importNamespace);
+}
+
+bool AOTCompiledContext::loadAttachedLookup(uint index, QObject *object, void *target) const
+{
+ QV4::Lookup *l = compilationUnit->runtimeLookups + index;
+ if (l->getter != QV4::QObjectWrapper::lookupAttached)
+ return false;
+
+ QV4::Scope scope(engine->handle());
+ QV4::Scoped<QV4::QQmlTypeWrapper> wrapper(scope, l->qmlTypeLookup.qmlTypeWrapper);
+ Q_ASSERT(wrapper);
+ *static_cast<QObject **>(target) = qmlAttachedPropertiesObject(
+ object, wrapper->d()->type().attachedPropertiesFunction(
+ QQmlEnginePrivate::get(qmlEngine())));
+ return true;
+}
+
+void AOTCompiledContext::initLoadAttachedLookup(
+ uint index, uint importNamespace, QObject *object) const
+{
+ QV4::Lookup *l = compilationUnit->runtimeLookups + index;
+ QV4::Scope scope(engine->handle());
+ QV4::ScopedString name(scope, compilationUnit->runtimeStrings[l->nameIndex]);
+
+ QQmlType type;
+ QQmlTypeLoader *typeLoader = scope.engine->typeLoader();
+ Q_ASSERT(typeLoader);
+ if (importNamespace != InvalidStringId) {
+ QV4::ScopedString import(scope, compilationUnit->runtimeStrings[importNamespace]);
+ if (const QQmlImportRef *importRef
+ = qmlContext->imports()->query(import, typeLoader).importNamespace) {
+ type = qmlContext->imports()->query(name, importRef, typeLoader).type;
+ }
+ } else {
+ type = qmlContext->imports()->query<QQmlImport::AllowRecursion>(name, typeLoader).type;
+ }
+
+ if (!type.isValid()) {
+ scope.engine->throwTypeError();
+ return;
+ }
+
+ QV4::Scoped<QV4::QQmlTypeWrapper> wrapper(
+ scope, QV4::QQmlTypeWrapper::create(scope.engine, object, type,
+ QV4::Heap::QQmlTypeWrapper::ExcludeEnums));
+
+ l->qmlTypeLookup.qmlTypeWrapper.set(scope.engine, wrapper->d());
+ l->getter = QV4::QObjectWrapper::lookupAttached;
+}
+
+bool AOTCompiledContext::loadTypeLookup(uint index, void *target) const
+{
+ QV4::Lookup *l = compilationUnit->runtimeLookups + index;
+ if (l->qmlContextPropertyGetter != QV4::QQmlContextWrapper::lookupType)
+ return false;
+
+ const QV4::Heap::QQmlTypeWrapper *typeWrapper = static_cast<const QV4::Heap::QQmlTypeWrapper *>(
+ l->qmlTypeLookup.qmlTypeWrapper.get());
+
+ QMetaType metaType = typeWrapper->type().typeId();
+ *static_cast<const QMetaObject **>(target)
+ = QQmlMetaType::metaObjectForType(metaType).metaObject();
+ return true;
+}
+
+void AOTCompiledContext::initLoadTypeLookup(uint index, uint importNamespace) const
+{
+ QV4::Lookup *l = compilationUnit->runtimeLookups + index;
+ initTypeWrapperLookup<QV4::QQmlContextWrapper::lookupType>(this, l, importNamespace);
+}
+
+bool AOTCompiledContext::getObjectLookup(uint index, QObject *object, void *target) const
+{
+ QV4::Lookup *l = compilationUnit->runtimeLookups + index;
+ const auto doThrow = [&]() {
+ engine->handle()->throwTypeError(
+ QStringLiteral("Cannot read property '%1' of null")
+ .arg(compilationUnit->runtimeStrings[l->nameIndex]->toQString()));
+ return false;
+ };
+
+ if (!object)
+ return doThrow();
+
+ ObjectPropertyResult result = ObjectPropertyResult::NeedsInit;
+ if (l->getter == QV4::Lookup::getterQObject)
+ result = loadObjectProperty(l, object, target, this);
+ else if (l->getter == QV4::Lookup::getterFallback)
+ result = loadFallbackProperty(l, object, target, this);
+ else if (l->getter == QV4::Lookup::getterQObjectAsVariant)
+ result = loadObjectAsVariant(l, object, target, this);
+ else if (l->getter == QV4::Lookup::getterFallbackAsVariant)
+ result = loadFallbackAsVariant(l, object, target, this);
+ else
+ return false;
+
+ switch (result) {
+ case ObjectPropertyResult::Deleted:
+ return doThrow();
+ case ObjectPropertyResult::NeedsInit:
+ return false;
+ case ObjectPropertyResult::OK:
+ return true;
+ }
+
+ Q_UNREACHABLE_RETURN(false);
+}
+
+bool AOTCompiledContext::writeBackObjectLookup(uint index, QObject *object, void *source) const
+{
+ QV4::Lookup *l = compilationUnit->runtimeLookups + index;
+ if (!object)
+ return true;
+
+ ObjectPropertyResult result = ObjectPropertyResult::NeedsInit;
+ if (l->getter == QV4::Lookup::getterQObject)
+ result = writeBackObjectProperty(l, object, source);
+ else if (l->getter == QV4::Lookup::getterFallback)
+ result = writeBackFallbackProperty(l, object, source);
+ else if (l->getter == QV4::Lookup::getterQObjectAsVariant)
+ result = writeBackObjectAsVariant(l, object, source);
+ else if (l->getter == QV4::Lookup::getterFallbackAsVariant)
+ result = writeBackFallbackAsVariant(l, object, source);
+ else
+ return false;
+
+ switch (result) {
+ case ObjectPropertyResult::NeedsInit:
+ return false;
+ case ObjectPropertyResult::Deleted: // Silently omit the write back
+ case ObjectPropertyResult::OK:
+ return true;
+ }
+
+ Q_UNREACHABLE_RETURN(false);
+}
+
+void AOTCompiledContext::initGetObjectLookup(uint index, QObject *object, QMetaType type) const
+{
+ QV4::ExecutionEngine *v4 = engine->handle();
+ if (v4->hasException) {
+ amendException(v4);
+ } else {
+ QV4::Lookup *l = compilationUnit->runtimeLookups + index;
+ switch (initObjectLookup(this, l, object, type)) {
+ case ObjectLookupResult::Object:
+ l->getter = QV4::Lookup::getterQObject;
+ break;
+ case ObjectLookupResult::ObjectAsVariant:
+ l->getter = QV4::Lookup::getterQObjectAsVariant;
+ break;
+ case ObjectLookupResult::Fallback:
+ l->getter = QV4::Lookup::getterFallback;
+ break;
+ case ObjectLookupResult::FallbackAsVariant:
+ l->getter = QV4::Lookup::getterFallbackAsVariant;
+ break;
+ case ObjectLookupResult::Failure:
+ engine->handle()->throwTypeError();
+ break;
+ }
+ }
+}
+
+bool AOTCompiledContext::getValueLookup(uint index, void *value, void *target) const
+{
+ Q_ASSERT(value);
+
+ QV4::Lookup *l = compilationUnit->runtimeLookups + index;
+ if (l->getter != QV4::QQmlValueTypeWrapper::lookupGetter)
+ return false;
+
+ const QMetaObject *metaObject
+ = reinterpret_cast<const QMetaObject *>(l->qgadgetLookup.metaObject - 1);
+ Q_ASSERT(metaObject);
+
+ void *args[] = { target, nullptr };
+ metaObject->d.static_metacall(
+ reinterpret_cast<QObject*>(value), QMetaObject::ReadProperty,
+ l->qgadgetLookup.coreIndex, args);
+ return true;
+}
+
+bool AOTCompiledContext::writeBackValueLookup(uint index, void *value, void *source) const
+{
+ Q_ASSERT(value);
+
+ QV4::Lookup *l = compilationUnit->runtimeLookups + index;
+ if (l->getter != QV4::QQmlValueTypeWrapper::lookupGetter)
+ return false;
+
+ const QMetaObject *metaObject
+ = reinterpret_cast<const QMetaObject *>(l->qgadgetLookup.metaObject - 1);
+ Q_ASSERT(metaObject);
+
+ void *args[] = { source, nullptr };
+ metaObject->d.static_metacall(
+ reinterpret_cast<QObject*>(value), QMetaObject::WriteProperty,
+ l->qgadgetLookup.coreIndex, args);
+ return true;
+}
+
+void AOTCompiledContext::initGetValueLookup(
+ uint index, const QMetaObject *metaObject, QMetaType type) const
+{
+ Q_ASSERT(!engine->hasError());
+ QV4::Lookup *l = compilationUnit->runtimeLookups + index;
+ if (initValueLookup(l, compilationUnit, metaObject, type))
+ l->getter = QV4::QQmlValueTypeWrapper::lookupGetter;
+ else
+ engine->handle()->throwTypeError();
+}
+
+bool AOTCompiledContext::getEnumLookup(uint index, void *target) const
+{
+ QV4::Lookup *l = compilationUnit->runtimeLookups + index;
+ if (l->getter != QV4::QQmlTypeWrapper::lookupEnumValue)
+ return false;
+ const bool isUnsigned
+ = l->qmlEnumValueLookup.metaType->flags & QMetaType::IsUnsignedEnumeration;
+ const QV4::ReturnedValue encoded = l->qmlEnumValueLookup.encodedEnumValue;
+ switch (l->qmlEnumValueLookup.metaType->size) {
+ case 1:
+ if (isUnsigned)
+ *static_cast<quint8 *>(target) = encoded;
+ else
+ *static_cast<qint8 *>(target) = encoded;
+ return true;
+ case 2:
+ if (isUnsigned)
+ *static_cast<quint16 *>(target) = encoded;
+ else
+ *static_cast<qint16 *>(target) = encoded;
+ return true;
+ case 4:
+ if (isUnsigned)
+ *static_cast<quint32 *>(target) = encoded;
+ else
+ *static_cast<qint32 *>(target) = encoded;
+ return true;
+ case 8:
+ if (isUnsigned)
+ *static_cast<quint64 *>(target) = encoded;
+ else
+ *static_cast<qint64 *>(target) = encoded;
+ return true;
+ default:
+ break;
+ }
+
+ return false;
+}
+
+void AOTCompiledContext::initGetEnumLookup(
+ uint index, const QMetaObject *metaObject,
+ const char *enumerator, const char *enumValue) const
+{
+ Q_ASSERT(!engine->hasError());
+ QV4::Lookup *l = compilationUnit->runtimeLookups + index;
+ if (!metaObject) {
+ engine->handle()->throwTypeError(
+ QStringLiteral("Cannot read property '%1' of undefined")
+ .arg(QString::fromUtf8(enumValue)));
+ return;
+ }
+ const int enumIndex = metaObject->indexOfEnumerator(enumerator);
+ const QMetaEnum metaEnum = metaObject->enumerator(enumIndex);
+ l->qmlEnumValueLookup.encodedEnumValue = metaEnum.keyToValue(enumValue);
+ l->qmlEnumValueLookup.metaType = metaEnum.metaType().iface();
+ l->getter = QV4::QQmlTypeWrapper::lookupEnumValue;
+}
+
+bool AOTCompiledContext::setObjectLookup(uint index, QObject *object, void *value) const
+{
+ const auto doThrow = [&]() {
+ engine->handle()->throwTypeError(
+ QStringLiteral("Value is null and could not be converted to an object"));
+ return false;
+ };
+
+ if (!object)
+ return doThrow();
+
+ QV4::Lookup *l = compilationUnit->runtimeLookups + index;
+ ObjectPropertyResult result = ObjectPropertyResult::NeedsInit;
+ if (l->setter == QV4::Lookup::setterQObject)
+ result = storeObjectProperty(l, object, value);
+ else if (l->setter == QV4::Lookup::setterFallback)
+ result = storeFallbackProperty(l, object, value);
+ else if (l->setter == QV4::Lookup::setterQObjectAsVariant)
+ result = storeObjectAsVariant(engine->handle(), l, object, value);
+ else if (l->setter == QV4::Lookup::setterFallbackAsVariant)
+ result = storeFallbackAsVariant(engine->handle(), l, object, value);
+ else
+ return false;
+
+ switch (result) {
+ case ObjectPropertyResult::Deleted:
+ return doThrow();
+ case ObjectPropertyResult::NeedsInit:
+ return false;
+ case ObjectPropertyResult::OK:
+ return true;
+ }
+
+ Q_UNREACHABLE_RETURN(false);
+}
+
+void AOTCompiledContext::initSetObjectLookup(uint index, QObject *object, QMetaType type) const
+{
+ QV4::ExecutionEngine *v4 = engine->handle();
+ if (v4->hasException) {
+ amendException(v4);
+ } else {
+ QV4::Lookup *l = compilationUnit->runtimeLookups + index;
+ switch (initObjectLookup(this, l, object, type)) {
+ case ObjectLookupResult::Object:
+ l->setter = QV4::Lookup::setterQObject;
+ break;
+ case ObjectLookupResult::ObjectAsVariant:
+ l->setter = QV4::Lookup::setterQObjectAsVariant;
+ break;
+ case ObjectLookupResult::Fallback:
+ l->setter = QV4::Lookup::setterFallback;
+ break;
+ case ObjectLookupResult::FallbackAsVariant:
+ l->setter = QV4::Lookup::setterFallbackAsVariant;
+ break;
+ case ObjectLookupResult::Failure:
+ engine->handle()->throwTypeError();
+ break;
+ }
+ }
+}
+
+bool AOTCompiledContext::setValueLookup(
+ uint index, void *target, void *value) const
+{
+ QV4::Lookup *l = compilationUnit->runtimeLookups + index;
+ if (l->setter != QV4::QQmlValueTypeWrapper::lookupSetter)
+ return false;
+
+ const QMetaObject *metaObject
+ = reinterpret_cast<const QMetaObject *>(l->qgadgetLookup.metaObject - 1);
+
+ void *args[] = { value, nullptr };
+ metaObject->d.static_metacall(
+ reinterpret_cast<QObject*>(target), QMetaObject::WriteProperty,
+ l->qgadgetLookup.coreIndex, args);
+ return true;
+}
+
+void AOTCompiledContext::initSetValueLookup(uint index, const QMetaObject *metaObject,
+ QMetaType type) const
+{
+ Q_ASSERT(!engine->hasError());
+ QV4::Lookup *l = compilationUnit->runtimeLookups + index;
+ if (initValueLookup(l, compilationUnit, metaObject, type))
+ l->setter = QV4::QQmlValueTypeWrapper::lookupSetter;
+ else
+ engine->handle()->throwTypeError();
+}
+
+} // namespace QQmlPrivate
+
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqml.h b/src/qml/qml/qqml.h
index 078bd93d25..3e6441bfa7 100644
--- a/src/qml/qml/qqml.h
+++ b/src/qml/qml/qqml.h
@@ -1,47 +1,12 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQML_H
#define QQML_H
#include <QtQml/qqmlprivate.h>
#include <QtQml/qjsvalue.h>
+#include <QtQml/qqmlregistration.h>
#include <QtCore/qbytearray.h>
#include <QtCore/qmetaobject.h>
@@ -51,14 +16,8 @@
#define QML_VERSION 0x020000
#define QML_VERSION_STR "2.0"
-#define QML_PRIVATE_NAMESPACE \
- QT_PREPEND_NAMESPACE(QQmlPrivate)
-
-#define QML_REGISTER_TYPES_AND_REVISIONS \
- QT_PREPEND_NAMESPACE(qmlRegisterTypesAndRevisions)
-
#define QML_DECLARE_TYPE(TYPE) \
- Q_DECLARE_METATYPE(TYPE *) \
+ Q_DECLARE_METATYPE(TYPE*) \
Q_DECLARE_METATYPE(QQmlListProperty<TYPE>)
#define QML_DECLARE_TYPE_HASMETATYPE(TYPE) \
@@ -70,95 +29,6 @@
#define QML_DECLARE_INTERFACE_HASMETATYPE(INTERFACE) \
QML_DECLARE_TYPE_HASMETATYPE(INTERFACE)
-#define QML_ELEMENT \
- Q_CLASSINFO("QML.Element", "auto")
-
-#define QML_ANONYMOUS \
- Q_CLASSINFO("QML.Element", "anonymous")
-
-#define QML_NAMED_ELEMENT(NAME) \
- Q_CLASSINFO("QML.Element", #NAME)
-
-#define QML_VALUE_TYPE(NAME) \
- Q_CLASSINFO("QML.Element", #NAME) \
- QML_UNCREATABLE("Value types cannot be created.")
-
-#define QML_UNCREATABLE(REASON) \
- Q_CLASSINFO("QML.Creatable", "false") \
- Q_CLASSINFO("QML.UncreatableReason", REASON)
-
-#define QML_SINGLETON \
- Q_CLASSINFO("QML.Singleton", "true") \
- enum class QmlIsSingleton {yes = true}; \
- template<typename, typename> friend struct QML_PRIVATE_NAMESPACE::QmlSingleton; \
- template<typename T, typename... Args> \
- friend void QML_REGISTER_TYPES_AND_REVISIONS(const char *uri, int versionMajor, QList<int> *);
-
-#define QML_SEQUENTIAL_CONTAINER(VALUE_TYPE) \
- Q_CLASSINFO("QML.Sequence", #VALUE_TYPE) \
- using QmlSequenceValueType = VALUE_TYPE; \
- enum class QmlIsSequence {yes = true}; \
- template<typename, typename> friend struct QML_PRIVATE_NAMESPACE::QmlSequence; \
- template<typename T, typename... Args> \
- friend void QML_REGISTER_TYPES_AND_REVISIONS(const char *uri, int versionMajor, QList<int> *);
-
-#define QML_ADDED_IN_MINOR_VERSION(VERSION) \
- Q_CLASSINFO("QML.AddedInVersion", Q_REVISION(VERSION))
-
-#define QML_ADDED_IN_VERSION(MAJOR, MINOR) \
- Q_CLASSINFO("QML.AddedInVersion", Q_REVISION(MAJOR, MINOR))
-
-#define QML_REMOVED_IN_MINOR_VERSION(VERSION) \
- Q_CLASSINFO("QML.RemovedInVersion", Q_REVISION(VERSION))
-
-#define QML_REMOVED_IN_VERSION(MAJOR, MINOR) \
- Q_CLASSINFO("QML.RemovedInVersion", Q_REVISION(MAJOR, MINOR))
-
-#define QML_ATTACHED(ATTACHED_TYPE) \
- Q_CLASSINFO("QML.Attached", #ATTACHED_TYPE) \
- using QmlAttachedType = ATTACHED_TYPE; \
- template<class, class, bool> friend struct QML_PRIVATE_NAMESPACE::QmlAttached; \
- template<class> friend struct QML_PRIVATE_NAMESPACE::QmlAttachedAccessor;
-
-#define QML_EXTENDED(EXTENDED_TYPE) \
- Q_CLASSINFO("QML.Extended", #EXTENDED_TYPE) \
- using QmlExtendedType = EXTENDED_TYPE; \
- template<class, class> friend struct QML_PRIVATE_NAMESPACE::QmlExtended; \
- template<typename T, typename... Args> \
- friend void QML_REGISTER_TYPES_AND_REVISIONS(const char *uri, int versionMajor, QList<int> *);
-
-#define QML_EXTENDED_NAMESPACE(EXTENDED_NAMESPACE) \
- Q_CLASSINFO("QML.Extended", #EXTENDED_NAMESPACE) \
- static constexpr const QMetaObject *qmlExtendedNamespace() { return &EXTENDED_NAMESPACE::staticMetaObject; } \
- template<class, class> friend struct QML_PRIVATE_NAMESPACE::QmlExtendedNamespace; \
- template<typename T, typename... Args> \
- friend void QML_REGISTER_TYPES_AND_REVISIONS(const char *uri, int versionMajor, QList<int> *);
-
-#define QML_FOREIGN(FOREIGN_TYPE) \
- Q_CLASSINFO("QML.Foreign", #FOREIGN_TYPE) \
- using QmlForeignType = FOREIGN_TYPE; \
- template<class, class> friend struct QML_PRIVATE_NAMESPACE::QmlResolved; \
- template<typename T, typename... Args> \
- friend void QML_REGISTER_TYPES_AND_REVISIONS(const char *uri, int versionMajor, QList<int> *);
-
-#define QML_FOREIGN_NAMESPACE(FOREIGN_NAMESPACE) \
- Q_CLASSINFO("QML.Foreign", #FOREIGN_NAMESPACE)
-
-#define QML_INTERFACE \
- Q_CLASSINFO("QML.Element", "anonymous") \
- enum class QmlIsInterface {yes = true}; \
- template<typename, typename> friend struct QML_PRIVATE_NAMESPACE::QmlInterface; \
- template<typename T, typename... Args> \
- friend void QML_REGISTER_TYPES_AND_REVISIONS(const char *uri, int versionMajor, QList<int> *);
-
-#define QML_IMPLEMENTS_INTERFACES(INTERFACES) \
- Q_INTERFACES(INTERFACES) \
- enum class QmlIsInterface {yes = false}; \
- template<typename, typename> friend struct QML_PRIVATE_NAMESPACE::QmlInterface;
-
-#define QML_UNAVAILABLE \
- QML_FOREIGN(QQmlTypeNotAvailable)
-
enum { /* TYPEINFO flags */
QML_HAS_ATTACHED_PROPERTIES = 0x01
};
@@ -186,7 +56,7 @@ template<typename T>
int qmlRegisterAnonymousType(const char *uri, int versionMajor)
{
QQmlPrivate::RegisterType type = {
- 0,
+ QQmlPrivate::RegisterType::CurrentVersion,
QQmlPrivate::QmlMetaType<T>::self(),
QQmlPrivate::QmlMetaType<T>::list(),
0,
@@ -207,20 +77,78 @@ int qmlRegisterAnonymousType(const char *uri, int versionMajor)
nullptr, nullptr,
nullptr,
- QTypeRevision::zero()
+ QTypeRevision::zero(),
+ QQmlPrivate::StaticCastSelector<T,QQmlFinalizerHook>::cast(),
+ QQmlPrivate::ValueTypeCreationMethod::None,
+ };
+
+ return QQmlPrivate::qmlregister(QQmlPrivate::TypeRegistration, &type);
+}
+
+//! \internal
+template<typename T, int metaObjectRevisionMinor>
+int qmlRegisterAnonymousType(const char *uri, int versionMajor)
+{
+ QQmlPrivate::RegisterType type = {
+ QQmlPrivate::RegisterType::CurrentVersion,
+ QQmlPrivate::QmlMetaType<T>::self(),
+ QQmlPrivate::QmlMetaType<T>::list(),
+ 0,
+ nullptr,
+ nullptr,
+ QString(),
+ QQmlPrivate::ValueType<T, void>::create,
+
+ uri,
+ QTypeRevision::fromVersion(versionMajor, 0),
+ nullptr,
+ QQmlPrivate::StaticMetaObject<T>::staticMetaObject(),
+
+ QQmlPrivate::attachedPropertiesFunc<T>(),
+ QQmlPrivate::attachedPropertiesMetaObject<T>(),
+
+ QQmlPrivate::StaticCastSelector<T, QQmlParserStatus>::cast(),
+ QQmlPrivate::StaticCastSelector<T, QQmlPropertyValueSource>::cast(),
+ QQmlPrivate::StaticCastSelector<T, QQmlPropertyValueInterceptor>::cast(),
+
+ nullptr,
+ nullptr,
+
+ nullptr,
+ QTypeRevision::fromMinorVersion(metaObjectRevisionMinor),
+ QQmlPrivate::StaticCastSelector<T, QQmlFinalizerHook>::cast(),
+ QQmlPrivate::ValueTypeCreationMethod::None,
};
return QQmlPrivate::qmlregister(QQmlPrivate::TypeRegistration, &type);
}
+//! \internal
+template<typename T>
+void qmlRegisterAnonymousTypesAndRevisions(const char *uri, int versionMajor)
+{
+ // Anonymous types are not creatable, no need to warn about missing acceptable constructors.
+ QQmlPrivate::qmlRegisterTypeAndRevisions<T, void>(
+ uri, versionMajor, QQmlPrivate::StaticMetaObject<T>::staticMetaObject(), nullptr,
+ nullptr, true);
+}
+
+class QQmlTypeNotAvailable : public QObject
+{
+ Q_OBJECT
+ QML_NAMED_ELEMENT(TypeNotAvailable)
+ QML_ADDED_IN_VERSION(2, 15)
+ QML_UNCREATABLE("Type not available.")
+};
+
int Q_QML_EXPORT qmlRegisterTypeNotAvailable(const char *uri, int versionMajor, int versionMinor,
- const char *qmlName, const QString& message);
+ const char *qmlName, const QString &message);
template<typename T>
int qmlRegisterUncreatableType(const char *uri, int versionMajor, int versionMinor, const char *qmlName, const QString& reason)
{
QQmlPrivate::RegisterType type = {
- 0,
+ QQmlPrivate::RegisterType::CurrentVersion,
QQmlPrivate::QmlMetaType<T>::self(),
QQmlPrivate::QmlMetaType<T>::list(),
0,
@@ -242,7 +170,9 @@ int qmlRegisterUncreatableType(const char *uri, int versionMajor, int versionMin
nullptr, nullptr,
nullptr,
- QTypeRevision::zero()
+ QTypeRevision::zero(),
+ QQmlPrivate::StaticCastSelector<T,QQmlFinalizerHook>::cast(),
+ QQmlPrivate::ValueTypeCreationMethod::None,
};
return QQmlPrivate::qmlregister(QQmlPrivate::TypeRegistration, &type);
@@ -252,7 +182,7 @@ template<typename T, int metaObjectRevision>
int qmlRegisterUncreatableType(const char *uri, int versionMajor, int versionMinor, const char *qmlName, const QString& reason)
{
QQmlPrivate::RegisterType type = {
- 0,
+ QQmlPrivate::RegisterType::CurrentVersion,
QQmlPrivate::QmlMetaType<T>::self(),
QQmlPrivate::QmlMetaType<T>::list(),
0,
@@ -274,7 +204,9 @@ int qmlRegisterUncreatableType(const char *uri, int versionMajor, int versionMin
nullptr, nullptr,
nullptr,
- QTypeRevision::fromMinorVersion(metaObjectRevision)
+ QTypeRevision::fromMinorVersion(metaObjectRevision),
+ QQmlPrivate::StaticCastSelector<T,QQmlFinalizerHook>::cast(),
+ QQmlPrivate::ValueTypeCreationMethod::None,
};
return QQmlPrivate::qmlregister(QQmlPrivate::TypeRegistration, &type);
@@ -291,7 +223,7 @@ int qmlRegisterExtendedUncreatableType(const char *uri, int versionMajor, int ve
}
QQmlPrivate::RegisterType type = {
- 0,
+ QQmlPrivate::RegisterType::CurrentVersion,
QQmlPrivate::QmlMetaType<T>::self(),
QQmlPrivate::QmlMetaType<T>::list(),
0,
@@ -313,7 +245,9 @@ int qmlRegisterExtendedUncreatableType(const char *uri, int versionMajor, int ve
QQmlPrivate::ExtendedType<E>::createParent, QQmlPrivate::ExtendedType<E>::staticMetaObject(),
nullptr,
- QTypeRevision::zero()
+ QTypeRevision::zero(),
+ QQmlPrivate::StaticCastSelector<T,QQmlFinalizerHook>::cast(),
+ QQmlPrivate::ValueTypeCreationMethod::None,
};
return QQmlPrivate::qmlregister(QQmlPrivate::TypeRegistration, &type);
@@ -330,7 +264,7 @@ int qmlRegisterExtendedUncreatableType(const char *uri, int versionMajor, int ve
}
QQmlPrivate::RegisterType type = {
- 0,
+ QQmlPrivate::RegisterType::CurrentVersion,
QQmlPrivate::QmlMetaType<T>::self(),
QQmlPrivate::QmlMetaType<T>::list(),
0,
@@ -352,7 +286,9 @@ int qmlRegisterExtendedUncreatableType(const char *uri, int versionMajor, int ve
QQmlPrivate::ExtendedType<E>::createParent, QQmlPrivate::ExtendedType<E>::staticMetaObject(),
nullptr,
- QTypeRevision::fromMinorVersion(metaObjectRevision)
+ QTypeRevision::fromMinorVersion(metaObjectRevision),
+ QQmlPrivate::StaticCastSelector<T,QQmlFinalizerHook>::cast(),
+ QQmlPrivate::ValueTypeCreationMethod::None,
};
return QQmlPrivate::qmlregister(QQmlPrivate::TypeRegistration, &type);
@@ -363,8 +299,12 @@ Q_QML_EXPORT int qmlRegisterUncreatableMetaObject(const QMetaObject &staticMetaO
template<typename T>
int qmlRegisterType(const char *uri, int versionMajor, int versionMinor, const char *qmlName)
{
+ static_assert(!std::is_abstract_v<T>,
+ "It is not possible to register an abstract type with qmlRegisterType. "
+ "Maybe you wanted qmlRegisterUncreatableType or qmlRegisterInterface?");
+
QQmlPrivate::RegisterType type = {
- 0,
+ QQmlPrivate::RegisterType::CurrentVersion,
QQmlPrivate::QmlMetaType<T>::self(),
QQmlPrivate::QmlMetaType<T>::list(),
sizeof(T), QQmlPrivate::Constructors<T>::createInto, nullptr,
@@ -384,7 +324,9 @@ int qmlRegisterType(const char *uri, int versionMajor, int versionMinor, const c
nullptr, nullptr,
nullptr,
- QTypeRevision::zero()
+ QTypeRevision::zero(),
+ QQmlPrivate::StaticCastSelector<T,QQmlFinalizerHook>::cast(),
+ QQmlPrivate::ValueTypeCreationMethod::None,
};
return QQmlPrivate::qmlregister(QQmlPrivate::TypeRegistration, &type);
@@ -393,8 +335,12 @@ int qmlRegisterType(const char *uri, int versionMajor, int versionMinor, const c
template<typename T, int metaObjectRevision>
int qmlRegisterType(const char *uri, int versionMajor, int versionMinor, const char *qmlName)
{
+ static_assert(!std::is_abstract_v<T>,
+ "It is not possible to register an abstract type with qmlRegisterType. "
+ "Maybe you wanted qmlRegisterUncreatableType or qmlRegisterInterface?");
+
QQmlPrivate::RegisterType type = {
- 0,
+ QQmlPrivate::RegisterType::CurrentVersion,
QQmlPrivate::QmlMetaType<T>::self(),
QQmlPrivate::QmlMetaType<T>::list(),
sizeof(T), QQmlPrivate::Constructors<T>::createInto, nullptr,
@@ -414,7 +360,9 @@ int qmlRegisterType(const char *uri, int versionMajor, int versionMinor, const c
nullptr, nullptr,
nullptr,
- QTypeRevision::fromMinorVersion(metaObjectRevision)
+ QTypeRevision::fromMinorVersion(metaObjectRevision),
+ QQmlPrivate::StaticCastSelector<T,QQmlFinalizerHook>::cast(),
+ QQmlPrivate::ValueTypeCreationMethod::None,
};
return QQmlPrivate::qmlregister(QQmlPrivate::TypeRegistration, &type);
@@ -424,7 +372,7 @@ template<typename T, int metaObjectRevision>
int qmlRegisterRevision(const char *uri, int versionMajor, int versionMinor)
{
QQmlPrivate::RegisterType type = {
- 0,
+ QQmlPrivate::RegisterType::CurrentVersion,
QQmlPrivate::QmlMetaType<T>::self(),
QQmlPrivate::QmlMetaType<T>::list(),
sizeof(T), QQmlPrivate::Constructors<T>::createInto, nullptr,
@@ -444,7 +392,9 @@ int qmlRegisterRevision(const char *uri, int versionMajor, int versionMinor)
nullptr, nullptr,
nullptr,
- QTypeRevision::fromMinorVersion(metaObjectRevision)
+ QTypeRevision::fromMinorVersion(metaObjectRevision),
+ QQmlPrivate::StaticCastSelector<T,QQmlFinalizerHook>::cast(),
+ QQmlPrivate::ValueTypeCreationMethod::None,
};
return QQmlPrivate::qmlregister(QQmlPrivate::TypeRegistration, &type);
@@ -453,8 +403,15 @@ int qmlRegisterRevision(const char *uri, int versionMajor, int versionMinor)
template<typename T, typename E>
int qmlRegisterExtendedType(const char *uri, int versionMajor)
{
+ static_assert(!std::is_abstract_v<T>,
+ "It is not possible to register an extension to an abstract type with qmlRegisterExtendedType.");
+
+ static_assert(!std::is_abstract_v<E>,
+ "It is not possible to register an abstract type with qmlRegisterExtendedType. "
+ "Maybe you wanted qmlRegisterExtendedUncreatableType?");
+
QQmlPrivate::RegisterType type = {
- 0,
+ QQmlPrivate::RegisterType::CurrentVersion,
QQmlPrivate::QmlMetaType<T>::self(),
QQmlPrivate::QmlMetaType<T>::list(),
0,
@@ -476,7 +433,9 @@ int qmlRegisterExtendedType(const char *uri, int versionMajor)
QQmlPrivate::ExtendedType<E>::createParent, QQmlPrivate::ExtendedType<E>::staticMetaObject(),
nullptr,
- QTypeRevision::zero()
+ QTypeRevision::zero(),
+ QQmlPrivate::StaticCastSelector<T,QQmlFinalizerHook>::cast(),
+ QQmlPrivate::ValueTypeCreationMethod::None,
};
return QQmlPrivate::qmlregister(QQmlPrivate::TypeRegistration, &type);
@@ -486,6 +445,13 @@ template<typename T, typename E>
int qmlRegisterExtendedType(const char *uri, int versionMajor, int versionMinor,
const char *qmlName)
{
+ static_assert(!std::is_abstract_v<T>,
+ "It is not possible to register an extension to an abstract type with qmlRegisterExtendedType.");
+
+ static_assert(!std::is_abstract_v<E>,
+ "It is not possible to register an abstract type with qmlRegisterExtendedType. "
+ "Maybe you wanted qmlRegisterExtendedUncreatableType?");
+
QQmlAttachedPropertiesFunc attached = QQmlPrivate::attachedPropertiesFunc<E>();
const QMetaObject * attachedMetaObject = QQmlPrivate::attachedPropertiesMetaObject<E>();
if (!attached) {
@@ -494,7 +460,7 @@ int qmlRegisterExtendedType(const char *uri, int versionMajor, int versionMinor,
}
QQmlPrivate::RegisterType type = {
- 0,
+ QQmlPrivate::RegisterType::CurrentVersion,
QQmlPrivate::QmlMetaType<T>::self(),
QQmlPrivate::QmlMetaType<T>::list(),
sizeof(T), QQmlPrivate::Constructors<T>::createInto, nullptr,
@@ -514,7 +480,9 @@ int qmlRegisterExtendedType(const char *uri, int versionMajor, int versionMinor,
QQmlPrivate::ExtendedType<E>::createParent, QQmlPrivate::ExtendedType<E>::staticMetaObject(),
nullptr,
- QTypeRevision::zero()
+ QTypeRevision::zero(),
+ QQmlPrivate::StaticCastSelector<T,QQmlFinalizerHook>::cast(),
+ QQmlPrivate::ValueTypeCreationMethod::None,
};
return QQmlPrivate::qmlregister(QQmlPrivate::TypeRegistration, &type);
@@ -542,8 +510,12 @@ template<typename T>
int qmlRegisterCustomType(const char *uri, int versionMajor, int versionMinor,
const char *qmlName, QQmlCustomParser *parser)
{
+ static_assert(!std::is_abstract_v<T>,
+ "It is not possible to register an abstract type with qmlRegisterCustomType. "
+ "Maybe you wanted qmlRegisterUncreatableType or qmlRegisterInterface?");
+
QQmlPrivate::RegisterType type = {
- 0,
+ QQmlPrivate::RegisterType::CurrentVersion,
QQmlPrivate::QmlMetaType<T>::self(),
QQmlPrivate::QmlMetaType<T>::list(),
sizeof(T), QQmlPrivate::Constructors<T>::createInto, nullptr,
@@ -563,7 +535,9 @@ int qmlRegisterCustomType(const char *uri, int versionMajor, int versionMinor,
nullptr, nullptr,
parser,
- QTypeRevision::zero()
+ QTypeRevision::zero(),
+ QQmlPrivate::StaticCastSelector<T,QQmlFinalizerHook>::cast(),
+ QQmlPrivate::ValueTypeCreationMethod::None,
};
return QQmlPrivate::qmlregister(QQmlPrivate::TypeRegistration, &type);
@@ -573,8 +547,12 @@ template<typename T, int metaObjectRevision>
int qmlRegisterCustomType(const char *uri, int versionMajor, int versionMinor,
const char *qmlName, QQmlCustomParser *parser)
{
+ static_assert(!std::is_abstract_v<T>,
+ "It is not possible to register an abstract type with qmlRegisterCustomType. "
+ "Maybe you wanted qmlRegisterUncreatableType or qmlRegisterInterface?");
+
QQmlPrivate::RegisterType type = {
- 0,
+ QQmlPrivate::RegisterType::CurrentVersion,
QQmlPrivate::QmlMetaType<T>::self(),
QQmlPrivate::QmlMetaType<T>::list(),
sizeof(T), QQmlPrivate::Constructors<T>::createInto, nullptr,
@@ -594,7 +572,9 @@ int qmlRegisterCustomType(const char *uri, int versionMajor, int versionMinor,
nullptr, nullptr,
parser,
- QTypeRevision::fromMinorVersion(metaObjectRevision)
+ QTypeRevision::fromMinorVersion(metaObjectRevision),
+ QQmlPrivate::StaticCastSelector<T,QQmlFinalizerHook>::cast(),
+ QQmlPrivate::ValueTypeCreationMethod::None,
};
return QQmlPrivate::qmlregister(QQmlPrivate::TypeRegistration, &type);
@@ -604,6 +584,12 @@ template<typename T, typename E>
int qmlRegisterCustomExtendedType(const char *uri, int versionMajor, int versionMinor,
const char *qmlName, QQmlCustomParser *parser)
{
+ static_assert(!std::is_abstract_v<T>,
+ "It is not possible to register an extension to an abstract type with qmlRegisterCustomExtendedType.");
+
+ static_assert(!std::is_abstract_v<E>,
+ "It is not possible to register an abstract type with qmlRegisterCustomExtendedType.");
+
QQmlAttachedPropertiesFunc attached = QQmlPrivate::attachedPropertiesFunc<E>();
const QMetaObject * attachedMetaObject = QQmlPrivate::attachedPropertiesMetaObject<E>();
if (!attached) {
@@ -612,7 +598,7 @@ int qmlRegisterCustomExtendedType(const char *uri, int versionMajor, int version
}
QQmlPrivate::RegisterType type = {
- 0,
+ QQmlPrivate::RegisterType::CurrentVersion,
QQmlPrivate::QmlMetaType<T>::self(),
QQmlPrivate::QmlMetaType<T>::list(),
sizeof(T), QQmlPrivate::Constructors<T>::createInto, nullptr,
@@ -632,7 +618,9 @@ int qmlRegisterCustomExtendedType(const char *uri, int versionMajor, int version
QQmlPrivate::ExtendedType<E>::createParent, QQmlPrivate::ExtendedType<E>::staticMetaObject(),
parser,
- QTypeRevision::zero()
+ QTypeRevision::zero(),
+ QQmlPrivate::StaticCastSelector<T,QQmlFinalizerHook>::cast(),
+ QQmlPrivate::ValueTypeCreationMethod::None,
};
return QQmlPrivate::qmlregister(QQmlPrivate::TypeRegistration, &type);
@@ -650,6 +638,7 @@ Q_QML_EXPORT QQmlAttachedPropertiesFunc qmlAttachedPropertiesFunction(QObject *,
const QMetaObject *);
Q_QML_EXPORT QObject *qmlAttachedPropertiesObject(QObject *, QQmlAttachedPropertiesFunc func,
bool create = true);
+Q_QML_EXPORT QObject *qmlExtendedObject(QObject *);
//The C++ version of protected namespaces in qmldir
Q_QML_EXPORT bool qmlProtectModule(const char* uri, int majVersion);
@@ -681,37 +670,25 @@ QObject *qmlAttachedPropertiesObject(const QObject *obj, bool create = true)
return qmlAttachedPropertiesObject(const_cast<QObject *>(obj), func, create);
}
-inline int qmlRegisterSingletonType(const char *uri, int versionMajor, int versionMinor, const char *typeName,
- QJSValue (*callback)(QQmlEngine *, QJSEngine *))
-{
- QQmlPrivate::RegisterSingletonType api = {
- 0,
-
- uri, QTypeRevision::fromVersion(versionMajor, versionMinor), typeName,
-
- callback,
- nullptr, nullptr, QMetaType(),
- nullptr, nullptr,
- QTypeRevision::zero()
- };
-
- return QQmlPrivate::qmlregister(QQmlPrivate::SingletonRegistration, &api);
-}
-
-template <typename T>
-inline int qmlRegisterSingletonType(
- const char *uri, int versionMajor, int versionMinor, const char *typeName,
- QObject *(*callback)(QQmlEngine *, QJSEngine *))
+#ifdef Q_QDOC
+int qmlRegisterSingletonType(
+ const char *uri, int versionMajor, int versionMinor, const char *typeName,
+ std::function<QJSValue(QQmlEngine *, QJSEngine *)> callback)
+#else
+template<typename F, typename std::enable_if<std::is_convertible<F, std::function<QJSValue(QQmlEngine *, QJSEngine *)>>::value, void>::type* = nullptr>
+int qmlRegisterSingletonType(
+ const char *uri, int versionMajor, int versionMinor, const char *typeName, F &&callback)
+#endif
{
QQmlPrivate::RegisterSingletonType api = {
0,
uri,
QTypeRevision::fromVersion(versionMajor, versionMinor),
typeName,
+ std::forward<F>(callback),
nullptr,
- callback,
- QQmlPrivate::StaticMetaObject<T>::staticMetaObject(),
- QQmlPrivate::QmlMetaType<T>::self(),
+ nullptr,
+ QMetaType(),
nullptr, nullptr,
QTypeRevision::zero()
};
@@ -721,12 +698,13 @@ inline int qmlRegisterSingletonType(
#ifdef Q_QDOC
template <typename T>
-int qmlRegisterSingletonType(const char *uri, int versionMajor, int versionMinor, const char *typeName, std::function<QObject*(QQmlEngine *, QJSEngine *)> callback)
+int qmlRegisterSingletonType(
+ const char *uri, int versionMajor, int versionMinor, const char *typeName,
+ std::function<QObject *(QQmlEngine *, QJSEngine *)> callback)
#else
-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)
+template<typename T, typename F, typename std::enable_if<std::is_convertible<F, std::function<QObject *(QQmlEngine *, QJSEngine *)>>::value, void>::type* = nullptr>
+int qmlRegisterSingletonType(
+ const char *uri, int versionMajor, int versionMinor, const char *typeName, F &&callback)
#endif
{
QQmlPrivate::RegisterSingletonType api = {
@@ -735,7 +713,7 @@ inline int qmlRegisterSingletonType(const char *uri, int versionMajor, int versi
QTypeRevision::fromVersion(versionMajor, versionMinor),
typeName,
nullptr,
- callback,
+ std::forward<F>(callback),
QQmlPrivate::StaticMetaObject<T>::staticMetaObject(),
QQmlPrivate::QmlMetaType<T>::self(),
nullptr, nullptr,
@@ -753,7 +731,7 @@ inline auto qmlRegisterSingletonInstance(const char *uri, int versionMajor, int
const char *typeName, T *cppObject) -> typename std::enable_if<std::is_base_of<QObject, T>::value, int>::type
#endif
{
- QQmlPrivate::SingletonFunctor registrationFunctor;
+ QQmlPrivate::SingletonInstanceFunctor registrationFunctor;
registrationFunctor.m_object = cppObject;
return qmlRegisterSingletonType<T>(uri, versionMajor, versionMinor, typeName, registrationFunctor);
}
@@ -799,6 +777,9 @@ inline int qmlRegisterType(const QUrl &url, const char *uri, int versionMajor, i
template<typename Container>
inline int qmlRegisterAnonymousSequentialContainer(const char *uri, int versionMajor)
{
+ static_assert(!std::is_abstract_v<Container>,
+ "It is not possible to register an abstract container with qmlRegisterAnonymousSequentialContainer.");
+
QQmlPrivate::RegisterSequentialContainer type = {
0,
uri,
@@ -812,14 +793,56 @@ inline int qmlRegisterAnonymousSequentialContainer(const char *uri, int versionM
return QQmlPrivate::qmlregister(QQmlPrivate::SequentialContainerRegistration, &type);
}
-template<class T, class Resolved, class Extended, bool Singleton, bool Interface, bool Sequence>
+template<class T, class Resolved, class Extended, bool Singleton, bool Interface, bool Sequence, bool Uncreatable>
struct QmlTypeAndRevisionsRegistration;
template<class T, class Resolved, class Extended>
-struct QmlTypeAndRevisionsRegistration<T, Resolved, Extended, false, false, false> {
+struct QmlTypeAndRevisionsRegistration<T, Resolved, Extended, false, false, false, false> {
+ static void registerTypeAndRevisions(const char *uri, int versionMajor, QList<int> *qmlTypeIds,
+ const QMetaObject *extension)
+ {
+#if QT_DEPRECATED_SINCE(6, 4)
+ // ### Qt7: Remove the warnings, and leave only the static asserts below.
+ if constexpr (!QQmlPrivate::QmlMetaType<Resolved>::hasAcceptableCtors()) {
+ QQmlPrivate::qmlRegistrationWarning(QQmlPrivate::UnconstructibleType,
+ QMetaType::fromType<Resolved>());
+ }
+
+ if constexpr (!std::is_base_of_v<QObject, Resolved>
+ && QQmlTypeInfo<T>::hasAttachedProperties) {
+ QQmlPrivate::qmlRegistrationWarning(QQmlPrivate::NonQObjectWithAtached,
+ QMetaType::fromType<Resolved>());
+ }
+#else
+ static_assert(QQmlPrivate::QmlMetaType<Resolved>::hasAcceptableCtors(),
+ "This type is neither a default constructible QObject, nor a default- "
+ "and copy-constructible Q_GADGET, nor marked as uncreatable.\n"
+ "You should not use it as a QML type.");
+ static_assert(std::is_base_of_v<QObject, Resolved>
+ || !QQmlTypeInfo<Resolved>::hasAttachedProperties);
+#endif
+ QQmlPrivate::qmlRegisterTypeAndRevisions<Resolved, Extended>(
+ uri, versionMajor, QQmlPrivate::StaticMetaObject<T>::staticMetaObject(),
+ qmlTypeIds, extension);
+ }
+};
+
+template<class T, class Resolved, class Extended>
+struct QmlTypeAndRevisionsRegistration<T, Resolved, Extended, false, false, false, true> {
static void registerTypeAndRevisions(const char *uri, int versionMajor, QList<int> *qmlTypeIds,
const QMetaObject *extension)
{
+#if QT_DEPRECATED_SINCE(6, 4)
+ // ### Qt7: Remove the warning, and leave only the static assert below.
+ if constexpr (!std::is_base_of_v<QObject, Resolved>
+ && QQmlTypeInfo<Resolved>::hasAttachedProperties) {
+ QQmlPrivate::qmlRegistrationWarning(QQmlPrivate::NonQObjectWithAtached,
+ QMetaType::fromType<Resolved>());
+ }
+#else
+ static_assert(std::is_base_of_v<QObject, Resolved>
+ || !QQmlTypeInfo<Resolved>::hasAttachedProperties);
+#endif
QQmlPrivate::qmlRegisterTypeAndRevisions<Resolved, Extended>(
uri, versionMajor, QQmlPrivate::StaticMetaObject<T>::staticMetaObject(),
qmlTypeIds, extension);
@@ -827,10 +850,11 @@ struct QmlTypeAndRevisionsRegistration<T, Resolved, Extended, false, false, fals
};
template<class T, class Resolved>
-struct QmlTypeAndRevisionsRegistration<T, Resolved, void, false, false, true> {
+struct QmlTypeAndRevisionsRegistration<T, Resolved, void, false, false, true, true> {
static void registerTypeAndRevisions(const char *uri, int versionMajor, QList<int> *qmlTypeIds,
const QMetaObject *)
{
+ // Sequences have to be anonymous for now, which implies uncreatable.
QQmlPrivate::qmlRegisterSequenceAndRevisions<Resolved>(
uri, versionMajor, QQmlPrivate::StaticMetaObject<T>::staticMetaObject(),
qmlTypeIds);
@@ -838,10 +862,37 @@ struct QmlTypeAndRevisionsRegistration<T, Resolved, void, false, false, true> {
};
template<class T, class Resolved, class Extended>
-struct QmlTypeAndRevisionsRegistration<T, Resolved, Extended, true, false, false> {
+struct QmlTypeAndRevisionsRegistration<T, Resolved, Extended, true, false, false, false> {
+ static void registerTypeAndRevisions(const char *uri, int versionMajor, QList<int> *qmlTypeIds,
+ const QMetaObject *extension)
+ {
+#if QT_DEPRECATED_SINCE(6, 4)
+ // ### Qt7: Remove the warning, and leave only the static assert below.
+ if constexpr (QQmlPrivate::singletonConstructionMode<Resolved, T>()
+ == QQmlPrivate::SingletonConstructionMode::None) {
+ QQmlPrivate::qmlRegistrationWarning(QQmlPrivate::UnconstructibleSingleton,
+ QMetaType::fromType<Resolved>());
+ }
+#else
+ static_assert(QQmlPrivate::singletonConstructionMode<Resolved, T>()
+ != QQmlPrivate::SingletonConstructionMode::None,
+ "A singleton needs either a default constructor or, when adding a default "
+ "constructor is infeasible, a public static "
+ "create(QQmlEngine *, QJSEngine *) method");
+#endif
+
+ QQmlPrivate::qmlRegisterSingletonAndRevisions<Resolved, Extended, T>(
+ uri, versionMajor, QQmlPrivate::StaticMetaObject<T>::staticMetaObject(),
+ qmlTypeIds, extension);
+ }
+};
+
+template<class T, class Resolved, class Extended>
+struct QmlTypeAndRevisionsRegistration<T, Resolved, Extended, true, false, false, true> {
static void registerTypeAndRevisions(const char *uri, int versionMajor, QList<int> *qmlTypeIds,
const QMetaObject *extension)
{
+ // An uncreatable singleton makes little sense? OK, you can still use the enums.
QQmlPrivate::qmlRegisterSingletonAndRevisions<Resolved, Extended, T>(
uri, versionMajor, QQmlPrivate::StaticMetaObject<T>::staticMetaObject(),
qmlTypeIds, extension);
@@ -849,7 +900,7 @@ struct QmlTypeAndRevisionsRegistration<T, Resolved, Extended, true, false, false
};
template<class T, class Resolved>
-struct QmlTypeAndRevisionsRegistration<T, Resolved, void, false, true, false> {
+struct QmlTypeAndRevisionsRegistration<T, Resolved, void, false, true, false, false> {
static void registerTypeAndRevisions(const char *uri, int versionMajor, QList<int> *qmlTypeIds,
const QMetaObject *)
{
@@ -859,36 +910,28 @@ struct QmlTypeAndRevisionsRegistration<T, Resolved, void, false, true, false> {
}
};
-template<typename T = void, typename... Args>
-void qmlRegisterTypesAndRevisions(const char *uri, int versionMajor,
- QList<int> *qmlTypeIds = nullptr);
-
-template<typename T, typename... Args>
+template<typename... T>
void qmlRegisterTypesAndRevisions(const char *uri, int versionMajor, QList<int> *qmlTypeIds)
{
- QmlTypeAndRevisionsRegistration<
+ (QmlTypeAndRevisionsRegistration<
T, typename QQmlPrivate::QmlResolved<T>::Type,
typename QQmlPrivate::QmlExtended<T>::Type,
QQmlPrivate::QmlSingleton<T>::Value,
QQmlPrivate::QmlInterface<T>::Value,
- QQmlPrivate::QmlSequence<T>::Value>
+ QQmlPrivate::QmlSequence<T>::Value,
+ QQmlPrivate::QmlUncreatable<T>::Value || QQmlPrivate::QmlAnonymous<T>::Value>
::registerTypeAndRevisions(uri, versionMajor, qmlTypeIds,
- QQmlPrivate::QmlExtendedNamespace<T>::metaObject());
- qmlRegisterTypesAndRevisions<Args...>(uri, versionMajor, qmlTypeIds);
-}
-
-template<>
-inline void qmlRegisterTypesAndRevisions<>(const char *, int, QList<int> *)
-{
+ QQmlPrivate::QmlExtendedNamespace<T>::metaObject()), ...);
}
inline void qmlRegisterNamespaceAndRevisions(const QMetaObject *metaObject,
const char *uri, int versionMajor,
- QList<int> *qmlTypeIds = nullptr,
- const QMetaObject *classInfoMetaObject = nullptr)
+ QList<int> *qmlTypeIds,
+ const QMetaObject *classInfoMetaObject,
+ const QMetaObject *extensionMetaObject)
{
QQmlPrivate::RegisterTypeAndRevisions type = {
- 0,
+ 3,
QMetaType(),
QMetaType(),
0,
@@ -910,15 +953,27 @@ inline void qmlRegisterNamespaceAndRevisions(const QMetaObject *metaObject,
-1,
nullptr,
- nullptr,
+ extensionMetaObject,
&qmlCreateCustomParser<void>,
- qmlTypeIds
+ qmlTypeIds,
+ -1,
+ false,
+ QMetaSequence()
};
qmlregister(QQmlPrivate::TypeAndRevisionsRegistration, &type);
}
+inline void qmlRegisterNamespaceAndRevisions(const QMetaObject *metaObject,
+ const char *uri, int versionMajor,
+ QList<int> *qmlTypeIds = nullptr,
+ const QMetaObject *classInfoMetaObject = nullptr)
+{
+ qmlRegisterNamespaceAndRevisions(metaObject, uri, versionMajor, qmlTypeIds,
+ classInfoMetaObject, nullptr);
+}
+
int Q_QML_EXPORT qmlTypeId(const char *uri, int versionMajor, int versionMinor, const char *qmlName);
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlabstractbinding.cpp b/src/qml/qml/qqmlabstractbinding.cpp
index 42891c1a8e..78d1d68f55 100644
--- a/src/qml/qml/qqmlabstractbinding.cpp
+++ b/src/qml/qml/qqmlabstractbinding.cpp
@@ -1,47 +1,12 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qqmlabstractbinding_p.h"
#include <QtQml/qqmlinfo.h>
#include <private/qqmlbinding_p.h>
#include <private/qqmlvaluetypeproxybinding_p.h>
+#include <private/qqmlvmemetaobject_p.h>
QT_BEGIN_NAMESPACE
@@ -89,7 +54,7 @@ void QQmlAbstractBinding::addToObject()
while (b && (b->targetPropertyIndex().coreIndex() != coreIndex ||
b->targetPropertyIndex().hasValueTypeIndex()))
b = b->nextBinding();
- Q_ASSERT(b && b->isValueTypeProxy());
+ Q_ASSERT(b && b->kind() == QQmlAbstractBinding::ValueTypeProxy);
proxy = static_cast<QQmlValueTypeProxyBinding *>(b);
}
@@ -144,12 +109,13 @@ void QQmlAbstractBinding::removeFromObject()
// Find the value type binding
QQmlAbstractBinding *vtbinding = data->bindings;
- while (vtbinding && (vtbinding->targetPropertyIndex().coreIndex() != coreIndex ||
- vtbinding->targetPropertyIndex().hasValueTypeIndex())) {
+ Q_ASSERT(vtbinding);
+ while (vtbinding->targetPropertyIndex().coreIndex() != coreIndex
+ || vtbinding->targetPropertyIndex().hasValueTypeIndex()) {
vtbinding = vtbinding->nextBinding();
Q_ASSERT(vtbinding);
}
- Q_ASSERT(vtbinding->isValueTypeProxy());
+ Q_ASSERT(vtbinding->kind() == QQmlAbstractBinding::ValueTypeProxy);
QQmlValueTypeProxyBinding *vtproxybinding =
static_cast<QQmlValueTypeProxyBinding *>(vtbinding);
@@ -189,19 +155,133 @@ void QQmlAbstractBinding::removeFromObject()
data->clearBindingBit(coreIndex);
}
-void QQmlAbstractBinding::printBindingLoopError(QQmlProperty &prop)
+void QQmlAbstractBinding::printBindingLoopError(const QQmlProperty &prop)
{
qmlWarning(prop.object()) << QString(QLatin1String("Binding loop detected for property \"%1\"")).arg(prop.name());
}
-QString QQmlAbstractBinding::expression() const
+void QQmlAbstractBinding::getPropertyData(
+ const QQmlPropertyData **propertyData, QQmlPropertyData *valueTypeData) const
{
- return QLatin1String("<Unknown>");
+ Q_ASSERT(propertyData);
+
+ QQmlData *data = QQmlData::get(m_target.data(), false);
+ Q_ASSERT(data);
+
+ if (Q_UNLIKELY(!data->propertyCache))
+ data->propertyCache = QQmlMetaType::propertyCache(m_target->metaObject());
+
+ *propertyData = data->propertyCache->property(m_targetIndex.coreIndex());
+ Q_ASSERT(*propertyData);
+
+ if (Q_UNLIKELY(m_targetIndex.hasValueTypeIndex() && valueTypeData)) {
+ const QMetaObject *valueTypeMetaObject
+ = QQmlMetaType::metaObjectForValueType((*propertyData)->propType());
+ Q_ASSERT(valueTypeMetaObject);
+ QMetaProperty vtProp = valueTypeMetaObject->property(m_targetIndex.valueTypeIndex());
+ valueTypeData->setFlags(QQmlPropertyData::flagsForProperty(vtProp));
+ valueTypeData->setPropType(vtProp.metaType());
+ valueTypeData->setCoreIndex(m_targetIndex.valueTypeIndex());
+ }
+}
+
+void QQmlAbstractBinding::updateCanUseAccessor()
+{
+ setCanUseAccessor(true); // Always use accessors, except when:
+ if (auto interceptorMetaObject = QQmlInterceptorMetaObject::get(targetObject())) {
+ if (!m_targetIndex.isValid() || interceptorMetaObject->intercepts(m_targetIndex))
+ setCanUseAccessor(false);
+ }
+}
+
+void QQmlAbstractBinding::setTarget(const QQmlProperty &prop)
+{
+ auto pd = QQmlPropertyPrivate::get(prop);
+ setTarget(prop.object(), pd->core, &pd->valueTypeData);
+}
+
+bool QQmlAbstractBinding::setTarget(
+ QObject *object, const QQmlPropertyData &core, const QQmlPropertyData *valueType)
+{
+ return setTarget(object, core.coreIndex(), core.isAlias(),
+ valueType ? valueType->coreIndex() : -1);
+}
+
+static const QQmlPropertyData *getObjectPropertyData(QObject *object, int coreIndex)
+{
+ QQmlData *data = QQmlData::get(object, true);
+ if (!data)
+ return nullptr;
+
+ if (!data->propertyCache) {
+ data->propertyCache = QQmlMetaType::propertyCache(object);
+ if (!data->propertyCache)
+ return nullptr;
+ }
+
+ const QQmlPropertyData *propertyData = data->propertyCache->property(coreIndex);
+ Q_ASSERT(propertyData);
+ return propertyData;
+}
+
+bool QQmlAbstractBinding::setTarget(
+ QObject *object, int coreIndex, bool coreIsAlias, int valueTypeIndex)
+{
+ auto invalidate = [this]() {
+ m_target = nullptr;
+ m_targetIndex = QQmlPropertyIndex();
+ return false;
+ };
+
+ if (!object)
+ return invalidate();
+
+ m_target = object;
+
+ for (bool isAlias = coreIsAlias; isAlias;) {
+ QQmlVMEMetaObject *vme = QQmlVMEMetaObject::getForProperty(object, coreIndex);
+
+ int aValueTypeIndex;
+ if (!vme->aliasTarget(coreIndex, &object, &coreIndex, &aValueTypeIndex)) {
+ // can't resolve id (yet)
+ return invalidate();
+ }
+
+ const QQmlPropertyData *propertyData = getObjectPropertyData(object, coreIndex);
+ if (!propertyData)
+ return invalidate();
+
+ if (aValueTypeIndex != -1) {
+ if (propertyData->propType().flags().testFlag(QMetaType::PointerToQObject)) {
+ // deep alias
+ propertyData->readProperty(object, &object);
+ coreIndex = aValueTypeIndex;
+ valueTypeIndex = -1;
+ propertyData = getObjectPropertyData(object, coreIndex);
+ if (!propertyData)
+ return invalidate();
+ } else {
+ valueTypeIndex = aValueTypeIndex;
+ }
+ }
+
+ m_target = object;
+ isAlias = propertyData->isAlias();
+ coreIndex = propertyData->coreIndex();
+ }
+ m_targetIndex = QQmlPropertyIndex(coreIndex, valueTypeIndex);
+
+ QQmlData *data = QQmlData::get(m_target.data(), true);
+ if (!data->propertyCache)
+ data->propertyCache = QQmlMetaType::propertyCache(m_target->metaObject());
+
+ return true;
}
-bool QQmlAbstractBinding::isValueTypeProxy() const
+
+QString QQmlAbstractBinding::expression() const
{
- return false;
+ return QLatin1String("<Unknown>");
}
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlabstractbinding_p.h b/src/qml/qml/qqmlabstractbinding_p.h
index 96bb0da269..8230c6aa6b 100644
--- a/src/qml/qml/qqmlabstractbinding_p.h
+++ b/src/qml/qml/qqmlabstractbinding_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLABSTRACTBINDING_P_H
#define QQMLABSTRACTBINDING_P_H
@@ -59,19 +23,27 @@
QT_BEGIN_NAMESPACE
class QQmlObjectCreator;
+class QQmlAnyBinding;
-class Q_QML_PRIVATE_EXPORT QQmlAbstractBinding
+class Q_QML_EXPORT QQmlAbstractBinding
{
+ friend class QQmlAnyBinding;
protected:
QQmlAbstractBinding();
public:
+ enum Kind {
+ ValueTypeProxy,
+ QmlBinding,
+ PropertyToPropertyBinding,
+ };
+
virtual ~QQmlAbstractBinding();
typedef QExplicitlySharedDataPointer<QQmlAbstractBinding> Ptr;
virtual QString expression() const;
- virtual bool isValueTypeProxy() const;
+ virtual Kind kind() const = 0;
// Should return the encoded property index for the binding. Should return this value
// even if the binding is not enabled or added to an object.
@@ -82,17 +54,23 @@ public:
// binding is not enabled or added to the object.
QObject *targetObject() const { return m_target.data(); }
+ void setTarget(const QQmlProperty &);
+ bool setTarget(QObject *, const QQmlPropertyData &, const QQmlPropertyData *valueType);
+ bool setTarget(QObject *, int coreIndex, bool coreIsAlias, int valueTypeIndex);
+
virtual void setEnabled(bool e, QQmlPropertyData::WriteFlags f = QQmlPropertyData::DontRemoveBinding) = 0;
void addToObject();
void removeFromObject();
- static void printBindingLoopError(QQmlProperty &prop);
+ static void printBindingLoopError(const QQmlProperty &prop);
inline QQmlAbstractBinding *nextBinding() const;
inline bool canUseAccessor() const
{ return m_nextBinding.tag().testFlag(CanUseAccessor); }
+ void setCanUseAccessor(bool canUseAccessor)
+ { m_nextBinding.setTag(m_nextBinding.tag().setFlag(CanUseAccessor, canUseAccessor)); }
struct RefCount {
RefCount() {}
@@ -127,6 +105,15 @@ protected:
inline void setNextBinding(QQmlAbstractBinding *);
+ void getPropertyData(
+ const QQmlPropertyData **propertyData, QQmlPropertyData *valueTypeData) const;
+
+ inline bool updatingFlag() const;
+ inline void setUpdatingFlag(bool);
+ inline bool enabledFlag() const;
+ inline void setEnabledFlag(bool);
+ void updateCanUseAccessor();
+
QQmlPropertyIndex m_targetIndex;
// Pointer is the target object to which the binding binds
@@ -163,6 +150,26 @@ void QQmlAbstractBinding::setNextBinding(QQmlAbstractBinding *b)
m_nextBinding = b;
}
+bool QQmlAbstractBinding::updatingFlag() const
+{
+ return m_target.tag().testFlag(UpdatingBinding);
+}
+
+void QQmlAbstractBinding::setUpdatingFlag(bool v)
+{
+ m_target.setTag(m_target.tag().setFlag(UpdatingBinding, v));
+}
+
+bool QQmlAbstractBinding::enabledFlag() const
+{
+ return m_target.tag().testFlag(BindingEnabled);
+}
+
+void QQmlAbstractBinding::setEnabledFlag(bool v)
+{
+ m_target.setTag(m_target.tag().setFlag(BindingEnabled, v));
+}
+
QT_END_NAMESPACE
#endif // QQMLABSTRACTBINDING_P_H
diff --git a/src/qml/qml/qqmlabstracturlinterceptor.cpp b/src/qml/qml/qqmlabstracturlinterceptor.cpp
index 3c215bc381..b73af72281 100644
--- a/src/qml/qml/qqmlabstracturlinterceptor.cpp
+++ b/src/qml/qml/qqmlabstracturlinterceptor.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 Research In Motion.
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 Research In Motion.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
/*!
\class QQmlAbstractUrlInterceptor
diff --git a/src/qml/qml/qqmlabstracturlinterceptor.h b/src/qml/qml/qqmlabstracturlinterceptor.h
index af231f51b2..ca3da059a3 100644
--- a/src/qml/qml/qqmlabstracturlinterceptor.h
+++ b/src/qml/qml/qqmlabstracturlinterceptor.h
@@ -1,50 +1,15 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 Research In Motion.
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 Research In Motion.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLABSTRACTURLINTERCEPTOR_H
#define QQMLABSTRACTURLINTERCEPTOR_H
-#include <QtCore/qurl.h>
#include <QtQml/qtqmlglobal.h>
QT_BEGIN_NAMESPACE
+class QUrl;
+
class Q_QML_EXPORT QQmlAbstractUrlInterceptor
{
public:
diff --git a/src/qml/qml/qqmlanybinding_p.h b/src/qml/qml/qqmlanybinding_p.h
index 38c1023c79..f432d2abae 100644
--- a/src/qml/qml/qqmlanybinding_p.h
+++ b/src/qml/qml/qqmlanybinding_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 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$
-**
-****************************************************************************/
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLANYBINDINGPTR_P_H
#define QQMLANYBINDINGPTR_P_H
@@ -55,6 +19,8 @@
#include <private/qqmlpropertybinding_p.h>
#include <private/qqmlbinding_p.h>
+QT_BEGIN_NAMESPACE
+
// Fully inline so that subsequent prop.isBindable check might get ellided.
/*!
@@ -78,10 +44,9 @@
class QQmlAnyBinding {
public:
- QQmlAnyBinding() = default;
+ constexpr QQmlAnyBinding() noexcept = default;
QQmlAnyBinding(std::nullptr_t) : d(static_cast<QQmlAbstractBinding *>(nullptr)) {}
-
/*!
\internal
Returns the binding of the property \a prop as a QQmlAnyBinding.
@@ -100,6 +65,28 @@ public:
}
/*!
+ \overload
+
+ \a object must be non-null
+ */
+ static QQmlAnyBinding ofProperty(QObject *object, QQmlPropertyIndex index)
+ {
+ QQmlAnyBinding binding;
+ Q_ASSERT(object);
+ auto coreIndex = index.coreIndex();
+ // we don't support bindable properties on value types so far
+ if (!index.hasValueTypeIndex()
+ && QQmlData::ensurePropertyCache(object)->property(coreIndex)->isBindable()) {
+ auto metaProp = object->metaObject()->property(coreIndex);
+ QUntypedBindable bindable = metaProp.bindable(object);
+ binding = bindable.binding();
+ } else {
+ binding = QQmlPropertyPrivate::binding(object, index);
+ }
+ return binding;
+ }
+
+ /*!
Removes the binding from the property \a prop, and returns it as a
QQmlAnyBinding if there was any. Otherwise returns a null
QQmlAnyBinding.
@@ -113,9 +100,9 @@ public:
} else {
auto qmlBinding = QQmlPropertyPrivate::binding(prop);
if (qmlBinding) {
+ binding = qmlBinding; // this needs to run before removeFromObject, else the refcount might reach zero
qmlBinding->setEnabled(false, QQmlPropertyData::DontRemoveBinding | QQmlPropertyData::BypassInterceptor);
qmlBinding->removeFromObject();
- binding = qmlBinding;
}
}
return binding;
@@ -149,6 +136,30 @@ public:
/*!
\internal
+ Creates a binding for property \a prop from \a script.
+ \a obj is the scope object which shall be used for the function and \a ctxt its QML scope.
+ The binding is not installed on the property (but if a QQmlBinding is created, it has its
+ target set to \a prop).
+ */
+ static QQmlAnyBinding createFromScriptString(const QQmlProperty &prop, const QQmlScriptString &script,
+ QObject *obj, QQmlContext *ctxt)
+ {
+ QQmlAnyBinding binding;
+ auto propPriv = QQmlPropertyPrivate::get(prop);
+ if (prop.isBindable()) {
+ auto index = QQmlPropertyIndex(propPriv->core.coreIndex(), -1);
+ binding = QQmlPropertyBinding::createFromScriptString(&propPriv->core, script, obj, ctxt, prop.object(), index);
+ } else {
+ auto qmlBinding = QQmlBinding::create(&propPriv->core, script, obj, ctxt);
+ qmlBinding->setTarget(prop);
+ binding = qmlBinding;
+ }
+ return binding;
+ }
+
+
+ /*!
+ \internal
Removes the binding from \a prop if there is any.
*/
static void removeBindingFrom(QQmlProperty &prop)
@@ -230,17 +241,39 @@ public:
QQmlPropertyPrivate::setBinding(abstractBinding);
} else {
Q_ASSERT(target.isBindable());
- // TODO: QMetaProperty::bindable needs a mode to work on the dynamic metaobject
- QUntypedBindable bindable = target.property().bindable(target.object());
+ QUntypedBindable bindable;
+ void *argv[] = {&bindable};
+ if (mode == IgnoreInterceptors) {
+ target.object()->qt_metacall(QMetaObject::BindableProperty, target.index(), argv);
+ } else {
+ QMetaObject::metacall(target.object(), QMetaObject::BindableProperty, target.index(), argv);
+ }
bindable.setBinding(asUntypedPropertyBinding());
}
}
/*!
+ \internal
+ Returns true if the binding is in an error state (e.g. binding loop), false otherwise.
+
+ \note For ValueTypeProxyBindings, this methods will always return false
+ */
+ bool hasError() {
+ if (isAbstractPropertyBinding()) {
+ auto abstractBinding = asAbstractBinding();
+ if (abstractBinding->kind() != QQmlAbstractBinding::QmlBinding)
+ return false;
+ return static_cast<QQmlBinding *>(abstractBinding)->hasError();
+ } else {
+ return asUntypedPropertyBinding().error().hasError();
+ }
+ }
+
+ /*!
Stores a null binding. For purpose of classification, the null bindings is
treated as a QQmlAbstractPropertyBindings.
*/
- QQmlAnyBinding& operator=(std::nullptr_t )
+ QQmlAnyBinding &operator=(std::nullptr_t)
{
clear();
return *this;
@@ -293,9 +326,31 @@ public:
/*!
\internal
+ Reevaluates the binding. If the binding was disabled,
+ it gets enabled.
+ */
+ void refresh()
+ {
+ if (d.isNull())
+ return;
+ if (d.isT1()) {
+ auto binding = static_cast<QQmlBinding *>(d.asT1());
+ binding->setEnabledFlag(true);
+ binding->refresh();
+ } else {
+ auto bindingPriv = d.asT2();
+ PendingBindingObserverList bindingObservers;
+ bindingPriv->evaluateRecursive(bindingObservers);
+ bindingPriv->notifyNonRecursive(bindingObservers);
+ }
+
+ }
+
+ /*!
+ \internal
Stores \a binding and keeps a reference to it.
*/
- QQmlAnyBinding& operator=(QQmlAbstractBinding *binding)
+ QQmlAnyBinding &operator=(QQmlAbstractBinding *binding)
{
clear();
if (binding) {
@@ -309,7 +364,7 @@ public:
\internal
Stores the binding stored in \a binding and keeps a reference to it.
*/
- QQmlAnyBinding& operator=(const QQmlAbstractBinding::Ptr &binding)
+ QQmlAnyBinding &operator=(const QQmlAbstractBinding::Ptr &binding)
{
clear();
if (binding) {
@@ -323,7 +378,7 @@ public:
\internal
Stores \a binding's binding, taking ownership from \a binding.
*/
- QQmlAnyBinding& operator=(QQmlAbstractBinding::Ptr &&binding)
+ QQmlAnyBinding &operator=(QQmlAbstractBinding::Ptr &&binding)
{
clear();
if (binding) {
@@ -336,7 +391,7 @@ public:
\internal
Stores the binding stored in \a untypedBinding and keeps a reference to it.
*/
- QQmlAnyBinding& operator=(const QUntypedPropertyBinding &untypedBinding)
+ QQmlAnyBinding &operator=(const QUntypedPropertyBinding &untypedBinding)
{
clear();
auto binding = QPropertyBindingPrivate::get(untypedBinding);
@@ -352,7 +407,7 @@ public:
\overload
Stores the binding stored in \a untypedBinding, taking ownership from it.
*/
- QQmlAnyBinding& operator=(const QUntypedPropertyBinding &&untypedBinding)
+ QQmlAnyBinding &operator=(QUntypedPropertyBinding &&untypedBinding)
{
clear();
auto binding = QPropertyBindingPrivate::get(untypedBinding);
@@ -363,17 +418,17 @@ public:
return *this;
}
- QQmlAnyBinding(const QQmlAnyBinding &other)
- {
- *this = other;
- }
+ QQmlAnyBinding(QQmlAnyBinding &&other) noexcept
+ : d(std::exchange(other.d, QBiPointer<QQmlAbstractBinding, QPropertyBindingPrivate>()))
+ {}
- friend void swap(const QQmlAnyBinding &a, const QQmlAnyBinding &b)
- {
- qSwap(a.d, b.d);
- }
+ QQmlAnyBinding(const QQmlAnyBinding &other) noexcept { *this = other; }
+ QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_MOVE_AND_SWAP(QQmlAnyBinding)
+
+ void swap(QQmlAnyBinding &other) noexcept { d.swap(other.d); }
+ friend void swap(QQmlAnyBinding &lhs, QQmlAnyBinding &rhs) noexcept { lhs.swap(rhs); }
- QQmlAnyBinding& operator=(const QQmlAnyBinding &other)
+ QQmlAnyBinding &operator=(const QQmlAnyBinding &other) noexcept
{
clear();
if (auto abstractBinding = other.asAbstractBinding())
@@ -393,11 +448,9 @@ public:
return p1.d != p2.d;
}
- ~QQmlAnyBinding() {
- clear();
- }
+ ~QQmlAnyBinding() noexcept { clear(); }
private:
- void clear() {
+ void clear() noexcept {
if (d.isNull())
return;
if (d.isT1()) {
@@ -406,14 +459,15 @@ private:
delete qqmlptr;
} else if (d.isT2()) {
QPropertyBindingPrivate *priv = d.asT2();
- priv->ref--;
- if (!priv->ref)
+ if (!priv->deref())
QPropertyBindingPrivate::destroyAndFreeMemory(priv);
}
d = static_cast<QQmlAbstractBinding *>(nullptr);
}
- QBiPointer<QQmlAbstractBinding, QPropertyBindingPrivate> d = static_cast<QQmlAbstractBinding *>(nullptr);
+ QBiPointer<QQmlAbstractBinding, QPropertyBindingPrivate> d;
};
+QT_END_NAMESPACE
+
#endif // QQMLANYBINDINGPTR_P_H
diff --git a/src/qml/qml/qqmlapplicationengine.cpp b/src/qml/qml/qqmlapplicationengine.cpp
index e0ab25892f..82cc335c8e 100644
--- a/src/qml/qml/qqmlapplicationengine.cpp
+++ b/src/qml/qml/qqmlapplicationengine.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 Research In Motion.
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 Research In Motion.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <QtQml/qqmlfile.h>
#include <QtCore/QCoreApplication>
@@ -43,7 +7,9 @@
#include <QQmlComponent>
#include "qqmlapplicationengine.h"
#include "qqmlapplicationengine_p.h"
-#include "qqmlfileselector.h"
+#include <QtQml/private/qqmlcomponent_p.h>
+#include <QtQml/private/qqmldirdata_p.h>
+#include <QtQml/private/qqmlfileselector_p.h>
QT_BEGIN_NAMESPACE
@@ -57,10 +23,18 @@ QQmlApplicationEnginePrivate::~QQmlApplicationEnginePrivate()
{
}
+void QQmlApplicationEnginePrivate::ensureInitialized()
+{
+ if (!isInitialized) {
+ init();
+ isInitialized = true;
+ }
+}
+
void QQmlApplicationEnginePrivate::cleanUp()
{
Q_Q(QQmlApplicationEngine);
- for (auto obj : qAsConst(objects))
+ for (auto obj : std::as_const(objects))
obj->disconnect(q);
qDeleteAll(objects);
@@ -73,7 +47,9 @@ void QQmlApplicationEnginePrivate::init()
&QCoreApplication::quit, Qt::QueuedConnection);
q->connect(q, &QQmlApplicationEngine::exit, QCoreApplication::instance(),
&QCoreApplication::exit, Qt::QueuedConnection);
- q->connect(q, SIGNAL(uiLanguageChanged()), q_func(), SLOT(_q_loadTranslations()));
+ QObject::connect(q, &QJSEngine::uiLanguageChanged, q, [this](){
+ _q_loadTranslations();
+ });
#if QT_CONFIG(translation)
QTranslator* qtTranslator = new QTranslator(q);
if (qtTranslator->load(QLocale(), QLatin1String("qt"), QLatin1String("_"), QLibraryInfo::path(QLibraryInfo::TranslationsPath), QLatin1String(".qm")))
@@ -89,18 +65,17 @@ void QQmlApplicationEnginePrivate::init()
void QQmlApplicationEnginePrivate::_q_loadTranslations()
{
#if QT_CONFIG(translation)
+ Q_Q(QQmlApplicationEngine);
if (translationsDirectory.isEmpty())
return;
- Q_Q(QQmlApplicationEngine);
-
- QScopedPointer<QTranslator> translator(new QTranslator);
+ auto translator = std::make_unique<QTranslator>();
if (!uiLanguage.value().isEmpty()) {
QLocale locale(uiLanguage);
if (translator->load(locale, QLatin1String("qml"), QLatin1String("_"), translationsDirectory, QLatin1String(".qm"))) {
if (activeTranslator)
- QCoreApplication::removeTranslator(activeTranslator.data());
- QCoreApplication::installTranslator(translator.data());
+ QCoreApplication::removeTranslator(activeTranslator.get());
+ QCoreApplication::installTranslator(translator.get());
activeTranslator.swap(translator);
}
} else {
@@ -114,10 +89,7 @@ void QQmlApplicationEnginePrivate::startLoad(const QUrl &url, const QByteArray &
{
Q_Q(QQmlApplicationEngine);
- if (!isInitialized) {
- init();
- isInitialized = true;
- }
+ ensureInitialized();
if (url.scheme() == QLatin1String("file") || url.scheme() == QLatin1String("qrc")) {
QFileInfo fi(QQmlFile::urlToLocalFileOrQrc(url));
@@ -134,11 +106,40 @@ void QQmlApplicationEnginePrivate::startLoad(const QUrl &url, const QByteArray &
else
c->loadUrl(url);
- if (!c->isLoading()) {
- finishLoad(c);
- return;
+ ensureLoadingFinishes(c);
+}
+
+void QQmlApplicationEnginePrivate::startLoad(QAnyStringView uri, QAnyStringView typeName)
+{
+ Q_Q(QQmlApplicationEngine);
+
+ QQmlComponent *c = new QQmlComponent(q, q);
+
+ ensureInitialized();
+
+ auto *componentPriv = QQmlComponentPrivate::get(c);
+ const auto [status, type] = componentPriv->prepareLoadFromModule(uri, typeName);
+
+ if (type.sourceUrl().isValid()) {
+ const auto qmlDirData = typeLoader.getQmldir(type.sourceUrl());
+ const QUrl url = qmlDirData->finalUrl();
+ if (url.scheme() == QLatin1String("file") || url.scheme() == QLatin1String("qrc")) {
+ QFileInfo fi(QQmlFile::urlToLocalFileOrQrc(url));
+ translationsDirectory = fi.path() + QLatin1String("/i18n");
+ } else {
+ translationsDirectory.clear();
+ }
}
- QObject::connect(c, &QQmlComponent::statusChanged, q, [this, c] { this->finishLoad(c); });
+
+ /* Translations must be loaded before the QML file. They require translationDirectory to
+ * already be resolved. But, in order to resolve the translationDirectory, the type of the
+ * module to load needs to be known. Therefore, loadFromModule is split into resolution and
+ * loading because the translation directory needs to be set in between.
+ */
+ _q_loadTranslations();
+ componentPriv->completeLoadFromModule(uri, typeName, type, status);
+
+ ensureLoadingFinishes(c);
}
void QQmlApplicationEnginePrivate::finishLoad(QQmlComponent *c)
@@ -149,6 +150,7 @@ void QQmlApplicationEnginePrivate::finishLoad(QQmlComponent *c)
qWarning() << "QQmlApplicationEngine failed to load component";
warning(c->errors());
q->objectCreated(nullptr, c->url());
+ q->objectCreationFailed(c->url());
break;
case QQmlComponent::Ready: {
auto newObj = initialProperties.empty() ? c->create() : c->createWithInitialProperties(initialProperties);
@@ -157,6 +159,7 @@ void QQmlApplicationEnginePrivate::finishLoad(QQmlComponent *c)
qWarning() << "QQmlApplicationEngine failed to create component";
warning(c->errors());
q->objectCreated(nullptr, c->url());
+ q->objectCreationFailed(c->url());
break;
}
@@ -173,6 +176,16 @@ void QQmlApplicationEnginePrivate::finishLoad(QQmlComponent *c)
c->deleteLater();
}
+void QQmlApplicationEnginePrivate::ensureLoadingFinishes(QQmlComponent *c)
+{
+ Q_Q(QQmlApplicationEngine);
+ if (!c->isLoading()) {
+ finishLoad(c);
+ return;
+ }
+ QObject::connect(c, &QQmlComponent::statusChanged, q, [this, c] { this->finishLoad(c); });
+}
+
/*!
\class QQmlApplicationEngine
\since 5.1
@@ -233,6 +246,32 @@ void QQmlApplicationEnginePrivate::finishLoad(QQmlComponent *c)
*/
/*!
+ \fn QQmlApplicationEngine::objectCreationFailed(const QUrl &url)
+ \since 6.4
+
+ This signal is emitted when loading finishes because an error occurred.
+
+ The \a url to the component that failed to load is provided as an argument.
+
+ \code
+ QGuiApplication app(argc, argv);
+ QQmlApplicationEngine engine;
+
+ // exit on error
+ QObject::connect(&engine, &QQmlApplicationEngine::objectCreationFailed,
+ &app, []() { QCoreApplication::exit(-1); }, Qt::QueuedConnection);
+ engine.load(QUrl());
+ return app.exec();
+ \endcode
+
+ \note If the path to the component was provided as a QString containing a
+ relative path, the \a url will contain a fully resolved path to the file.
+
+ See also \l {QQmlApplicationEngine::objectCreated}, which will be emitted in
+ addition to this signal (even though creation failed).
+*/
+
+/*!
Create a new QQmlApplicationEngine with the given \a parent. You will have to call load() later in
order to load a QML file.
*/
@@ -253,6 +292,20 @@ QQmlApplicationEngine::QQmlApplicationEngine(const QUrl &url, QObject *parent)
}
/*!
+ Create a new QQmlApplicationEngine and loads the QML type specified by
+ \a uri and \a typeName
+ This is provided as a convenience, and is the same as using the empty constructor and calling
+ loadFromModule afterwards.
+
+ \since 6.5
+*/
+QQmlApplicationEngine::QQmlApplicationEngine(QAnyStringView uri, QAnyStringView typeName, QObject *parent)
+ : QQmlApplicationEngine(parent)
+{
+ loadFromModule(uri, typeName);
+}
+
+/*!
Create a new QQmlApplicationEngine and loads the QML file at the given
\a filePath, which must be a local file path. If a relative path is
given then it will be interpreted as relative to the working directory of the
@@ -306,6 +359,36 @@ void QQmlApplicationEngine::load(const QString &filePath)
}
/*!
+ Loads the QML type \a typeName from the module specified by \a uri.
+ If the type originates from a QML file located at a remote url,
+ the type will be loaded asynchronously.
+ Listen to the \l {QQmlApplicationEngine::objectCreated()}{objectCreated}
+ signal to determine when the object tree is ready.
+
+ If an error occurs, the \l {QQmlApplicationEngine::objectCreated()}{objectCreated}
+ signal is emitted with a null pointer as parameter and error messages are printed
+ with qWarning.
+
+ \code
+ QQmlApplicationEngine engine;
+ engine.loadFromModule("QtQuick", "Rectangle");
+ \endcode
+
+ \note The module identified by \a uri is searched in the
+ \l {QML Import Path}{import path}, in the same way as if
+ you were doing \c{import uri} inside a QML file. If the
+ module cannot be located there, this function will fail.
+
+ \since 6.5
+ \sa QQmlComponent::loadFromModule
+ */
+void QQmlApplicationEngine::loadFromModule(QAnyStringView uri, QAnyStringView typeName)
+{
+ Q_D(QQmlApplicationEngine);
+ d->startLoad(uri, typeName);
+}
+
+/*!
Sets the \a initialProperties with which the QML component gets initialized after
it gets loaded.
diff --git a/src/qml/qml/qqmlapplicationengine.h b/src/qml/qml/qqmlapplicationengine.h
index dc8a0c9100..69e4a7261c 100644
--- a/src/qml/qml/qqmlapplicationengine.h
+++ b/src/qml/qml/qqmlapplicationengine.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 Research In Motion.
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 Research In Motion.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLAPPLICATIONENGINE_H
#define QQMLAPPLICATIONENGINE_H
@@ -55,6 +19,8 @@ class Q_QML_EXPORT QQmlApplicationEngine : public QQmlEngine
public:
QQmlApplicationEngine(QObject *parent = nullptr);
QQmlApplicationEngine(const QUrl &url, QObject *parent = nullptr);
+ explicit QQmlApplicationEngine(QAnyStringView uri, QAnyStringView typeName,
+ QObject *parent = nullptr);
QQmlApplicationEngine(const QString &filePath, QObject *parent = nullptr);
~QQmlApplicationEngine() override;
@@ -63,12 +29,14 @@ public:
public Q_SLOTS:
void load(const QUrl &url);
void load(const QString &filePath);
+ void loadFromModule(QAnyStringView uri, QAnyStringView typeName);
void setInitialProperties(const QVariantMap &initialProperties);
void setExtraFileSelectors(const QStringList &extraFileSelectors);
void loadData(const QByteArray &data, const QUrl &url = QUrl());
Q_SIGNALS:
void objectCreated(QObject *object, const QUrl &url);
+ void objectCreationFailed(const QUrl &url);
private:
Q_DISABLE_COPY(QQmlApplicationEngine)
diff --git a/src/qml/qml/qqmlapplicationengine_p.h b/src/qml/qml/qqmlapplicationengine_p.h
index d944dd25b3..df99783e0a 100644
--- a/src/qml/qml/qqmlapplicationengine_p.h
+++ b/src/qml/qml/qqmlapplicationengine_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 Research In Motion.
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 Research In Motion.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLAPPLICATIONENGINE_P_H
#define QQMLAPPLICATIONENGINE_P_H
@@ -60,24 +24,27 @@
QT_BEGIN_NAMESPACE
class QFileSelector;
-class Q_QML_PRIVATE_EXPORT QQmlApplicationEnginePrivate : public QQmlEnginePrivate
+class Q_QML_EXPORT QQmlApplicationEnginePrivate : public QQmlEnginePrivate
{
Q_DECLARE_PUBLIC(QQmlApplicationEngine)
public:
QQmlApplicationEnginePrivate(QQmlEngine *e);
~QQmlApplicationEnginePrivate();
+ void ensureInitialized();
void init();
void cleanUp();
void startLoad(const QUrl &url, const QByteArray &data = QByteArray(), bool dataFlag = false);
+ void startLoad(QAnyStringView uri, QAnyStringView type);
void _q_loadTranslations();
void finishLoad(QQmlComponent *component);
+ void ensureLoadingFinishes(QQmlComponent *component);
QList<QObject *> objects;
QVariantMap initialProperties;
QStringList extraFileSelectors;
QString translationsDirectory;
#if QT_CONFIG(translation)
- QScopedPointer<QTranslator> activeTranslator;
+ std::unique_ptr<QTranslator> activeTranslator;
#endif
bool isInitialized = false;
};
diff --git a/src/qml/qml/qqmlbinding.cpp b/src/qml/qml/qqmlbinding.cpp
index 69ac63b0ad..47f8e5c429 100644
--- a/src/qml/qml/qqmlbinding.cpp
+++ b/src/qml/qml/qqmlbinding.cpp
@@ -1,47 +1,9 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qqmlbinding_p.h"
-#include "qqml.h"
#include "qqmlcontext.h"
-#include "qqmlinfo.h"
#include "qqmldata_p.h"
#include <private/qqmldebugserviceinterfaces_p.h>
@@ -67,9 +29,12 @@
QT_BEGIN_NAMESPACE
+Q_TRACE_POINT(qtqml, QQmlBinding_entry, const QQmlEngine *engine, const QString &function, const QString &fileName, int line, int column)
+Q_TRACE_POINT(qtqml, QQmlBinding_exit)
+
QQmlBinding *QQmlBinding::create(const QQmlPropertyData *property, const QQmlScriptString &script, QObject *obj, QQmlContext *ctxt)
{
- QQmlBinding *b = newBinding(QQmlEnginePrivate::get(ctxt), property);
+ QQmlBinding *b = newBinding(property);
if (ctxt && !ctxt->isValid())
return b;
@@ -125,7 +90,7 @@ QQmlBinding *QQmlBinding::create(
const QQmlPropertyData *property, const QString &str, QObject *obj,
const QQmlRefPointer<QQmlContextData> &ctxt, const QString &url, quint16 lineNumber)
{
- QQmlBinding *b = newBinding(QQmlEnginePrivate::get(ctxt), property);
+ QQmlBinding *b = newBinding(property);
b->setNotifyOnValueChanged(true);
b->QQmlJavaScriptExpression::setContext(ctxt);
@@ -140,7 +105,14 @@ QQmlBinding *QQmlBinding::create(
const QQmlPropertyData *property, QV4::Function *function, QObject *obj,
const QQmlRefPointer<QQmlContextData> &ctxt, QV4::ExecutionContext *scope)
{
- QQmlBinding *b = newBinding(QQmlEnginePrivate::get(ctxt), property);
+ return create(property ? property->propType() : QMetaType(), function, obj, ctxt, scope);
+}
+
+QQmlBinding *QQmlBinding::create(QMetaType propertyType, QV4::Function *function, QObject *obj,
+ const QQmlRefPointer<QQmlContextData> &ctxt,
+ QV4::ExecutionContext *scope)
+{
+ QQmlBinding *b = newBinding(propertyType);
b->setNotifyOnValueChanged(true);
b->QQmlJavaScriptExpression::setContext(ctxt);
@@ -168,7 +140,7 @@ void QQmlBinding::update(QQmlPropertyData::WriteFlags flags)
// Check for a binding update loop
if (Q_UNLIKELY(updatingFlag())) {
- QQmlPropertyData *d = nullptr;
+ const QQmlPropertyData *d = nullptr;
QQmlPropertyData vtd;
getPropertyData(&d, &vtd);
Q_ASSERT(d);
@@ -211,81 +183,44 @@ QV4::ReturnedValue QQmlBinding::evaluate(bool *isUndefined)
thisObject = &b->d()->boundThis;
}
QV4::Scope scope(v4);
- QV4::JSCallData jsCall(scope, argc, argv, thisObject);
+ QV4::JSCallData jsCall(thisObject, argv, argc);
- return QQmlJavaScriptExpression::evaluate(jsCall.callData(), isUndefined);
+ return QQmlJavaScriptExpression::evaluate(jsCall.callData(scope), isUndefined);
}
-
-// QQmlBindingBinding is for target properties which are of type "binding" (instead of, say, int or
-// double). The reason for being is that GenericBinding::fastWrite needs a compile-time constant
-// expression for the switch for the compiler to generate the optimal code, but
-// qMetaTypeId<QQmlBinding *>() needs to be used for the ID. So QQmlBinding::newBinding uses that
-// to instantiate this class.
-class QQmlBindingBinding: public QQmlBinding
-{
-protected:
- void doUpdate(const DeleteWatcher &,
- QQmlPropertyData::WriteFlags flags, QV4::Scope &) override final
- {
- Q_ASSERT(!m_targetIndex.hasValueTypeIndex());
- QQmlPropertyData *pd = nullptr;
- getPropertyData(&pd, nullptr);
- QQmlBinding *thisPtr = this;
- pd->writeProperty(m_target.data(), &thisPtr, flags);
- }
-};
-
-// For any target that's not a binding, we have a common doUpdate. However, depending on the type
-// of the target property, there is a specialized write method.
-class QQmlNonbindingBinding: public QQmlBinding
+template<int StaticPropType>
+class GenericBinding: public QQmlBinding
{
protected:
- void doUpdate(const DeleteWatcher &watcher,
- QQmlPropertyData::WriteFlags flags, QV4::Scope &scope) override
+ // Returns true if successful, false if an error description was set on expression
+ Q_ALWAYS_INLINE bool write(void *result, QMetaType type, bool isUndefined,
+ QQmlPropertyData::WriteFlags flags) override final
{
- auto ep = QQmlEnginePrivate::get(scope.engine);
- ep->referenceScarceResources();
-
- bool isUndefined = false;
-
- QV4::ScopedValue result(scope, evaluate(&isUndefined));
-
- bool error = false;
- if (!watcher.wasDeleted() && isAddedToObject() && !hasError())
- error = !write(result, isUndefined, flags);
-
- if (!watcher.wasDeleted()) {
+ const QQmlPropertyData *pd;
+ QQmlPropertyData vpd;
+ getPropertyData(&pd, &vpd);
+ Q_ASSERT(pd);
- if (error) {
- delayedError()->setErrorLocation(sourceLocation());
- delayedError()->setErrorObject(m_target.data());
- }
+ if (isUndefined || vpd.isValid())
+ return slowWrite(*pd, vpd, result, type, isUndefined, flags);
- if (hasError()) {
- if (!delayedError()->addError(ep)) ep->warning(this->error(engine()));
- } else {
- clearError();
- }
+ if ((StaticPropType == QMetaType::UnknownType && pd->propType() == type)
+ || StaticPropType == type.id()) {
+ Q_ASSERT(targetObject());
+ return pd->writeProperty(targetObject(), result, flags);
}
- ep->dereferenceScarceResources();
+ // If the type didn't match, we need to do JavaScript conversion. This should be rare.
+ return write(engine()->handle()->metaTypeToJS(type, result), isUndefined, flags);
}
- virtual bool write(const QV4::Value &result, bool isUndefined, QQmlPropertyData::WriteFlags flags) = 0;
-};
-
-template<int StaticPropType>
-class GenericBinding: public QQmlNonbindingBinding
-{
-protected:
// Returns true if successful, false if an error description was set on expression
Q_ALWAYS_INLINE bool write(const QV4::Value &result, bool isUndefined,
QQmlPropertyData::WriteFlags flags) override final
{
Q_ASSERT(targetObject());
- QQmlPropertyData *pd;
+ const QQmlPropertyData *pd;
QQmlPropertyData vpd;
getPropertyData(&pd, &vpd);
Q_ASSERT(pd);
@@ -305,7 +240,7 @@ protected:
if (result.isInteger())
return doStore<int>(result.integerValue(), pd, flags);
else if (result.isNumber()) {
- return doStore<int>(QV4::StaticValue::toInteger(result.doubleValue()), pd, flags);
+ return doStore<int>(result.toInt32(), pd, flags);
}
break;
case QMetaType::Double:
@@ -322,7 +257,7 @@ protected:
break;
default:
if (const QV4::QQmlValueTypeWrapper *vtw = result.as<const QV4::QQmlValueTypeWrapper>()) {
- if (vtw->d()->valueType()->metaType == pd->propType()) {
+ if (vtw->d()->metaType() == pd->propType()) {
return vtw->write(m_target.data(), pd->coreIndex());
}
}
@@ -341,19 +276,19 @@ protected:
}
};
-class QQmlTranslationBinding : public GenericBinding<QMetaType::QString> {
+class QQmlTranslationBinding : public GenericBinding<QMetaType::QString>, public QPropertyObserver {
public:
- QQmlTranslationBinding(const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit, const QV4::CompiledData::Binding *binding)
+ QQmlTranslationBinding(const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit)
+ : QPropertyObserver(&QQmlTranslationBinding::onLanguageChange)
{
setCompilationUnit(compilationUnit);
- m_binding = binding;
+ setSource(QQmlEnginePrivate::get(compilationUnit->engine)->translationLanguage);
}
- QQmlSourceLocation sourceLocation() const override final
- {
- return QQmlSourceLocation(m_compilationUnit->fileName(), m_binding->valueLocation.line, m_binding->valueLocation.column);
- }
+ virtual QString bindingValue() const = 0;
+ static void onLanguageChange(QPropertyObserver *observer, QUntypedPropertyData *)
+ { static_cast<QQmlTranslationBinding *>(observer)->update(); }
void doUpdate(const DeleteWatcher &watcher,
QQmlPropertyData::WriteFlags flags, QV4::Scope &scope) override final
@@ -364,11 +299,11 @@ public:
if (!isAddedToObject() || hasError())
return;
- const QString result = m_compilationUnit->bindingValueAsString(m_binding);
+ const QString result = this->bindingValue();
Q_ASSERT(targetObject());
- QQmlPropertyData *pd;
+ const QQmlPropertyData *pd;
QQmlPropertyData vpd;
getPropertyData(&pd, &vpd);
Q_ASSERT(pd);
@@ -381,9 +316,56 @@ public:
}
bool hasDependencies() const override final { return true; }
+};
-private:
+class QQmlTranslationBindingFromBinding : public QQmlTranslationBinding
+{
const QV4::CompiledData::Binding *m_binding;
+
+public:
+ QQmlTranslationBindingFromBinding(
+ const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit,
+ const QV4::CompiledData::Binding *binding)
+ : QQmlTranslationBinding(compilationUnit), m_binding(binding)
+ {
+ }
+
+ QString bindingValue() const override
+ {
+ return this->m_compilationUnit->bindingValueAsString(m_binding);
+ }
+
+ QQmlSourceLocation sourceLocation() const override final
+ {
+ return QQmlSourceLocation(m_compilationUnit->fileName(), m_binding->valueLocation.line(),
+ m_binding->valueLocation.column());
+ }
+};
+
+class QQmlTranslationBindingFromTranslationInfo : public QQmlTranslationBinding
+{
+ QQmlTranslation m_translationData;
+
+ quint16 m_line;
+ quint16 m_column;
+
+public:
+ QQmlTranslationBindingFromTranslationInfo(
+ const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit,
+ const QQmlTranslation &translationData, quint16 line, quint16 column)
+ : QQmlTranslationBinding(compilationUnit),
+ m_translationData(translationData),
+ m_line(line),
+ m_column(column)
+ {
+ }
+
+ virtual QString bindingValue() const override { return m_translationData.translate(); }
+
+ QQmlSourceLocation sourceLocation() const override final
+ {
+ return QQmlSourceLocation(m_compilationUnit->fileName(), m_line, m_column);
+ }
};
QQmlBinding *QQmlBinding::createTranslationBinding(
@@ -391,29 +373,106 @@ QQmlBinding *QQmlBinding::createTranslationBinding(
const QV4::CompiledData::Binding *binding, QObject *obj,
const QQmlRefPointer<QQmlContextData> &ctxt)
{
- QQmlTranslationBinding *b = new QQmlTranslationBinding(unit, binding);
+ QQmlTranslationBinding *b = new QQmlTranslationBindingFromBinding(unit, binding);
b->setNotifyOnValueChanged(true);
b->QQmlJavaScriptExpression::setContext(ctxt);
b->setScopeObject(obj);
-
+#if QT_CONFIG(translation) && QT_CONFIG(qml_debug)
if (QQmlDebugTranslationService *service
= QQmlDebugConnector::service<QQmlDebugTranslationService>()) {
- service->foundTranslationBinding(b, obj, ctxt);
+ service->foundTranslationBinding(
+ TranslationBindingInformation::create(unit, binding, b->scopeObject(), ctxt));
}
+#endif
+ return b;
+}
+QQmlBinding *QQmlBinding::createTranslationBinding(
+ const QQmlRefPointer<QV4::ExecutableCompilationUnit> &unit,
+ const QQmlRefPointer<QQmlContextData> &ctxt, const QString &propertyName,
+ const QQmlTranslation &translationData, const QQmlSourceLocation &location, QObject *obj)
+{
+ QQmlTranslationBinding *b = new QQmlTranslationBindingFromTranslationInfo(
+ unit, translationData, location.column, location.line);
+
+ b->setNotifyOnValueChanged(true);
+ b->QQmlJavaScriptExpression::setContext(ctxt);
+ b->setScopeObject(obj);
+
+#if QT_CONFIG(translation) && QT_CONFIG(qml_debug)
+ QString originString;
+ if (QQmlDebugTranslationService *service =
+ QQmlDebugConnector::service<QQmlDebugTranslationService>()) {
+ service->foundTranslationBinding({ unit, b->scopeObject(), ctxt,
+
+ propertyName, translationData,
+
+ location.line, location.column });
+ }
+#else
+ Q_UNUSED(propertyName)
+#endif
return b;
}
+bool QQmlBinding::slowWrite(
+ const QQmlPropertyData &core, const QQmlPropertyData &valueTypeData, const void *result,
+ QMetaType resultType, bool isUndefined, QQmlPropertyData::WriteFlags flags)
+{
+ // The logic in this method is obscure. It follows what the other slowWrite does, minus the type
+ // conversions and the checking for binding functions. If you're writing a C++ type, and
+ // you're passing a binding function wrapped into QJSValue, you probably want it to be assigned.
+
+ if (hasError())
+ return false;
+
+ QQmlEngine *qmlEngine = engine();
+ const QMetaType metaType = valueTypeData.isValid() ? valueTypeData.propType() : core.propType();
+ QQmlJavaScriptExpression::DeleteWatcher watcher(this);
+
+ if (core.isVarProperty()) {
+ QQmlVMEMetaObject *vmemo = QQmlVMEMetaObject::get(m_target.data());
+ Q_ASSERT(vmemo);
+ vmemo->setVMEProperty(core.coreIndex(),
+ qmlEngine->handle()->metaTypeToJS(resultType, result));
+ } else if (isUndefined && core.isResettable()) {
+ void *args[] = { nullptr };
+ QMetaObject::metacall(m_target.data(), QMetaObject::ResetProperty, core.coreIndex(), args);
+ } else if (isUndefined && metaType == QMetaType::fromType<QVariant>()) {
+ QQmlPropertyPrivate::writeValueProperty(
+ m_target.data(), core, valueTypeData, QVariant(), context(), flags);
+ } else if (metaType == QMetaType::fromType<QJSValue>()) {
+ QQmlPropertyPrivate::writeValueProperty(
+ m_target.data(), core, valueTypeData,
+ QVariant(resultType, result), context(), flags);
+ } else if (isUndefined) {
+ const char *name = metaType.name();
+ const QString typeName = name
+ ? QString::fromUtf8(name)
+ : QStringLiteral("[unknown property type]");
+ delayedError()->setErrorDescription(
+ QStringLiteral("Unable to assign [undefined] to ") + typeName);
+ return false;
+ } else if (!QQmlPropertyPrivate::writeValueProperty(
+ m_target.data(), core, valueTypeData, QVariant(resultType, result),
+ context(), flags)) {
+ if (watcher.wasDeleted())
+ return true;
+ handleWriteError(result, resultType, metaType);
+ return false;
+ }
+
+ return true;
+}
+
Q_NEVER_INLINE bool QQmlBinding::slowWrite(const QQmlPropertyData &core,
const QQmlPropertyData &valueTypeData,
const QV4::Value &result,
bool isUndefined, QQmlPropertyData::WriteFlags flags)
{
- QQmlEngine *qmlEngine = engine();
- QV4::ExecutionEngine *v4engine = qmlEngine->handle();
-
- const int type = valueTypeData.isValid() ? valueTypeData.propType().id() : core.propType().id();
+ const QMetaType metaType = valueTypeData.isValid() ? valueTypeData.propType() : core.propType();
+ const int type = metaType.id();
QQmlJavaScriptExpression::DeleteWatcher watcher(this);
@@ -422,13 +481,20 @@ Q_NEVER_INLINE bool QQmlBinding::slowWrite(const QQmlPropertyData &core,
if (isUndefined) {
} else if (core.isQList()) {
- value = v4engine->toVariant(result, qMetaTypeId<QList<QObject *> >());
+ if (core.propType().flags() & QMetaType::IsQmlList)
+ value = QV4::ExecutionEngine::toVariant(result, QMetaType::fromType<QList<QObject*>>());
+ else
+ value = QV4::ExecutionEngine::toVariant(result, core.propType());
} else if (result.isNull() && core.isQObject()) {
value = QVariant::fromValue((QObject *)nullptr);
- } else if (core.propType().id() == qMetaTypeId<QList<QUrl> >()) {
- value = QQmlPropertyPrivate::urlSequence(v4engine->toVariant(result, qMetaTypeId<QList<QUrl>>()));
- } else if (!isVarProperty && type != qMetaTypeId<QJSValue>()) {
- value = v4engine->toVariant(result, type);
+ } else if (core.propType() == QMetaType::fromType<QList<QUrl>>()) {
+ const QVariant resultVariant
+ = QV4::ExecutionEngine::toVariant(result, QMetaType::fromType<QList<QUrl>>());
+ value = QVariant::fromValue(QQmlPropertyPrivate::resolveUrlsOnAssignment()
+ ? QQmlPropertyPrivate::urlSequence(resultVariant, context())
+ : QQmlPropertyPrivate::urlSequence(resultVariant));
+ } else if (!isVarProperty && metaType != QMetaType::fromType<QJSValue>()) {
+ value = QV4::ExecutionEngine::toVariant(result, metaType);
}
if (hasError()) {
@@ -445,12 +511,13 @@ Q_NEVER_INLINE bool QQmlBinding::slowWrite(const QQmlPropertyData &core,
QQmlVMEMetaObject *vmemo = QQmlVMEMetaObject::get(m_target.data());
Q_ASSERT(vmemo);
vmemo->setVMEProperty(core.coreIndex(), result);
- } else if (isUndefined && core.isResettable()) {
- void *args[] = { nullptr };
- QMetaObject::metacall(m_target.data(), QMetaObject::ResetProperty, core.coreIndex(), args);
- } else if (isUndefined && type == qMetaTypeId<QVariant>()) {
+ } else if (isUndefined
+ && (valueTypeData.isValid() ? valueTypeData.isResettable() : core.isResettable())) {
+ QQmlPropertyPrivate::resetValueProperty(
+ m_target.data(), core, valueTypeData, context(), flags);
+ } else if (isUndefined && type == QMetaType::QVariant) {
QQmlPropertyPrivate::writeValueProperty(m_target.data(), core, valueTypeData, QVariant(), context(), flags);
- } else if (type == qMetaTypeId<QJSValue>()) {
+ } else if (metaType == QMetaType::fromType<QJSValue>()) {
const QV4::FunctionObject *f = result.as<QV4::FunctionObject>();
if (f && f->isBinding()) {
delayedError()->setErrorDescription(QLatin1String("Invalid use of Qt.binding() in a binding declaration."));
@@ -476,41 +543,45 @@ Q_NEVER_INLINE bool QQmlBinding::slowWrite(const QQmlPropertyData &core,
if (watcher.wasDeleted())
return true;
+ handleWriteError(value.constData(), value.metaType(), metaType);
+ return false;
+ }
- const char *valueType = nullptr;
- const char *propertyType = nullptr;
-
- const int userType = value.userType();
- if (userType == QMetaType::QObjectStar) {
- if (QObject *o = *(QObject *const *)value.constData()) {
- valueType = o->metaObject()->className();
+ return true;
+}
- QQmlMetaObject propertyMetaObject = QQmlPropertyPrivate::rawMetaObjectForType(QQmlEnginePrivate::get(qmlEngine), type);
- if (!propertyMetaObject.isNull())
- propertyType = propertyMetaObject.className();
- }
- } else if (userType != QMetaType::UnknownType) {
- if (userType == QMetaType::Nullptr || userType == QMetaType::VoidStar)
- valueType = "null";
- else
- valueType = QMetaType(userType).name();
+void QQmlBinding::handleWriteError(const void *result, QMetaType resultType, QMetaType metaType)
+{
+ const char *valueType = nullptr;
+ const char *propertyType = nullptr;
+
+ if (resultType.flags() & QMetaType::PointerToQObject) {
+ if (QObject *o = *(QObject *const *)result) {
+ valueType = o->metaObject()->className();
+ QQmlMetaObject propertyMetaObject = QQmlPropertyPrivate::rawMetaObjectForType(metaType);
+ if (!propertyMetaObject.isNull())
+ propertyType = propertyMetaObject.className();
+ }
+ } else if (resultType.isValid()) {
+ if (resultType == QMetaType::fromType<std::nullptr_t>()
+ || resultType == QMetaType::fromType<void *>()) {
+ valueType = "null";
+ } else {
+ valueType = resultType.name();
}
-
- if (!valueType)
- valueType = "undefined";
- if (!propertyType)
- propertyType = QMetaType(type).name();
- if (!propertyType)
- propertyType = "[unknown property type]";
-
- delayedError()->setErrorDescription(QLatin1String("Unable to assign ") +
- QLatin1String(valueType) +
- QLatin1String(" to ") +
- QLatin1String(propertyType));
- return false;
}
- return true;
+ if (!valueType)
+ valueType = "undefined";
+ if (!propertyType)
+ propertyType = metaType.name();
+ if (!propertyType)
+ propertyType = "[unknown property type]";
+
+ delayedError()->setErrorDescription(QStringLiteral("Unable to assign ")
+ + QString::fromUtf8(valueType)
+ + QStringLiteral(" to ")
+ + QString::fromUtf8(propertyType));
}
QVariant QQmlBinding::evaluate()
@@ -526,7 +597,7 @@ QVariant QQmlBinding::evaluate()
ep->dereferenceScarceResources();
- return scope.engine->toVariant(result, qMetaTypeId<QList<QObject*> >());
+ return QV4::ExecutionEngine::toVariant(result, QMetaType::fromType<QList<QObject*> >());
}
void QQmlBinding::expressionChanged()
@@ -544,12 +615,7 @@ void QQmlBinding::setEnabled(bool e, QQmlPropertyData::WriteFlags flags)
const bool wasEnabled = enabledFlag();
setEnabledFlag(e);
setNotifyOnValueChanged(e);
-
- m_nextBinding.setTag(m_nextBinding.tag().setFlag(CanUseAccessor)); // Always use accessors, only not when:
- if (auto interceptorMetaObject = QQmlInterceptorMetaObject::get(targetObject())) {
- if (!m_targetIndex.isValid() || interceptorMetaObject->intercepts(m_targetIndex))
- m_nextBinding.setTag(m_nextBinding.tag().setFlag(CanUseAccessor, false));
- }
+ updateCanUseAccessor();
if (e && !wasEnabled)
update(flags);
@@ -560,85 +626,6 @@ QString QQmlBinding::expression() const
return QStringLiteral("function() { [native code] }");
}
-void QQmlBinding::setTarget(const QQmlProperty &prop)
-{
- auto pd = QQmlPropertyPrivate::get(prop);
- setTarget(prop.object(), pd->core, &pd->valueTypeData);
-}
-
-bool QQmlBinding::setTarget(QObject *object, const QQmlPropertyData &core, const QQmlPropertyData *valueType)
-{
- m_target = object;
-
- if (!object) {
- m_targetIndex = QQmlPropertyIndex();
- return false;
- }
-
- int coreIndex = core.coreIndex();
- int valueTypeIndex = valueType ? valueType->coreIndex() : -1;
- for (bool isAlias = core.isAlias(); isAlias; ) {
- QQmlVMEMetaObject *vme = QQmlVMEMetaObject::getForProperty(object, coreIndex);
-
- int aValueTypeIndex;
- if (!vme->aliasTarget(coreIndex, &object, &coreIndex, &aValueTypeIndex)) {
- // can't resolve id (yet)
- m_target = nullptr;
- m_targetIndex = QQmlPropertyIndex();
- return false;
- }
- if (valueTypeIndex == -1)
- valueTypeIndex = aValueTypeIndex;
-
- QQmlData *data = QQmlData::get(object, false);
- if (!data || !data->propertyCache) {
- m_target = nullptr;
- m_targetIndex = QQmlPropertyIndex();
- return false;
- }
- QQmlPropertyData *propertyData = data->propertyCache->property(coreIndex);
- Q_ASSERT(propertyData);
-
- m_target = object;
- isAlias = propertyData->isAlias();
- coreIndex = propertyData->coreIndex();
- }
- m_targetIndex = QQmlPropertyIndex(coreIndex, valueTypeIndex);
-
- QQmlData *data = QQmlData::get(m_target.data(), true);
- if (!data->propertyCache) {
- data->propertyCache = QQmlEnginePrivate::get(engine())->cache(m_target->metaObject());
- data->propertyCache->addref();
- }
-
- return true;
-}
-
-void QQmlBinding::getPropertyData(QQmlPropertyData **propertyData, QQmlPropertyData *valueTypeData) const
-{
- Q_ASSERT(propertyData);
-
- QQmlData *data = QQmlData::get(m_target.data(), false);
- Q_ASSERT(data);
-
- if (Q_UNLIKELY(!data->propertyCache)) {
- data->propertyCache = QQmlEnginePrivate::get(engine())->cache(m_target->metaObject());
- data->propertyCache->addref();
- }
-
- *propertyData = data->propertyCache->property(m_targetIndex.coreIndex());
- Q_ASSERT(*propertyData);
-
- if (Q_UNLIKELY(m_targetIndex.hasValueTypeIndex() && valueTypeData)) {
- const QMetaObject *valueTypeMetaObject = QQmlMetaType::metaObjectForMetaType((*propertyData)->propType());
- Q_ASSERT(valueTypeMetaObject);
- QMetaProperty vtProp = valueTypeMetaObject->property(m_targetIndex.valueTypeIndex());
- valueTypeData->setFlags(QQmlPropertyData::flagsForProperty(vtProp));
- valueTypeData->setPropType(vtProp.metaType());
- valueTypeData->setCoreIndex(m_targetIndex.valueTypeIndex());
- }
-}
-
QVector<QQmlProperty> QQmlBinding::dependencies() const
{
QVector<QQmlProperty> dependencies;
@@ -660,33 +647,132 @@ QVector<QQmlProperty> QQmlBinding::dependencies() const
for (int i = 0; i < senderMeta->propertyCount(); i++) {
QMetaProperty property = senderMeta->property(i);
if (property.notifySignalIndex() == QMetaObjectPrivate::signal(senderMeta, guard->signalIndex()).methodIndex()) {
- dependencies.push_back(QQmlProperty(senderObject, QString::fromUtf8(senderObject->metaObject()->property(i).name())));
+ dependencies.push_back(QQmlProperty(senderObject, QString::fromUtf8(property.name())));
}
}
}
+ for (auto trigger = qpropertyChangeTriggers; trigger; trigger = trigger->next) {
+ QMetaProperty prop = trigger->property();
+ if (prop.isValid())
+ dependencies.push_back(QQmlProperty(trigger->target, QString::fromUtf8(prop.name())));
+ }
+
return dependencies;
}
bool QQmlBinding::hasDependencies() const
{
- return !activeGuards.isEmpty() || translationsCaptured() || qpropertyChangeTriggers;
+ return !activeGuards.isEmpty() || qpropertyChangeTriggers;
}
-class QObjectPointerBinding: public QQmlNonbindingBinding
+void QQmlBinding::doUpdate(const DeleteWatcher &watcher, QQmlPropertyData::WriteFlags flags, QV4::Scope &scope)
+{
+ auto ep = QQmlEnginePrivate::get(scope.engine);
+ ep->referenceScarceResources();
+
+ bool error = false;
+ auto canWrite = [&]() { return !watcher.wasDeleted() && isAddedToObject() && !hasError(); };
+ const QV4::Function *v4Function = function();
+ if (v4Function && v4Function->kind == QV4::Function::AotCompiled && !hasBoundFunction()) {
+ const auto returnType = v4Function->aotCompiledFunction.types[0];
+ if (returnType == QMetaType::fromType<QVariant>()) {
+ QVariant result;
+ const bool isUndefined = !evaluate(&result, returnType);
+ if (canWrite())
+ error = !write(result.data(), result.metaType(), isUndefined, flags);
+ } else {
+ const auto size = returnType.sizeOf();
+ if (Q_LIKELY(size > 0)) {
+ Q_ALLOCA_VAR(void, result, size);
+ if (returnType.flags() & QMetaType::NeedsConstruction)
+ returnType.construct(result);
+ const bool isUndefined = !evaluate(result, returnType);
+ if (canWrite())
+ error = !write(result, returnType, isUndefined, flags);
+ if (returnType.flags() & QMetaType::NeedsDestruction)
+ returnType.destruct(result);
+ } else if (canWrite()) {
+ error = !write(QV4::Encode::undefined(), true, flags);
+ }
+ }
+ } else {
+ bool isUndefined = false;
+ QV4::ScopedValue result(scope, evaluate(&isUndefined));
+ if (canWrite())
+ error = !write(result, isUndefined, flags);
+ }
+
+ if (!watcher.wasDeleted()) {
+
+ if (error) {
+ delayedError()->setErrorLocation(sourceLocation());
+ delayedError()->setErrorObject(m_target.data());
+ }
+
+ if (hasError()) {
+ if (!delayedError()->addError(ep)) ep->warning(this->error(engine()));
+ } else {
+ clearError();
+ }
+ }
+
+ ep->dereferenceScarceResources();
+}
+
+class QObjectPointerBinding: public QQmlBinding
{
QQmlMetaObject targetMetaObject;
public:
- QObjectPointerBinding(QQmlEnginePrivate *engine, int propertyType)
- : targetMetaObject(QQmlPropertyPrivate::rawMetaObjectForType(engine, propertyType))
+ QObjectPointerBinding(QMetaType propertyType)
+ : targetMetaObject(QQmlPropertyPrivate::rawMetaObjectForType(propertyType))
{}
protected:
+ Q_ALWAYS_INLINE bool write(void *result, QMetaType type, bool isUndefined,
+ QQmlPropertyData::WriteFlags flags) override final
+ {
+ const QQmlPropertyData *pd;
+ QQmlPropertyData vtpd;
+ getPropertyData(&pd, &vtpd);
+ if (Q_UNLIKELY(isUndefined || vtpd.isValid()))
+ return slowWrite(*pd, vtpd, result, type, isUndefined, flags);
+
+ // Check if the result is a QObject:
+ QObject *resultObject = nullptr;
+ QQmlMetaObject resultMo;
+ const auto typeFlags = type.flags();
+ if (!result || ((typeFlags & QMetaType::IsPointer) && !*static_cast<void **>(result))) {
+ // Special case: we can always write a nullptr. Don't bother checking anything else.
+ return pd->writeProperty(targetObject(), &resultObject, flags);
+ } else if (typeFlags & QMetaType::PointerToQObject) {
+ resultObject = *static_cast<QObject **>(result);
+ if (!resultObject)
+ return pd->writeProperty(targetObject(), &resultObject, flags);
+ if (QQmlData *ddata = QQmlData::get(resultObject, false))
+ resultMo = ddata->propertyCache;
+ if (resultMo.isNull())
+ resultMo = resultObject->metaObject();
+ } else if (type == QMetaType::fromType<QVariant>()) {
+ const QVariant value = *static_cast<QVariant *>(result);
+ resultMo = QQmlPropertyPrivate::rawMetaObjectForType(value.metaType());
+ if (resultMo.isNull())
+ return slowWrite(*pd, vtpd, result, type, isUndefined, flags);
+ resultObject = *static_cast<QObject *const *>(value.constData());
+ } else {
+ return slowWrite(*pd, vtpd, result, type, isUndefined, flags);
+ }
+
+ return compareAndSet(resultMo, resultObject, pd, flags, [&]() {
+ return slowWrite(*pd, vtpd, result, type, isUndefined, flags);
+ });
+ }
+
Q_ALWAYS_INLINE bool write(const QV4::Value &result, bool isUndefined,
QQmlPropertyData::WriteFlags flags) override final
{
- QQmlPropertyData *pd;
+ const QQmlPropertyData *pd;
QQmlPropertyData vtpd;
getPropertyData(&pd, &vtpd);
if (Q_UNLIKELY(isUndefined || vtpd.isValid()))
@@ -708,10 +794,8 @@ protected:
resultMo = resultObject->metaObject();
}
} else if (auto variant = result.as<QV4::VariantObject>()) {
- QVariant value = variant->d()->data();
- QQmlEngine *qmlEngine = engine();
- resultMo = QQmlPropertyPrivate::rawMetaObjectForType(
- qmlEngine ? QQmlEnginePrivate::get(qmlEngine) : nullptr, value.userType());
+ const QVariant value = variant->d()->data();
+ resultMo = QQmlPropertyPrivate::rawMetaObjectForType(value.metaType());
if (resultMo.isNull())
return slowWrite(*pd, vtpd, result, isUndefined, flags);
resultObject = *static_cast<QObject *const *>(value.constData());
@@ -719,7 +803,18 @@ protected:
return slowWrite(*pd, vtpd, result, isUndefined, flags);
}
- // Compare & set:
+ return compareAndSet(resultMo, resultObject, pd, flags, [&]() {
+ return slowWrite(*pd, vtpd, result, isUndefined, flags);
+ });
+ }
+
+private:
+ using QQmlBinding::slowWrite;
+
+ template<typename SlowWrite>
+ bool compareAndSet(const QQmlMetaObject &resultMo, QObject *resultObject, const QQmlPropertyData *pd,
+ QQmlPropertyData::WriteFlags flags, const SlowWrite &slowWrite) const
+ {
if (QQmlMetaObject::canConvert(resultMo, targetMetaObject)) {
return pd->writeProperty(targetObject(), &resultObject, flags);
} else if (!resultObject && QQmlMetaObject::canConvert(targetMetaObject, resultMo)) {
@@ -728,23 +823,22 @@ protected:
// the property type.
return pd->writeProperty(targetObject(), &resultObject, flags);
} else {
- return slowWrite(*pd, vtpd, result, isUndefined, flags);
+ return slowWrite();
}
}
};
-QQmlBinding *QQmlBinding::newBinding(QQmlEnginePrivate *engine, const QQmlPropertyData *property)
+QQmlBinding *QQmlBinding::newBinding(const QQmlPropertyData *property)
{
- if (property && property->isQObject())
- return new QObjectPointerBinding(engine, property->propType().id());
-
- const int type = property ? property->propType().id() : QMetaType::UnknownType;
+ return newBinding(property ? property->propType() : QMetaType());
+}
- if (type == qMetaTypeId<QQmlBinding *>()) {
- return new QQmlBindingBinding;
- }
+QQmlBinding *QQmlBinding::newBinding(QMetaType propertyType)
+{
+ if (propertyType.flags() & QMetaType::PointerToQObject)
+ return new QObjectPointerBinding(propertyType);
- switch (type) {
+ switch (propertyType.id()) {
case QMetaType::Bool:
return new GenericBinding<QMetaType::Bool>;
case QMetaType::Int:
diff --git a/src/qml/qml/qqmlbinding_p.h b/src/qml/qml/qqmlbinding_p.h
index bf73c24c9e..4031a2655e 100644
--- a/src/qml/qml/qqmlbinding_p.h
+++ b/src/qml/qml/qqmlbinding_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLBINDING_P_H
#define QQMLBINDING_P_H
@@ -51,12 +15,8 @@
// We mean it.
//
-#include "qqml.h"
-#include "qqmlpropertyvaluesource.h"
-#include "qqmlexpression.h"
#include "qqmlproperty.h"
#include "qqmlscriptstring.h"
-#include "qqmlproperty_p.h"
#include <QtCore/QObject>
#include <QtCore/QMetaProperty>
@@ -64,11 +24,12 @@
#include <private/qqmlabstractbinding_p.h>
#include <private/qqmljavascriptexpression_p.h>
#include <private/qv4functionobject_p.h>
+#include <private/qqmltranslation_p.h>
QT_BEGIN_NAMESPACE
class QQmlContext;
-class Q_QML_PRIVATE_EXPORT QQmlBinding : public QQmlJavaScriptExpression,
+class Q_QML_EXPORT QQmlBinding : public QQmlJavaScriptExpression,
public QQmlAbstractBinding
{
friend class QQmlAbstractBinding;
@@ -86,16 +47,26 @@ public:
const QQmlPropertyData *property, QV4::Function *function, QObject *obj,
const QQmlRefPointer<QQmlContextData> &ctxt, QV4::ExecutionContext *scope);
+ static QQmlBinding *create(QMetaType propertyType, QV4::Function *function, QObject *obj,
+ const QQmlRefPointer<QQmlContextData> &ctxt,
+ QV4::ExecutionContext *scope);
+
static QQmlBinding *createTranslationBinding(
const QQmlRefPointer<QV4::ExecutableCompilationUnit> &unit,
const QV4::CompiledData::Binding *binding, QObject *obj,
const QQmlRefPointer<QQmlContextData> &ctxt);
- ~QQmlBinding() override;
+ static QQmlBinding *
+ createTranslationBinding(const QQmlRefPointer<QV4::ExecutableCompilationUnit> &unit,
+ const QQmlRefPointer<QQmlContextData> &ctxt,
+ const QString &propertyName, const QQmlTranslation &translationData,
+ const QQmlSourceLocation &location, QObject *obj);
- void setTarget(const QQmlProperty &);
- bool setTarget(QObject *, const QQmlPropertyData &, const QQmlPropertyData *valueType);
+ Kind kind() const final { return QQmlAbstractBinding::QmlBinding; }
+
+ ~QQmlBinding() override;
+ bool mustCaptureBindableProperty() const final {return true;}
void refresh() override;
void setEnabled(bool, QQmlPropertyData::WriteFlags flags = QQmlPropertyData::DontRemoveBinding) override;
@@ -108,6 +79,10 @@ public:
};
QVariant evaluate();
+ bool evaluate(void *result, QMetaType type)
+ {
+ return QQmlJavaScriptExpression::evaluate(&result, &type, 0);
+ }
void expressionChanged() override;
@@ -116,6 +91,7 @@ public:
void setBoundFunction(QV4::BoundFunction *boundFunction) {
m_boundFunction.set(boundFunction->engine(), *boundFunction);
}
+ bool hasBoundFunction() const { return m_boundFunction.valueRef(); }
/**
* This method returns a snapshot of the currently tracked dependencies of
@@ -125,52 +101,35 @@ public:
* Call this method from the UI thread.
*/
QVector<QQmlProperty> dependencies() const;
+ // This method is used internally to check whether a binding is constant and can be removed
virtual bool hasDependencies() const;
protected:
virtual void doUpdate(const DeleteWatcher &watcher,
- QQmlPropertyData::WriteFlags flags, QV4::Scope &scope) = 0;
+ QQmlPropertyData::WriteFlags flags, QV4::Scope &scope);
+
+ virtual bool write(const QV4::Value &result, bool isUndefined, QQmlPropertyData::WriteFlags flags) = 0;
+ virtual bool write(void *result, QMetaType type, bool isUndefined, QQmlPropertyData::WriteFlags flags) = 0;
- void getPropertyData(QQmlPropertyData **propertyData, QQmlPropertyData *valueTypeData) const;
int getPropertyType() const;
bool slowWrite(const QQmlPropertyData &core, const QQmlPropertyData &valueTypeData,
const QV4::Value &result, bool isUndefined, QQmlPropertyData::WriteFlags flags);
+ bool slowWrite(const QQmlPropertyData &core, const QQmlPropertyData &valueTypeData,
+ const void *result, QMetaType resultType, bool isUndefined,
+ QQmlPropertyData::WriteFlags flags);
QV4::ReturnedValue evaluate(bool *isUndefined);
private:
- inline bool updatingFlag() const;
- inline void setUpdatingFlag(bool);
- inline bool enabledFlag() const;
- inline void setEnabledFlag(bool);
-
- static QQmlBinding *newBinding(QQmlEnginePrivate *engine, const QQmlPropertyData *property);
+ static QQmlBinding *newBinding(const QQmlPropertyData *property);
+ static QQmlBinding *newBinding(QMetaType propertyType);
QQmlSourceLocation *m_sourceLocation = nullptr; // used for Qt.binding() created functions
QV4::PersistentValue m_boundFunction; // used for Qt.binding() that are created from a bound function object
+ void handleWriteError(const void *result, QMetaType resultType, QMetaType metaType);
};
-bool QQmlBinding::updatingFlag() const
-{
- return m_target.tag().testFlag(UpdatingBinding);
-}
-
-void QQmlBinding::setUpdatingFlag(bool v)
-{
- m_target.setTag(m_target.tag().setFlag(UpdatingBinding, v));
-}
-
-bool QQmlBinding::enabledFlag() const
-{
- return m_target.tag().testFlag(BindingEnabled);
-}
-
-void QQmlBinding::setEnabledFlag(bool v)
-{
- m_target.setTag(m_target.tag().setFlag(BindingEnabled, v));
-}
-
QT_END_NAMESPACE
Q_DECLARE_METATYPE(QQmlBinding*)
diff --git a/src/qml/qml/qqmlboundsignal.cpp b/src/qml/qml/qqmlboundsignal.cpp
index 9e1e056381..3f9ce26764 100644
--- a/src/qml/qml/qqmlboundsignal.cpp
+++ b/src/qml/qml/qqmlboundsignal.cpp
@@ -1,51 +1,11 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qqmlboundsignal_p.h"
#include <private/qmetaobject_p.h>
#include <private/qmetaobjectbuilder_p.h>
#include "qqmlengine_p.h"
-#include "qqmlexpression_p.h"
-#include "qqmlcontext_p.h"
-#include "qqml.h"
-#include "qqmlcontext.h"
#include "qqmlglobal_p.h"
#include <private/qqmlprofiler_p.h>
#include <private/qqmldebugconnector_p.h>
@@ -64,6 +24,10 @@
QT_BEGIN_NAMESPACE
+Q_TRACE_POINT(qtqml, QQmlHandlingSignal_entry, const QQmlEngine *engine, const QString &function,
+ const QString &fileName, int line, int column)
+Q_TRACE_POINT(qtqml, QQmlHandlingSignal_exit)
+
QQmlBoundSignalExpression::QQmlBoundSignalExpression(const QObject *target, int index, const QQmlRefPointer<QQmlContextData> &ctxt, QObject *scope,
const QString &expression, const QString &fileName, quint16 line, quint16 column,
const QString &handlerName, const QString &parameterString)
@@ -114,12 +78,7 @@ QQmlBoundSignalExpression::QQmlBoundSignalExpression(const QObject *target, int
QV4::ExecutionEngine *engine = ctxt->engine()->handle();
- // If the function is marked as having a nested function, then the user wrote:
- // onSomeSignal: function() { /*....*/ }
- // So take that nested function:
- if (auto closure = function->nestedFunction()) {
- function = closure;
- } else {
+ if (!function->isClosureWrapper()) {
QList<QByteArray> signalParameters = QMetaObjectPrivate::signal(m_target->metaObject(), m_index).parameterNames();
if (!signalParameters.isEmpty()) {
QString error;
@@ -136,7 +95,29 @@ QQmlBoundSignalExpression::QQmlBoundSignalExpression(const QObject *target, int
QV4::Scoped<QV4::QmlContext> qmlContext(valueScope, scope);
if (!qmlContext)
qmlContext = QV4::QmlContext::create(engine->rootContext(), ctxt, scopeObject);
- setupFunction(qmlContext, function);
+ if (auto closure = function->nestedFunction()) {
+ // If the function is marked as having a nested function, then the user wrote:
+ // onSomeSignal: function() { /*....*/ }
+ // So take that nested function:
+ setupFunction(qmlContext, closure);
+ } else {
+ setupFunction(qmlContext, function);
+
+ // If it's a closure wrapper but we cannot directly access the nested function
+ // we need to run the outer function to get the nested one.
+ if (function->isClosureWrapper()) {
+ bool isUndefined = false;
+ QV4::ScopedFunctionObject result(
+ valueScope, QQmlJavaScriptExpression::evaluate(&isUndefined));
+
+ Q_ASSERT(!isUndefined);
+ Q_ASSERT(result->function());
+ Q_ASSERT(result->function()->compilationUnit == function->compilationUnit);
+
+ QV4::Scoped<QV4::ExecutionContext> callContext(valueScope, result->scope());
+ setupFunction(callContext, result->function());
+ }
+ }
}
void QQmlBoundSignalExpression::init(const QQmlRefPointer<QQmlContextData> &ctxt, QObject *scope)
@@ -171,55 +152,52 @@ QString QQmlBoundSignalExpression::expression() const
return QString();
}
-// Parts of this function mirror code in QQmlExpressionPrivate::value() and v8value().
+// Parts of this function mirror code in QQmlExpressionPrivate::value() and v4Value().
// Changes made here may need to be made there and vice versa.
void QQmlBoundSignalExpression::evaluate(void **a)
{
- Q_ASSERT (engine());
-
if (!expressionFunctionValid())
return;
QQmlEngine *qmlengine = engine();
- QQmlEnginePrivate *ep = QQmlEnginePrivate::get(qmlengine);
- QV4::ExecutionEngine *v4 = qmlengine->handle();
- QV4::Scope scope(v4);
-
- ep->referenceScarceResources(); // "hold" scarce resources in memory during evaluation.
- QQmlMetaObject::ArgTypeStorage storage;
- //TODO: lookup via signal index rather than method index as an optimization
- int methodIndex = QMetaObjectPrivate::signal(m_target->metaObject(), m_index).methodIndex();
- bool ok = QQmlMetaObject(m_target).methodParameterTypes(methodIndex, &storage, nullptr);
- const int argCount = ok ? storage.size() : 0;
-
- QV4::JSCallData jsCall(scope, argCount);
- populateJSCallArguments(v4, jsCall, argCount, a, storage.constData());
-
- QQmlJavaScriptExpression::evaluate(jsCall.callData(), nullptr);
-
- ep->dereferenceScarceResources(); // "release" scarce resources if top-level expression evaluation is complete.
-}
-
-void QQmlBoundSignalExpression::evaluate(const QList<QVariant> &args)
-{
- Q_ASSERT (engine());
-
- if (!expressionFunctionValid())
+ // If there is no engine, we have no way to evaluate anything.
+ // This can happen on destruction.
+ if (!qmlengine)
return;
- QQmlEngine *qmlengine = engine();
QQmlEnginePrivate *ep = QQmlEnginePrivate::get(qmlengine);
- QV4::Scope scope(qmlengine->handle());
+ QV4::ExecutionEngine *v4 = qmlengine->handle();
+ QV4::Scope scope(v4);
ep->referenceScarceResources(); // "hold" scarce resources in memory during evaluation.
- QV4::JSCallData jsCall(scope, args.count());
- for (int ii = 0; ii < args.count(); ++ii) {
- jsCall->args[ii] = scope.engine->fromVariant(args[ii]);
- }
+ if (a) {
+ //TODO: lookup via signal index rather than method index as an optimization
+ const QMetaObject *targetMeta = m_target->metaObject();
+ const QMetaMethod metaMethod = targetMeta->method(
+ QMetaObjectPrivate::signal(targetMeta, m_index).methodIndex());
+
+ int argCount = metaMethod.parameterCount();
+ QQmlMetaObject::ArgTypeStorage<9> storage;
+ storage.reserve(argCount + 1);
+ storage.append(QMetaType()); // We're not interested in the return value
+ for (int i = 0; i < argCount; ++i) {
+ const QMetaType type = metaMethod.parameterMetaType(i);
+ if (!type.isValid())
+ argCount = 0;
+ else if (type.flags().testFlag(QMetaType::IsEnumeration))
+ storage.append(type.underlyingType());
+ else
+ storage.append(type);
+ }
- QQmlJavaScriptExpression::evaluate(jsCall.callData(), nullptr);
+ QQmlJavaScriptExpression::evaluate(a, storage.constData(), argCount);
+ } else {
+ void *ignoredResult = nullptr;
+ QMetaType invalidType;
+ QQmlJavaScriptExpression::evaluate(&ignoredResult, &invalidType, 0);
+ }
ep->dereferenceScarceResources(); // "release" scarce resources if top-level expression evaluation is complete.
}
@@ -235,7 +213,7 @@ QQmlBoundSignal::QQmlBoundSignal(QObject *target, int signal, QObject *owner,
QQmlEngine *engine)
: QQmlNotifierEndpoint(QQmlNotifierEndpoint::QQmlBoundSignal),
m_prevSignal(nullptr), m_nextSignal(nullptr),
- m_enabled(true), m_expression(nullptr)
+ m_enabled(true)
{
addToObject(owner);
@@ -345,7 +323,7 @@ void QQmlBoundSignal_callback(QQmlNotifierEndpoint *e, void **a)
QQmlPropertyObserver::QQmlPropertyObserver(QQmlBoundSignalExpression *expr)
: QPropertyObserver([](QPropertyObserver *self, QUntypedPropertyData *) {
auto This = static_cast<QQmlPropertyObserver*>(self);
- This->expression->evaluate(QList<QVariant>());
+ This->expression->evaluate(nullptr);
})
{
expression.adopt(expr);
diff --git a/src/qml/qml/qqmlboundsignal_p.h b/src/qml/qml/qqmlboundsignal_p.h
index 075053b95e..9eab562f56 100644
--- a/src/qml/qml/qqmlboundsignal_p.h
+++ b/src/qml/qml/qqmlboundsignal_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLBOUNDSIGNAL_P_H
#define QQMLBOUNDSIGNAL_P_H
@@ -55,14 +19,16 @@
#include <private/qqmljavascriptexpression_p.h>
#include <private/qqmlnotifier_p.h>
-#include <private/qflagpointer_p.h>
#include <private/qqmlrefcount_p.h>
-#include <private/qqmlglobal_p.h>
+#include <private/qtqmlglobal_p.h>
QT_BEGIN_NAMESPACE
-class Q_QML_PRIVATE_EXPORT QQmlBoundSignalExpression : public QQmlJavaScriptExpression, public QQmlRefCount
+class Q_QML_EXPORT QQmlBoundSignalExpression final
+ : public QQmlJavaScriptExpression,
+ public QQmlRefCounted<QQmlBoundSignalExpression>
{
+ friend class QQmlRefCounted<QQmlBoundSignalExpression>;
public:
QQmlBoundSignalExpression(
const QObject *target, int index, const QQmlRefPointer<QQmlContextData> &ctxt, QObject *scope,
@@ -79,7 +45,8 @@ public:
// evaluation of a bound signal expression doesn't return any value
void evaluate(void **a);
- void evaluate(const QList<QVariant> &args);
+
+ bool mustCaptureBindableProperty() const final {return true;}
QString expression() const;
const QObject *target() const { return m_target; }
@@ -95,7 +62,7 @@ private:
const QObject *m_target;
};
-class Q_QML_PRIVATE_EXPORT QQmlBoundSignal : public QQmlNotifierEndpoint
+class Q_QML_EXPORT QQmlBoundSignal : public QQmlNotifierEndpoint
{
public:
QQmlBoundSignal(QObject *target, int signal, QObject *owner, QQmlEngine *engine);
diff --git a/src/qml/qml/v8/qqmlbuiltinfunctions.cpp b/src/qml/qml/qqmlbuiltinfunctions.cpp
index d4e3b39752..5c6daa0969 100644
--- a/src/qml/qml/v8/qqmlbuiltinfunctions.cpp
+++ b/src/qml/qml/qqmlbuiltinfunctions.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qqmlbuiltinfunctions_p.h"
@@ -84,7 +48,9 @@
QT_BEGIN_NAMESPACE
-Q_LOGGING_CATEGORY(lcRootProperties, "qml.rootObjectProperties");
+Q_LOGGING_CATEGORY(lcRootProperties, "qt.qml.rootObjectProperties");
+Q_LOGGING_CATEGORY(lcQml, "qml");
+Q_LOGGING_CATEGORY(lcJs, "js");
using namespace QV4;
@@ -93,16 +59,231 @@ using namespace QV4;
return scope.engine->throwTypeError(QString::fromUtf8(msg)); \
} while (false)
+/*!
+\qmltype Qt
+\inqmlmodule QtQml
+//! \instantiates QQmlEnginePrivate
+\ingroup qml-utility-elements
+\keyword QmlGlobalQtObject
+\brief Provides a global object with useful enums and functions from Qt.
+
+\c Qt is a singleton type that provides utility functions, properties, and
+enums. Here is an example showing how to use this type:
+
+\qml
+import QtQuick 2.0
+
+Text {
+ color: Qt.rgba(1, 0, 0, 1)
+ text: Qt.md5("hello, world")
+}
+\endqml
+
+
+\section1 Enums
+
+The Qt object contains the enums available in the \l [QtCore]{Qt}{Qt Namespace}. For example, you can access
+the \l Qt::LeftButton and \l Qt::RightButton enumeration values as \c Qt.LeftButton and \c Qt.RightButton.
+
+
+\section1 Types
+\target globalqtobjecttypes
+
+The Qt object also contains helper functions for creating objects of specific
+data types. This is primarily useful when setting the properties of an item
+when the property has one of the following types:
+\list
+\li \c rect - use \l{Qt::rect()}{Qt.rect()}
+\li \c point - use \l{Qt::point()}{Qt.point()}
+\li \c size - use \l{Qt::size()}{Qt.size()}
+\endlist
+
+If the \c QtQuick module has been imported, the following helper functions for
+creating objects of specific data types are also available for clients to use:
+\list
+\li \c color - use \l{Qt::rgba()}{Qt.rgba()}, \l{Qt::hsla()}{Qt.hsla()}, \l{Qt::darker()}{Qt.darker()}, \l{Qt::lighter()}{Qt.lighter()} or \l{Qt::tint()}{Qt.tint()}
+\li \c font - use \l{Qt::font()}{Qt.font()}
+\li \c vector2d - use \l{Qt::vector2d()}{Qt.vector2d()}
+\li \c vector3d - use \l{Qt::vector3d()}{Qt.vector3d()}
+\li \c vector4d - use \l{Qt::vector4d()}{Qt.vector4d()}
+\li \c quaternion - use \l{Qt::quaternion()}{Qt.quaternion()}
+\li \c matrix4x4 - use \l{Qt::matrix4x4()}{Qt.matrix4x4()}
+\endlist
+
+\section1 Date/Time Formatters
+
+The Qt object contains several functions for formatting QDateTime, QDate and QTime values.
+
+\list
+ \li \l{Qt::formatDateTime}{string Qt.formatDateTime(datetime date, variant format)}
+ \li \l{Qt::formatDate}{string Qt.formatDate(datetime date, variant format)}
+ \li \l{Qt::formatTime}{string Qt.formatTime(datetime date, variant format)}
+\endlist
+
+The format specification is described at \l{Qt::formatDateTime}{Qt.formatDateTime}.
+
+
+\section1 Dynamic Object Creation
+The following functions on the global object allow you to dynamically create QML
+items from files or strings. See \l{Dynamic QML Object Creation from JavaScript} for an overview
+of their use.
+
+\list
+ \li \l{Qt::createComponent()}{object Qt.createComponent(url)}
+ \li \l{Qt::createQmlObject()}{object Qt.createQmlObject(string qml, object parent, string filepath)}
+\endlist
+
+
+\section1 Other Functions
+
+The following functions are also on the Qt object.
+
+\list
+ \li \l{Qt::quit()}{Qt.quit()}
+ \li \l{Qt::md5()}{Qt.md5(string)}
+ \li \l{Qt::btoa()}{string Qt.btoa(string)}
+ \li \l{Qt::atob()}{string Qt.atob(string)}
+ \li \l{Qt::binding()}{object Qt.binding(function)}
+ \li \l{Qt::locale()}{object Qt.locale()}
+ \li \l{Qt::resolvedUrl()}{string Qt.resolvedUrl(string)}
+ \li \l{Qt::openUrlExternally()}{Qt.openUrlExternally(string)}
+ \li \l{Qt::fontFamilies()}{list<string> Qt.fontFamilies()}
+\endlist
+*/
+
+/*!
+ \qmlproperty object Qt::platform
+ \since 5.1
+
+ The \c platform object provides info about the underlying platform.
+
+ Its properties are:
+
+ \table
+ \row
+ \li \c platform.os
+ \li
+
+ This read-only property contains the name of the operating system.
+
+ Possible values are:
+
+ \list
+ \li \c "android" - Android
+ \li \c "ios" - iOS
+ \li \c "tvos" - tvOS
+ \li \c "linux" - Linux
+ \li \c "osx" - \macos
+ \li \c "qnx" - QNX (since Qt 5.9.3)
+ \li \c "unix" - Other Unix-based OS
+ \li \c "windows" - Windows
+ \li \c "wasm" - WebAssembly
+ \endlist
+
+ \row
+ \li \c platform.pluginName
+ \li This is the name of the platform set on the QGuiApplication instance
+ as returned by \l QGuiApplication::platformName()
+
+ \endtable
+*/
+
+/*!
+ \qmlproperty Application Qt::application
+ \since 5.1
+
+ The \c application object provides access to global application state
+ properties shared by many QML components.
+
+ It is the same as the \l Application singleton.
+
+ The following example uses the \c application object to indicate
+ whether the application is currently active:
+
+ \snippet qml/application.qml document
+
+ \note When using QML without a QGuiApplication, the following properties will be undefined:
+ \list
+ \li application.active
+ \li application.state
+ \li application.layoutDirection
+ \li application.font
+ \endlist
+*/
+
+/*!
+ \qmlproperty InputMethod Qt::inputMethod
+ \since 5.0
+
+ It is the same as the \l InputMethod singleton.
+
+ The \c inputMethod object allows access to application's QInputMethod object
+ and all its properties and slots. See the QInputMethod documentation for
+ further details.
+*/
+
+/*!
+ \qmlproperty object Qt::styleHints
+ \since 5.5
+
+ The \c styleHints object provides platform-specific style hints and settings.
+ See the \l QStyleHints documentation for further details.
+
+ You should access StyleHints via \l Application::styleHints instead.
+
+ \note The \c styleHints object is only available when using the Qt Quick module.
+*/
+
+/*!
+\qmlmethod object Qt::include(string url, jsobject callback)
+\deprecated
+
+This method should not be used. Use ECMAScript modules, and the native
+JavaScript \c import and \c export statements instead.
+
+Includes another JavaScript file. This method can only be used from within JavaScript files,
+and not regular QML files.
+
+This imports all functions from \a url into the current script's namespace.
+
+Qt.include() returns an object that describes the status of the operation. The object has
+a single property, \c {status}, that is set to one of the following values:
+
+\table
+\header \li Symbol \li Value \li Description
+\row \li result.OK \li 0 \li The include completed successfully.
+\row \li result.LOADING \li 1 \li Data is being loaded from the network.
+\row \li result.NETWORK_ERROR \li 2 \li A network error occurred while fetching the url.
+\row \li result.EXCEPTION \li 3 \li A JavaScript exception occurred while executing the included code.
+An additional \c exception property will be set in this case.
+\endtable
+
+The \c status property will be updated as the operation progresses.
+
+If provided, \a callback is invoked when the operation completes. The callback is passed
+the same object as is returned from the Qt.include() call.
+*/
+// Qt.include() is implemented in qv4include.cpp
+
QtObject::QtObject(ExecutionEngine *engine)
: m_engine(engine)
{
- QV4::Scope scope(engine);
- QV4::ScopedString callLaterName(scope, engine->newIdentifier(QStringLiteral("callLater")));
+}
- QV4::ScopedFunctionObject function(scope, QV4::FunctionObject::createBuiltinFunction(
- engine, callLaterName, QQmlDelayedCallQueue::addUniquelyAndExecuteLater, 1));
+QtObject::Contexts QtObject::getContexts() const
+{
+ QQmlEngine *engine = qmlEngine();
+ if (!engine)
+ return {};
+
+ QQmlRefPointer<QQmlContextData> context = v4Engine()->callingQmlContext();
+ if (!context)
+ context = QQmlContextData::get(QQmlEnginePrivate::get(engine)->rootContext);
- m_callLater = QJSValuePrivate::fromReturnedValue(function.asReturnedValue());
+ Q_ASSERT(context);
+ QQmlRefPointer<QQmlContextData> effectiveContext
+ = context->isPragmaLibraryContext() ? nullptr : context;
+ return {context, effectiveContext};
}
QtObject *QtObject::create(QQmlEngine *, QJSEngine *jsEngine)
@@ -213,7 +394,7 @@ QVariant QtObject::hsva(double h, double s, double v, double a) const
Returns \c true if both \a lhs and \a rhs yield equal color values. Both
arguments may be either color values or string values. If a string value
is supplied it must be convertible to a color, as described for the
- \l{colorbasictypedocs}{color} basic type.
+ \l{colorvaluetypedocs}{color} value type.
*/
bool QtObject::colorEqual(const QVariant &lhs, const QVariant &rhs) const
{
@@ -281,7 +462,7 @@ QSizeF QtObject::size(double w, double h) const
Returns a font with the properties specified in the \a fontSpecifier object
or the nearest matching font. The \a fontSpecifier object should contain
- key-value pairs where valid keys are the \l{fontbasictypedocs}{font} type's
+ key-value pairs where valid keys are the \l{fontvaluetypedocs}{font} type's
subproperty names, and the values are valid values for each subproperty.
Invalid keys will be ignored.
*/
@@ -293,8 +474,9 @@ QVariant QtObject::font(const QJSValue &fontSpecifier) const
}
{
- QVariant v;
- if (QQml_valueTypeProvider()->createValueType(QMetaType::QFont, fontSpecifier, v))
+ const QVariant v = QQmlValueTypeProvider::createValueType(
+ fontSpecifier, QMetaType(QMetaType::QFont));
+ if (v.isValid())
return v;
}
@@ -323,15 +505,14 @@ void addParameters(QJSEngine *e, QJSValue &result, int i, T parameter, Others...
}
template<typename ...T>
-static QVariant createValueType(QJSEngine *e, QMetaType::Type type, T... parameters)
+static QVariant constructFromJSValue(QJSEngine *e, QMetaType type, T... parameters)
{
if (!e)
return QVariant();
QJSValue params = e->newArray(sizeof...(parameters));
addParameters(e, params, 0, parameters...);
- QVariant variant;
- QQml_valueTypeProvider()->createValueType(type, params, variant);
- return variant;
+ const QVariant variant = QQmlValueTypeProvider::createValueType(params, type);
+ return variant.isValid() ? variant : QVariant(type);
}
/*!
@@ -341,7 +522,7 @@ static QVariant createValueType(QJSEngine *e, QMetaType::Type type, T... paramet
*/
QVariant QtObject::vector2d(double x, double y) const
{
- return createValueType(jsEngine(), QMetaType::QVector2D, x, y);
+ return constructFromJSValue(jsEngine(), QMetaType(QMetaType::QVector2D), x, y);
}
/*!
@@ -351,7 +532,7 @@ QVariant QtObject::vector2d(double x, double y) const
*/
QVariant QtObject::vector3d(double x, double y, double z) const
{
- return createValueType(jsEngine(), QMetaType::QVector3D, x, y, z);
+ return constructFromJSValue(jsEngine(), QMetaType(QMetaType::QVector3D), x, y, z);
}
/*!
@@ -361,7 +542,7 @@ QVariant QtObject::vector3d(double x, double y, double z) const
*/
QVariant QtObject::vector4d(double x, double y, double z, double w) const
{
- return createValueType(jsEngine(), QMetaType::QVector4D, x, y, z, w);
+ return constructFromJSValue(jsEngine(), QMetaType(QMetaType::QVector4D), x, y, z, w);
}
/*!
@@ -371,42 +552,42 @@ QVariant QtObject::vector4d(double x, double y, double z, double w) const
*/
QVariant QtObject::quaternion(double scalar, double x, double y, double z) const
{
- return createValueType(jsEngine(), QMetaType::QQuaternion, scalar, x, y, z);
+ return constructFromJSValue(jsEngine(), QMetaType(QMetaType::QQuaternion), scalar, x, y, z);
}
/*!
- \qmlmethod matrix4x4 Qt::matrix4x4(real m11, real m12, real m13, real m14, real m21, real m22, real m23, real m24, real m31, real m32, real m33, real m34, real m41, real m42, real m43, real m44)
+ \qmlmethod matrix4x4 Qt::matrix4x4()
- Returns a matrix4x4 with the specified values.
+ Returns an identity matrix4x4.
+ */
+QVariant QtObject::matrix4x4() const
+{
+ const QMetaType metaType(QMetaType::QMatrix4x4);
+ const QVariant variant = QQmlValueTypeProvider::createValueType(QJSValue(), metaType);
+ return variant.isValid() ? variant : QVariant(metaType);
+}
- The arguments correspond to their positions in the matrix:
+/*!
+ \qmlmethod matrix4x4 Qt::matrix4x4(var values)
- \table
- \row \li \a m11 \li \a m12 \li \a m13 \li \a m14
- \row \li \a m21 \li \a m22 \li \a m23 \li \a m24
- \row \li \a m31 \li \a m32 \li \a m33 \li \a m34
- \row \li \a m41 \li \a m42 \li \a m43 \li \a m44
- \endtable
+ Returns a matrix4x4 with the specified \a values. \a values is expected to
+ be a JavaScript array with 16 entries.
- Alternatively, the function may be called with a single argument
- where that argument is a JavaScript array which contains the sixteen
- matrix values.
+ The array indices correspond to positions in the matrix as follows:
- Finally, the function may be called with no arguments and the resulting
- matrix will be the identity matrix.
+ \table
+ \row \li 0 \li 1 \li 2 \li 3
+ \row \li 4 \li 5 \li 6 \li 7
+ \row \li 8 \li 9 \li 10 \li 11
+ \row \li 12 \li 13 \li 14 \li 15
+ \endtable
*/
-QVariant QtObject::matrix4x4() const
-{
- QVariant variant;
- QQml_valueTypeProvider()->createValueType(QMetaType::QMatrix4x4, QJSValue(), variant);
- return variant;
-}
-
QVariant QtObject::matrix4x4(const QJSValue &value) const
{
if (value.isObject()) {
- QVariant v;
- if (QQml_valueTypeProvider()->createValueType(QMetaType::QMatrix4x4, value, v))
+ QVariant v = QQmlValueTypeProvider::createValueType(
+ value, QMetaType(QMetaType::QMatrix4x4));
+ if (v.isValid())
return v;
}
@@ -415,12 +596,26 @@ QVariant QtObject::matrix4x4(const QJSValue &value) const
return QVariant();
}
+/*!
+ \qmlmethod matrix4x4 Qt::matrix4x4(real m11, real m12, real m13, real m14, real m21, real m22, real m23, real m24, real m31, real m32, real m33, real m34, real m41, real m42, real m43, real m44)
+
+ Returns a matrix4x4 with the specified values.
+
+ The arguments correspond to their positions in the matrix:
+
+ \table
+ \row \li \a m11 \li \a m12 \li \a m13 \li \a m14
+ \row \li \a m21 \li \a m22 \li \a m23 \li \a m24
+ \row \li \a m31 \li \a m32 \li \a m33 \li \a m34
+ \row \li \a m41 \li \a m42 \li \a m43 \li \a m44
+ \endtable
+*/
QVariant QtObject::matrix4x4(double m11, double m12, double m13, double m14,
double m21, double m22, double m23, double m24,
double m31, double m32, double m33, double m34,
double m41, double m42, double m43, double m44) const
{
- return createValueType(jsEngine(), QMetaType::QMatrix4x4,
+ return constructFromJSValue(jsEngine(), QMetaType(QMetaType::QMatrix4x4),
m11, m12, m13, m14, m21, m22, m23, m24,
m31, m32, m33, m34, m41, m42, m43, m44);
}
@@ -561,6 +756,11 @@ QString formatDateTimeObjectUsingDateFormat(T formatThis, Qt::DateFormat format)
}
}
+static QTime dateTimeToTime(const QDateTime &dateTime)
+{
+ return dateTime.toLocalTime().time();
+}
+
/*!
\qmlmethod string Qt::formatDate(datetime date, variant format, variant localeFormatOption)
@@ -577,22 +777,93 @@ default locale.
\sa Locale
*/
-QString QtObject::formatDate(const QDate &date, const QString &format) const
+static std::optional<QDate> dateFromString(const QString &string, QV4::ExecutionEngine *engine)
+{
+ {
+ const QDate date = QDate::fromString(string, Qt::ISODate);
+ if (date.isValid())
+ return date;
+ }
+
+ {
+ // For historical reasons, the string argument is parsed as datetime, not as only date
+ const QDateTime dateTime = QDateTime::fromString(string, Qt::ISODate);
+ if (dateTime.isValid()) {
+ qCWarning(lcRootProperties())
+ << string << "is a date/time string being passed to formatDate()."
+ << "You should only pass date strings to formatDate().";
+ return dateTime.date();
+ }
+ }
+
+ {
+ // Since we can coerce QDate to QString, allow the resulting string format here.
+ const QDateTime dateTime = DateObject::stringToDateTime(string, engine);
+ if (dateTime.isValid())
+ return DateObject::dateTimeToDate(dateTime);
+ }
+
+ engine->throwError(QStringLiteral("Invalid argument passed to formatDate(): %1").arg(string));
+ return std::nullopt;
+}
+
+QString QtObject::formatDate(QDate date, const QString &format) const
{
return date.toString(format);
}
-QString QtObject::formatDate(const QDate &date, Qt::DateFormat format) const
+QString QtObject::formatDate(QDate date, Qt::DateFormat format) const
{
return formatDateTimeObjectUsingDateFormat(date, format);
}
+QString QtObject::formatDate(const QDateTime &dateTime, const QString &format) const
+{
+ return DateObject::dateTimeToDate(dateTime).toString(format);
+}
+
+QString QtObject::formatDate(const QString &string, const QString &format) const
+{
+ if (const auto qDate = dateFromString(string, v4Engine()))
+ return formatDate(qDate.value(), format);
+
+ return QString();
+}
+
+QString QtObject::formatDate(const QDateTime &dateTime, Qt::DateFormat format) const
+{
+ return formatDateTimeObjectUsingDateFormat(DateObject::dateTimeToDate(dateTime), format);
+}
+
+QString QtObject::formatDate(const QString &string, Qt::DateFormat format) const
+{
+ if (const auto qDate = dateFromString(string, v4Engine()))
+ return formatDate(qDate.value(), format);
+
+ return QString();
+}
+
#if QT_CONFIG(qml_locale)
-QString QtObject::formatDate(const QDate &date, const QLocale &locale,
+QString QtObject::formatDate(QDate date, const QLocale &locale,
QLocale::FormatType formatType) const
{
return locale.toString(date, formatType);
}
+
+QString QtObject::formatDate(const QDateTime &dateTime, const QLocale &locale,
+ QLocale::FormatType formatType) const
+{
+ return locale.toString(DateObject::dateTimeToDate(dateTime), formatType);
+}
+
+QString QtObject::formatDate(const QString &string, const QLocale &locale,
+ QLocale::FormatType formatType) const
+{
+ if (const auto qDate = dateFromString(string, v4Engine()))
+ return locale.toString(qDate.value(), formatType);
+
+ return QString();
+}
#endif
/*!
@@ -630,15 +901,27 @@ static std::optional<QTime> timeFromString(const QString &string, QV4::Execution
}
}
+ {
+ // Since we can coerce QTime to QString, allow the resulting string format here.
+ const QDateTime dateTime = DateObject::stringToDateTime(string, engine);
+ if (dateTime.isValid())
+ return dateTimeToTime(dateTime);
+ }
+
engine->throwError(QStringLiteral("Invalid argument passed to formatTime(): %1").arg(string));
return std::nullopt;
}
-QString QtObject::formatTime(const QTime &time, const QString &format) const
+QString QtObject::formatTime(QTime time, const QString &format) const
{
return time.toString(format);
}
+QString QtObject::formatTime(const QDateTime &dateTime, const QString &format) const
+{
+ return dateTimeToTime(dateTime).toString(format);
+}
+
QString QtObject::formatTime(const QString &time, const QString &format) const
{
@@ -648,11 +931,16 @@ QString QtObject::formatTime(const QString &time, const QString &format) const
return QString();
}
-QString QtObject::formatTime(const QTime &time, Qt::DateFormat format) const
+QString QtObject::formatTime(QTime time, Qt::DateFormat format) const
{
return formatDateTimeObjectUsingDateFormat(time, format);
}
+QString QtObject::formatTime(const QDateTime &dateTime, Qt::DateFormat format) const
+{
+ return formatDateTimeObjectUsingDateFormat(dateTimeToTime(dateTime), format);
+}
+
QString QtObject::formatTime(const QString &time, Qt::DateFormat format) const
{
if (auto qTime = timeFromString(time, v4Engine()))
@@ -662,12 +950,18 @@ QString QtObject::formatTime(const QString &time, Qt::DateFormat format) const
}
#if QT_CONFIG(qml_locale)
-QString QtObject::formatTime(const QTime &time, const QLocale &locale,
+QString QtObject::formatTime(QTime time, const QLocale &locale,
QLocale::FormatType formatType) const
{
return locale.toString(time, formatType);
}
+QString QtObject::formatTime(const QDateTime &dateTime, const QLocale &locale,
+ QLocale::FormatType formatType) const
+{
+ return locale.toString(dateTimeToTime(dateTime), formatType);
+}
+
QString QtObject::formatTime(const QString &time, const QLocale &locale,
QLocale::FormatType formatType) const
{
@@ -776,22 +1070,69 @@ with the \a format values below to produce the following results:
\sa Locale
*/
+static std::optional<QDateTime> dateTimeFromString(const QString &string, QV4::ExecutionEngine *engine)
+{
+ {
+ const QDateTime dateTime = QDateTime::fromString(string, Qt::ISODate);
+ if (dateTime.isValid())
+ return dateTime;
+ }
+
+ {
+ // Since we can coerce QDateTime to QString, allow the resulting string format here.
+ const QDateTime dateTime = DateObject::stringToDateTime(string, engine);
+ if (dateTime.isValid())
+ return dateTime;
+ }
+
+ engine->throwError(QStringLiteral("Invalid argument passed to formatDateTime(): %1").arg(string));
+ return std::nullopt;
+}
+
QString QtObject::formatDateTime(const QDateTime &dateTime, const QString &format) const
{
return dateTime.toString(format);
}
+QString QtObject::formatDateTime(const QString &string, const QString &format) const
+{
+
+ if (const auto qDateTime = dateTimeFromString(string, v4Engine()))
+ return formatDateTime(qDateTime.value(), format);
+
+ return QString();
+}
+
QString QtObject::formatDateTime(const QDateTime &dateTime, Qt::DateFormat format) const
{
return formatDateTimeObjectUsingDateFormat(dateTime, format);
}
+QString QtObject::formatDateTime(const QString &string, Qt::DateFormat format) const
+{
+
+ if (const auto qDateTime = dateTimeFromString(string, v4Engine()))
+ return formatDateTime(qDateTime.value(), format);
+
+ return QString();
+}
+
#if QT_CONFIG(qml_locale)
QString QtObject::formatDateTime(const QDateTime &dateTime, const QLocale &locale,
QLocale::FormatType formatType) const
{
return locale.toString(dateTime, formatType);
}
+
+QString QtObject::formatDateTime(const QString &string, const QLocale &locale,
+ QLocale::FormatType formatType) const
+{
+
+ if (const auto qDateTime = dateTimeFromString(string, v4Engine()))
+ return formatDateTime(qDateTime.value(), locale, formatType);
+
+ return QString();
+}
#endif
/*!
@@ -811,9 +1152,30 @@ bool QtObject::openUrlExternally(const QUrl &url) const
}
/*!
+ \qmlmethod url Qt::url(url url)
+
+ Returns \a url verbatim. This can be used to force a type coercion to \c url.
+ In contrast to Qt.resolvedUrl() this retains any relative URLs. As strings
+ are implicitly converted to urls, the function can be called with a string
+ as argument, and will then return a url.
+
+ \sa resolvedUrl()
+*/
+QUrl QtObject::url(const QUrl &url) const
+{
+ return url;
+}
+
+/*!
\qmlmethod url Qt::resolvedUrl(url url)
Returns \a url resolved relative to the URL of the caller.
+
+ If there is no caller or the caller is not associated with a QML context,
+ returns \a url resolved relative to the QML engine's base URL. If the QML
+ engine has no base URL, just returns \a url.
+
+ \sa url()
*/
QUrl QtObject::resolvedUrl(const QUrl &url) const
{
@@ -825,6 +1187,29 @@ QUrl QtObject::resolvedUrl(const QUrl &url) const
}
/*!
+ \qmlmethod url Qt::resolvedUrl(url url, object context)
+
+ Returns \a url resolved relative to the URL of the QML context of
+ \a context. If \a context is not associated with a QML context,
+ returns \a url resolved relative to the QML engine's base URL. If
+ the QML engine has no base URL, just returns \a url.
+
+ \sa url()
+*/
+QUrl QtObject::resolvedUrl(const QUrl &url, QObject *context) const
+{
+ if (context) {
+ QQmlData *data = QQmlData::get(context);
+ if (data && data->outerContext)
+ return data->outerContext->resolvedUrl(url);
+ }
+
+ if (QQmlEngine *engine = qmlEngine())
+ return engine->baseUrl().resolved(url);
+ return url;
+}
+
+/*!
\qmlmethod list<string> Qt::fontFamilies()
Returns a list of the font families available to the application.
@@ -862,13 +1247,15 @@ QString QtObject::atob(const QString &data) const
}
/*!
-\qmlmethod Qt::quit()
-This function causes the QQmlEngine::quit() signal to be emitted.
-Within the \l {Prototyping with qmlscene}, this causes the launcher application to exit;
-to quit a C++ application when this method is called, connect the
-QQmlEngine::quit() signal to the QCoreApplication::quit() slot.
+ \qmlmethod Qt::quit()
-\sa exit()
+ This function causes the QQmlEngine::quit() signal to be emitted.
+ Within the \l {Prototyping with the QML Runtime Tool}{qml tool},
+ this causes the launcher application to exit; to quit a C++ application
+ when this method is called, connect the QQmlEngine::quit() signal to the
+ QCoreApplication::quit() slot.
+
+ \sa exit()
*/
void QtObject::quit() const
{
@@ -880,7 +1267,8 @@ void QtObject::quit() const
\qmlmethod Qt::exit(int retCode)
This function causes the QQmlEngine::exit(int) signal to be emitted.
- Within the \l {Prototyping with qmlscene}, this causes the launcher application to exit
+ Within the \l {Prototyping with the QML Runtime Tool}{qml tool},
+ this causes the launcher application to exit with
the specified return code (\a retCode). To exit from the event loop with a specified
return code when this method is called, a C++ application can connect the
QQmlEngine::exit(int) signal to the QCoreApplication::exit(int) slot.
@@ -911,10 +1299,15 @@ Each object in this array has the members \c lineNumber, \c columnNumber, \c fil
For example, if the above snippet had misspelled color as 'colro' then the array would contain an object like the following:
{ "lineNumber" : 1, "columnNumber" : 32, "fileName" : "dynamicSnippet1", "message" : "Cannot assign to non-existent property \"colro\""}.
-Note that this function returns immediately, and therefore may not work if
+\note This function returns immediately, and therefore may not work if
the \a qml string loads new components (that is, external QML files that have not yet been loaded).
If this is the case, consider using \l{QtQml::Qt::createComponent()}{Qt.createComponent()} instead.
+\warning This function is extremely slow since it has to compile the passed QML string every time
+it is invoked. Furthermore, it's very easy to produce invalid QML when programmatically constructing
+QML code. It's much better to keep your QML components as separate files and add properties and
+methods to customize their behavior than to produce new components by string manipulation.
+
See \l {Dynamic QML Object Creation from JavaScript} for more information on using this function.
*/
QObject *QtObject::createQmlObject(const QString &qml, QObject *parent, const QUrl &url) const
@@ -937,7 +1330,7 @@ QObject *QtObject::createQmlObject(const QString &qml, QObject *parent, const QU
QV4::ScopedObject qmlerror(scope);
QV4::ScopedString s(scope);
QV4::ScopedValue v(scope);
- for (int ii = 0; ii < errors.count(); ++ii) {
+ for (int ii = 0; ii < errors.size(); ++ii) {
const QQmlError &error = errors.at(ii);
errorstr += QLatin1String("\n ") + error.toString();
qmlerror = v4->newObject();
@@ -1013,7 +1406,7 @@ QObject *QtObject::createQmlObject(const QString &qml, QObject *parent, const QU
obj->setParent(parent);
QList<QQmlPrivate::AutoParentFunction> functions = QQmlMetaType::parentFunctions();
- for (int ii = 0; ii < functions.count(); ++ii) {
+ for (int ii = 0; ii < functions.size(); ++ii) {
if (QQmlPrivate::Parented == functions.at(ii)(obj, parent))
break;
}
@@ -1031,7 +1424,7 @@ QObject *QtObject::createQmlObject(const QString &qml, QObject *parent, const QU
}
/*!
-\qmlmethod object Qt::createComponent(url, mode, parent)
+\qmlmethod Component Qt::createComponent(url url, enumeration mode, QtObject parent)
Returns a \l Component object created using the QML file at the specified \a url,
or \c null if an empty string was given.
@@ -1074,6 +1467,32 @@ See \l {Dynamic QML Object Creation from JavaScript} for more information on usi
To create a QML object from an arbitrary string of QML (instead of a file),
use \l{QtQml::Qt::createQmlObject()}{Qt.createQmlObject()}.
*/
+
+/*!
+\qmlmethod Component Qt::createComponent(string moduleUri, string typeName, enumeration mode, QtObject parent)
+\overload
+Returns a \l Component object created for the type specified by \a moduleUri and \a typeName.
+\qml
+import QtQuick
+QtObject {
+ id: root
+ property Component myComponent: Qt.createComponent("QtQuick", "Rectangle", Component.Asynchronous, root)
+}
+\endqml
+This overload mostly behaves as the \c url based version, but can be used
+to instantiate types which do not have an URL (e.g. C++ types registered
+via \l {QML_ELEMENT}).
+\note In some cases, passing \c Component.Asynchronous won't have any
+effect:
+\list
+\li The type is implemented in C++
+\li The type is an inline component.
+\endlist
+If the optional \a parent parameter is given, it should refer to the object
+that will become the parent for the created \l Component object. If no mode
+was passed, this can be the second argument.
+*/
+
QQmlComponent *QtObject::createComponent(const QUrl &url, QObject *parent) const
{
return createComponent(url, QQmlComponent::PreferSynchronous, parent);
@@ -1094,13 +1513,9 @@ QQmlComponent *QtObject::createComponent(const QUrl &url, QQmlComponent::Compila
if (!engine)
return nullptr;
- QQmlRefPointer<QQmlContextData> context = v4Engine()->callingQmlContext();
+ auto [context, effectiveContext] = getContexts();
if (!context)
- context = QQmlContextData::get(QQmlEnginePrivate::get(engine)->rootContext);
-
- Q_ASSERT(context);
- QQmlRefPointer<QQmlContextData> effectiveContext
- = context->isPragmaLibraryContext() ? nullptr : context;
+ return nullptr;
QQmlComponent *c = new QQmlComponent(engine, context->resolvedUrl(url), mode, parent);
QQmlComponentPrivate::get(c)->creationContext = effectiveContext;
@@ -1109,6 +1524,41 @@ QQmlComponent *QtObject::createComponent(const QUrl &url, QQmlComponent::Compila
return c;
}
+QQmlComponent *QtObject::createComponent(const QString &moduleUri, const QString &typeName,
+ QObject *parent) const
+{
+ return createComponent(moduleUri, typeName, QQmlComponent::PreferSynchronous, parent);
+}
+
+QQmlComponent *QtObject::createComponent(const QString &moduleUri, const QString &typeName, QQmlComponent::CompilationMode mode, QObject *parent) const
+{
+ if (mode != QQmlComponent::Asynchronous && mode != QQmlComponent::PreferSynchronous) {
+ v4Engine()->throwError(QStringLiteral("Invalid compilation mode %1").arg(mode));
+ return nullptr;
+ }
+
+ QQmlEngine *engine = qmlEngine();
+ if (!engine)
+ return nullptr;
+
+ if (moduleUri.isEmpty() || typeName.isEmpty())
+ return nullptr;
+
+ auto [context, effectiveContext] = getContexts();
+ if (!context)
+ return nullptr;
+
+ QQmlComponent *c = new QQmlComponent(engine, moduleUri, typeName, mode, parent);
+ if (c->isError() && !parent && moduleUri.endsWith(u".qml")) {
+ v4Engine()->throwTypeError(
+ QStringLiteral("Invalid arguments; did you swap mode and parent"));
+ }
+ QQmlComponentPrivate::get(c)->creationContext = effectiveContext;
+ QQmlData::get(c, true)->explicitIndestructibleSet = false;
+ QQmlData::get(c)->indestructible = false;
+ return c;
+}
+
#if QT_CONFIG(translation)
QString QtObject::uiLanguage() const
{
@@ -1238,6 +1688,11 @@ QJSValue QtObject::binding(const QJSValue &function) const
Encode(e->memoryManager->allocate<QQmlBindingFunction>(f)));
}
+void QtObject::callLater(QQmlV4FunctionPtr args)
+{
+ m_engine->delayedCallQueue()->addUniquelyAndExecuteLater(m_engine, args);
+}
+
QQmlPlatform *QtObject::platform()
{
@@ -1265,11 +1720,6 @@ QObject *QtObject::styleHints() const
return QQml_guiProvider()->styleHints();
}
-QJSValue QtObject::callLater() const
-{
- return m_callLater;
-}
-
void QV4::Heap::ConsoleObject::init()
{
Object::init();
@@ -1303,21 +1753,22 @@ enum ConsoleLogTypes {
static QString jsStack(QV4::ExecutionEngine *engine) {
QString stack;
- QVector<QV4::StackFrame> stackTrace = engine->stackTrace(10);
-
- for (int i = 0; i < stackTrace.count(); i++) {
- const QV4::StackFrame &frame = stackTrace.at(i);
-
+ int i = 0;
+ for (CppStackFrame *f = engine->currentStackFrame; f && i < 10; f = f->parentFrame(), ++i) {
QString stackFrame;
- if (frame.column >= 0)
- stackFrame = QStringLiteral("%1 (%2:%3:%4)").arg(frame.function,
- frame.source,
- QString::number(frame.line),
- QString::number(frame.column));
- else
- stackFrame = QStringLiteral("%1 (%2:%3)").arg(frame.function,
- frame.source,
- QString::number(frame.line));
+
+ if (f->isJSTypesFrame() && static_cast<JSTypesStackFrame *>(f)->isTailCalling()) {
+ stackFrame = QStringLiteral("[elided tail calls]");
+ } else {
+ const int line = f->lineNumber();
+ if (line != f->missingLineNumber()) {
+ stackFrame = QStringLiteral("%1 (%2:%3)").arg(
+ f->function(), f->source(), QString::number(qAbs(line)));
+ } else {
+ stackFrame = QStringLiteral("%1 (%2)").arg(
+ f->function(), f->source());
+ }
+ }
if (i)
stack += QLatin1Char('\n');
@@ -1354,7 +1805,7 @@ static QString serializeArray(Object *array, ExecutionEngine *v4, QSet<QV4::Heap
static ReturnedValue writeToConsole(const FunctionObject *b, const Value *argv, int argc,
ConsoleLogTypes logType, bool printStack = false)
{
- QLoggingCategory *loggingCategory = nullptr;
+ const QLoggingCategory *loggingCategory = nullptr;
QString result;
QV4::Scope scope(b);
QV4::ExecutionEngine *v4 = scope.engine;
@@ -1387,11 +1838,8 @@ static ReturnedValue writeToConsole(const FunctionObject *b, const Value *argv,
if (printStack)
result += QLatin1Char('\n') + jsStack(v4);
- static QLoggingCategory qmlLoggingCategory("qml");
- static QLoggingCategory jsLoggingCategory("js");
-
if (!loggingCategory)
- loggingCategory = v4->qmlEngine() ? &qmlLoggingCategory : &jsLoggingCategory;
+ loggingCategory = v4->qmlEngine() ? &lcQml() : &lcJs();
QV4::CppStackFrame *frame = v4->currentStackFrame;
const QByteArray baSource = frame ? frame->source().toUtf8() : QByteArray();
const QByteArray baFunction = frame ? frame->function().toUtf8() : QByteArray();
@@ -1546,7 +1994,7 @@ ReturnedValue ConsoleObject::method_trace(const FunctionObject *b, const Value *
QV4::CppStackFrame *frame = v4->currentStackFrame;
QMessageLogger(frame->source().toUtf8().constData(), frame->lineNumber(),
frame->function().toUtf8().constData())
- .debug("%s", qPrintable(stack));
+ .debug(v4->qmlEngine() ? lcQml : lcJs, "%s", qPrintable(stack));
return QV4::Encode::undefined();
}
@@ -1648,7 +2096,7 @@ void QV4::GlobalExtensions::init(Object *globalObject, QJSEngine::Extensions ext
Example:
\snippet qml/qsTranslate.qml 0
- \sa {Internationalization and Localization with Qt Quick}
+ \sa {Internationalization with Qt}
*/
ReturnedValue GlobalExtensions::method_qsTranslate(const FunctionObject *b, const Value *, const Value *argv, int argc)
{
@@ -1709,7 +2157,7 @@ ReturnedValue GlobalExtensions::method_qsTranslate(const FunctionObject *b, cons
Example:
\snippet qml/qtTranslateNoOp.qml 0
- \sa {Internationalization and Localization with Qt Quick}
+ \sa {Internationalization with Qt}
*/
ReturnedValue GlobalExtensions::method_qsTranslateNoOp(const FunctionObject *b, const Value *, const Value *argv, int argc)
{
@@ -1720,6 +2168,46 @@ ReturnedValue GlobalExtensions::method_qsTranslateNoOp(const FunctionObject *b,
return argv[1].asReturnedValue();
}
+QString GlobalExtensions::currentTranslationContext(ExecutionEngine *engine)
+{
+ QString context;
+ CppStackFrame *frame = engine->currentStackFrame;
+
+ // The first non-empty source URL in the call stack determines the translation context.
+ while (frame && context.isEmpty()) {
+ if (ExecutableCompilationUnit *unit = frame->v4Function->executableCompilationUnit()) {
+ auto translationContextIndex = unit->unitData()->translationContextIndex();
+ if (translationContextIndex)
+ context = unit->stringAt(*translationContextIndex);
+ if (!context.isEmpty())
+ break;
+ QString fileName = unit->fileName();
+ QUrl url(unit->fileName());
+ if (url.isValid() && url.isRelative()) {
+ context = url.fileName();
+ } else {
+ context = QQmlFile::urlToLocalFileOrQrc(fileName);
+ if (context.isEmpty() && fileName.startsWith(QLatin1String(":/")))
+ context = fileName;
+ }
+ context = QFileInfo(context).completeBaseName();
+ }
+ frame = frame->parentFrame();
+ }
+
+ if (context.isEmpty()) {
+ if (QQmlRefPointer<QQmlContextData> ctxt = engine->callingQmlContext()) {
+ QString path = ctxt->urlString();
+ int lastSlash = path.lastIndexOf(QLatin1Char('/'));
+ int lastDot = path.lastIndexOf(QLatin1Char('.'));
+ int length = lastDot - (lastSlash + 1);
+ context = (lastSlash > -1) ? path.mid(lastSlash + 1, (length > -1) ? length : -1) : QString();
+ }
+ }
+
+ return context;
+}
+
/*!
\qmlmethod string Qt::qsTr(string sourceText, string disambiguation, int n)
@@ -1735,7 +2223,7 @@ ReturnedValue GlobalExtensions::method_qsTranslateNoOp(const FunctionObject *b,
Example:
\snippet qml/qsTr.qml 0
- \sa {Internationalization and Localization with Qt Quick}
+ \sa {Internationalization with Qt}
*/
ReturnedValue GlobalExtensions::method_qsTr(const FunctionObject *b, const Value *, const Value *argv, int argc)
{
@@ -1749,43 +2237,10 @@ ReturnedValue GlobalExtensions::method_qsTr(const FunctionObject *b, const Value
if ((argc > 2) && !argv[2].isNumber())
THROW_GENERIC_ERROR("qsTr(): third argument (n) must be a number");
- QString context;
- CppStackFrame *frame = scope.engine->currentStackFrame;
- // The first non-empty source URL in the call stack determines the translation context.
- while (frame && context.isEmpty()) {
- if (CompiledData::CompilationUnitBase *baseUnit = frame->v4Function->compilationUnit) {
- const auto *unit = static_cast<const CompiledData::CompilationUnit *>(baseUnit);
- QString fileName = unit->fileName();
- QUrl url(unit->fileName());
- if (url.isValid() && url.isRelative()) {
- context = url.fileName();
- } else {
- context = QQmlFile::urlToLocalFileOrQrc(fileName);
- if (context.isEmpty() && fileName.startsWith(QLatin1String(":/")))
- context = fileName;
- }
- context = QFileInfo(context).baseName();
- }
- frame = frame->parent;
- }
-
- if (context.isEmpty()) {
- if (QQmlRefPointer<QQmlContextData> ctxt = scope.engine->callingQmlContext()) {
- QString path = ctxt->urlString();
- int lastSlash = path.lastIndexOf(QLatin1Char('/'));
- int lastDot = path.lastIndexOf(QLatin1Char('.'));
- int length = lastDot - (lastSlash + 1);
- context = (lastSlash > -1) ? path.mid(lastSlash + 1, (length > -1) ? length : -1) : QString();
- }
- }
-
- QString text = argv[0].toQStringNoThrow();
- QString comment;
- if (argc > 1)
- comment = argv[1].toQStringNoThrow();
- int n = -1;
- if (argc > 2)
- n = argv[2].toInt32();
+ const QString context = currentTranslationContext(scope.engine);
+ const QString text = argv[0].toQStringNoThrow();
+ const QString comment = argc > 1 ? argv[1].toQStringNoThrow() : QString();
+ const int n = argc > 2 ? argv[2].toInt32() : -1;
if (QQmlEnginePrivate *ep = (scope.engine->qmlEngine() ? QQmlEnginePrivate::get(scope.engine->qmlEngine()) : nullptr))
if (ep->propertyCapture)
@@ -1817,7 +2272,7 @@ ReturnedValue GlobalExtensions::method_qsTr(const FunctionObject *b, const Value
Example:
\snippet qml/qtTrNoOp.qml 0
- \sa {Internationalization and Localization with Qt Quick}
+ \sa {Internationalization with Qt}
*/
ReturnedValue GlobalExtensions::method_qsTrNoOp(const FunctionObject *, const Value *, const Value *argv, int argc)
{
@@ -1855,7 +2310,7 @@ ReturnedValue GlobalExtensions::method_qsTrNoOp(const FunctionObject *, const Va
Creating binary translation (QM) files suitable for use with this function requires passing
the \c -idbased option to the \c lrelease tool.
- \sa QT_TRID_NOOP(), {Internationalization and Localization with Qt Quick}
+ \sa QT_TRID_NOOP(), {Internationalization with Qt}
*/
ReturnedValue GlobalExtensions::method_qsTrId(const FunctionObject *b, const Value *, const Value *argv, int argc)
{
@@ -1892,7 +2347,7 @@ ReturnedValue GlobalExtensions::method_qsTrId(const FunctionObject *b, const Val
Example:
\snippet qml/qtTrIdNoOp.qml 0
- \sa qsTrId(), {Internationalization and Localization with Qt Quick}
+ \sa qsTrId(), {Internationalization with Qt}
*/
ReturnedValue GlobalExtensions::method_qsTrIdNoOp(const FunctionObject *, const Value *, const Value *argv, int argc)
{
@@ -1903,16 +2358,23 @@ ReturnedValue GlobalExtensions::method_qsTrIdNoOp(const FunctionObject *, const
}
#endif // translation
+/*!
+ \qmlmethod void Qt::gc()
+
+ Runs the garbage collector.
+
+ This is equivalent to calling QJSEngine::collectGarbage().
+ \sa {Garbage Collection}
+*/
ReturnedValue GlobalExtensions::method_gc(const FunctionObject *b, const Value *, const Value *, int)
{
- b->engine()->memoryManager->runGC();
+ auto mm = b->engine()->memoryManager;
+ mm->runFullGC();
return QV4::Encode::undefined();
}
-
-
ReturnedValue GlobalExtensions::method_string_arg(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
{
QV4::Scope scope(b);
@@ -1952,10 +2414,7 @@ be passed on to the function invoked. Note that if redundant calls
are eliminated, then only the last set of arguments will be passed to the
function.
*/
-ReturnedValue QtObject::method_callLater(const FunctionObject *b, const Value *thisObject,
- const Value *argv, int argc)
-{
- return b->engine()->delayedCallQueue()->addUniquelyAndExecuteLater(b, thisObject, argv, argc);
-}
QT_END_NAMESPACE
+
+#include "moc_qqmlbuiltinfunctions_p.cpp"
diff --git a/src/qml/qml/v8/qqmlbuiltinfunctions_p.h b/src/qml/qml/qqmlbuiltinfunctions_p.h
index 972a0d0b31..9ceedad28b 100644
--- a/src/qml/qml/v8/qqmlbuiltinfunctions_p.h
+++ b/src/qml/qml/qqmlbuiltinfunctions_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLBUILTINFUNCTIONS_P_H
#define QQMLBUILTINFUNCTIONS_P_H
@@ -51,15 +15,17 @@
// We mean it.
//
-#include <private/qqmlglobal_p.h>
-#include <private/qv4functionobject_p.h>
#include <private/qjsengine_p.h>
+#include <private/qqmlglobal_p.h>
#include <private/qqmlplatform_p.h>
+#include <private/qv4functionobject_p.h>
+
#include <QtCore/qnamespace.h>
#include <QtCore/qdatetime.h>
#include <QtCore/qsize.h>
#include <QtCore/qrect.h>
#include <QtCore/qpoint.h>
+
#include <QtQml/qqmlcomponent.h>
#include <QtQml/qqmlengine.h>
@@ -72,7 +38,6 @@ class Q_QML_EXPORT QtObject : public QObject
Q_PROPERTY(QQmlPlatform *platform READ platform CONSTANT)
Q_PROPERTY(QObject *inputMethod READ inputMethod CONSTANT)
Q_PROPERTY(QObject *styleHints READ styleHints CONSTANT)
- Q_PROPERTY(QJSValue callLater READ callLater CONSTANT)
#if QT_CONFIG(translation)
Q_PROPERTY(QString uiLanguage READ uiLanguage WRITE setUiLanguage BINDABLE uiLanguageBindable)
@@ -120,31 +85,49 @@ public:
Q_INVOKABLE QVariant alpha(const QJSValue &baseColor, double value) const;
Q_INVOKABLE QVariant tint(const QJSValue &baseColor, const QJSValue &tintColor) const;
- Q_INVOKABLE QString formatDate(const QDate &date, const QString &format) const;
- Q_INVOKABLE QString formatDate(const QDate &date, Qt::DateFormat format) const;
+ Q_INVOKABLE QString formatDate(QDate date, const QString &format) const;
+ Q_INVOKABLE QString formatDate(const QDateTime &dateTime, const QString &format) const;
+ Q_INVOKABLE QString formatDate(const QString &string, const QString &format) const;
+ Q_INVOKABLE QString formatDate(QDate date, Qt::DateFormat format) const;
+ Q_INVOKABLE QString formatDate(const QDateTime &dateTime, Qt::DateFormat format) const;
+ Q_INVOKABLE QString formatDate(const QString &string, Qt::DateFormat format) const;
- Q_INVOKABLE QString formatTime(const QTime &time, const QString &format) const;
+ Q_INVOKABLE QString formatTime(QTime time, const QString &format) const;
+ Q_INVOKABLE QString formatTime(const QDateTime &dateTime, const QString &format) const;
Q_INVOKABLE QString formatTime(const QString &time, const QString &format) const;
- Q_INVOKABLE QString formatTime(const QTime &time, Qt::DateFormat format) const;
+ Q_INVOKABLE QString formatTime(QTime time, Qt::DateFormat format) const;
+ Q_INVOKABLE QString formatTime(const QDateTime &dateTime, Qt::DateFormat format) const;
Q_INVOKABLE QString formatTime(const QString &time, Qt::DateFormat format) const;
Q_INVOKABLE QString formatDateTime(const QDateTime &date, const QString &format) const;
+ Q_INVOKABLE QString formatDateTime(const QString &string, const QString &format) const;
Q_INVOKABLE QString formatDateTime(const QDateTime &date, Qt::DateFormat format) const;
+ Q_INVOKABLE QString formatDateTime(const QString &string, Qt::DateFormat format) const;
#if QT_CONFIG(qml_locale)
- Q_INVOKABLE QString formatDate(const QDate &date, const QLocale &locale = QLocale(),
+ Q_INVOKABLE QString formatDate(QDate date, const QLocale &locale = QLocale(),
+ QLocale::FormatType formatType = QLocale::ShortFormat) const;
+ Q_INVOKABLE QString formatDate(const QDateTime &dateTime, const QLocale &locale = QLocale(),
QLocale::FormatType formatType = QLocale::ShortFormat) const;
- Q_INVOKABLE QString formatTime(const QTime &time, const QLocale &locale = QLocale(),
+ Q_INVOKABLE QString formatDate(const QString &string, const QLocale &locale = QLocale(),
+ QLocale::FormatType formatType = QLocale::ShortFormat) const;
+ Q_INVOKABLE QString formatTime(QTime time, const QLocale &locale = QLocale(),
+ QLocale::FormatType formatType = QLocale::ShortFormat) const;
+ Q_INVOKABLE QString formatTime(const QDateTime &dateTime, const QLocale &locale = QLocale(),
QLocale::FormatType formatType = QLocale::ShortFormat) const;
Q_INVOKABLE QString formatTime(const QString &time, const QLocale &locale = QLocale(),
QLocale::FormatType formatType = QLocale::ShortFormat) const;
Q_INVOKABLE QString formatDateTime(const QDateTime &date, const QLocale &locale = QLocale(),
QLocale::FormatType formatType = QLocale::ShortFormat) const;
+ Q_INVOKABLE QString formatDateTime(const QString &string, const QLocale &locale = QLocale(),
+ QLocale::FormatType formatType = QLocale::ShortFormat) const;
Q_INVOKABLE QLocale locale() const;
Q_INVOKABLE QLocale locale(const QString &name) const;
#endif
+ Q_INVOKABLE QUrl url(const QUrl &url) const;
Q_INVOKABLE QUrl resolvedUrl(const QUrl &url) const;
+ Q_INVOKABLE QUrl resolvedUrl(const QUrl &url, QObject *context) const;
Q_INVOKABLE bool openUrlExternally(const QUrl &url) const;
Q_INVOKABLE QVariant font(const QJSValue &fontSpecifier) const;
@@ -164,12 +147,14 @@ public:
const QUrl &url, QQmlComponent::CompilationMode mode = QQmlComponent::PreferSynchronous,
QObject *parent = nullptr) const;
- Q_INVOKABLE QJSValue binding(const QJSValue &function) const;
+ Q_INVOKABLE QQmlComponent *createComponent(const QString &moduleUri,
+ const QString &typeName, QObject *parent) const;
+ Q_INVOKABLE QQmlComponent *createComponent(const QString &moduleUri, const QString &typeName,
+ QQmlComponent::CompilationMode mode = QQmlComponent::PreferSynchronous,
+ QObject *parent = nullptr) const;
- // We can't make this invokable as it uses actual varargs
- static QV4::ReturnedValue method_callLater(
- const QV4::FunctionObject *b, const QV4::Value *thisObject,
- const QV4::Value *argv, int argc);
+ Q_INVOKABLE QJSValue binding(const QJSValue &function) const;
+ Q_INVOKABLE void callLater(QQmlV4FunctionPtr args);
#if QT_CONFIG(translation)
QString uiLanguage() const;
@@ -183,7 +168,6 @@ public:
QObject *inputMethod() const;
QObject *styleHints() const;
- QJSValue callLater() const;
private:
friend struct QV4::ExecutionEngine;
@@ -194,11 +178,16 @@ private:
QJSEngine *jsEngine() const { return m_engine->jsEngine(); }
QV4::ExecutionEngine *v4Engine() const { return m_engine; }
+ struct Contexts {
+ QQmlRefPointer<QQmlContextData> context;
+ QQmlRefPointer<QQmlContextData> effectiveContext;
+ };
+ Contexts getContexts() const;
+
QQmlPlatform *m_platform = nullptr;
QQmlApplication *m_application = nullptr;
QV4::ExecutionEngine *m_engine = nullptr;
- QJSValue m_callLater;
};
namespace QV4 {
@@ -237,10 +226,11 @@ struct ConsoleObject : Object
};
-struct Q_QML_PRIVATE_EXPORT GlobalExtensions {
+struct Q_QML_EXPORT GlobalExtensions {
static void init(Object *globalObject, QJSEngine::Extensions extensions);
#if QT_CONFIG(translation)
+ static QString currentTranslationContext(ExecutionEngine *engine);
static ReturnedValue method_qsTranslate(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
static ReturnedValue method_qsTranslateNoOp(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
static ReturnedValue method_qsTr(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
diff --git a/src/qml/qml/qqmlcomponent.cpp b/src/qml/qml/qqmlcomponent.cpp
index 7d9261604e..e063418de4 100644
--- a/src/qml/qml/qqmlcomponent.cpp
+++ b/src/qml/qml/qqmlcomponent.cpp
@@ -1,52 +1,14 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qqmlcomponent.h"
#include "qqmlcomponent_p.h"
#include "qqmlcomponentattached_p.h"
-#include "qqmlcontext_p.h"
#include "qqmlengine_p.h"
#include "qqmlvme_p.h"
#include "qqml.h"
#include "qqmlengine.h"
-#include "qqmlbinding_p.h"
#include "qqmlincubator.h"
#include "qqmlincubator_p.h"
#include <private/qqmljavascriptexpression_p.h>
@@ -67,8 +29,11 @@
#include <QtCore/qloggingcategory.h>
#include <qqmlinfo.h>
+
+using namespace Qt::Literals::StringLiterals;
+
namespace {
- QThreadStorage<int> creationDepth;
+ Q_CONSTINIT thread_local int creationDepth = 0;
}
Q_LOGGING_CATEGORY(lcQmlComponentGeneral, "qt.qml.qmlcomponent")
@@ -159,11 +124,12 @@ V4_DEFINE_EXTENSION(QQmlComponentExtension, componentExtension);
{
// ...
component = new QQmlComponent(engine, QUrl("http://www.example.com/main.qml"));
- if (component->isLoading())
- QObject::connect(component, SIGNAL(statusChanged(QQmlComponent::Status)),
- this, SLOT(continueLoading()));
- else
+ if (component->isLoading()) {
+ QObject::connect(component, &QQmlComponent::statusChanged,
+ this, &MyApplication::continueLoading);
+ } else {
continueLoading();
+ }
}
void MyApplication::continueLoading()
@@ -284,7 +250,7 @@ V4_DEFINE_EXTENSION(QQmlComponentExtension, componentExtension);
}
\endqml
- \sa {Qt QML}
+ \sa {Qt Qml}
*/
/*!
@@ -304,7 +270,7 @@ V4_DEFINE_EXTENSION(QQmlComponentExtension, componentExtension);
Specifies whether the QQmlComponent should load the component immediately, or asynchonously.
\value PreferSynchronous Prefer loading/compiling the component immediately, blocking the thread.
- This is not always possible; for example, remote URLs will always load asynchronously.
+ This is not always possible; for example, remote URLs will always load asynchronously.
\value Asynchronous Load/compile the component in a background thread.
*/
@@ -315,7 +281,7 @@ void QQmlComponentPrivate::typeDataReady(QQmlTypeData *)
Q_ASSERT(typeData);
fromTypeData(typeData);
- typeData = nullptr;
+ typeData.reset();
progress = 1.0;
emit q->statusChanged(q->status());
@@ -334,32 +300,31 @@ void QQmlComponentPrivate::typeDataProgress(QQmlTypeData *, qreal p)
void QQmlComponentPrivate::fromTypeData(const QQmlRefPointer<QQmlTypeData> &data)
{
url = data->finalUrl();
- compilationUnit = data->compilationUnit();
+ if (auto cu = data->compilationUnit())
+ compilationUnit = engine->handle()->executableCompilationUnit(std::move(cu));
if (!compilationUnit) {
Q_ASSERT(data->isError());
- state.errors = data->errors();
+ state.errors.clear();
+ state.appendErrors(data->errors());
}
}
-RequiredProperties &QQmlComponentPrivate::requiredProperties()
-{
- return state.creator->requiredProperties();
-}
-
-bool QQmlComponentPrivate::hadRequiredProperties() const
+bool QQmlComponentPrivate::hadTopLevelRequiredProperties() const
{
- return state.creator->componentHadRequiredProperties();
+ return state.creator()->componentHadTopLevelRequiredProperties();
}
void QQmlComponentPrivate::clear()
{
if (typeData) {
typeData->unregisterCallback(this);
- typeData = nullptr;
+ typeData.reset();
}
- compilationUnit = nullptr;
+ compilationUnit.reset();
+ loadedType = {};
+ inlineComponentName.reset();
}
QObject *QQmlComponentPrivate::doBeginCreate(QQmlComponent *q, QQmlContext *context)
@@ -374,18 +339,93 @@ QObject *QQmlComponentPrivate::doBeginCreate(QQmlComponent *q, QQmlContext *cont
return q->beginCreate(context);
}
-bool QQmlComponentPrivate::setInitialProperty(QObject *component, const QString& name, const QVariant &value)
+static void removePendingQPropertyBinding(
+ QV4::Value *object, const QString &propertyName, QQmlObjectCreator *creator)
{
- QQmlProperty prop = QQmlComponentPrivate::removePropertyFromRequired(component, name, requiredProperties());
+ if (!creator)
+ return;
+
+ QV4::QObjectWrapper *wrapper = object->as<QV4::QObjectWrapper>();
+ if (!wrapper)
+ return;
+
+ QObject *o = wrapper->object();
+ if (!o)
+ return;
+
+ if (QQmlData *ddata = QQmlData::get(o)) {
+ const QQmlPropertyData *propData = ddata->propertyCache->property(
+ propertyName, o, ddata->outerContext);
+ if (propData && propData->isBindable())
+ creator->removePendingBinding(o, propData->coreIndex());
+ return;
+ }
+
+ const QMetaObject *meta = o->metaObject();
+ Q_ASSERT(meta);
+ const int index = meta->indexOfProperty(propertyName.toUtf8());
+ if (index != -1 && meta->property(index).isBindable())
+ creator->removePendingBinding(o, index);
+}
+
+bool QQmlComponentPrivate::setInitialProperty(
+ QObject *base, const QString &name, const QVariant &value)
+{
+ const QStringList properties = name.split(u'.');
+
+ if (properties.size() > 1) {
+ QV4::Scope scope(engine->handle());
+ QV4::ScopedObject object(scope, QV4::QObjectWrapper::wrap(scope.engine, base));
+ QV4::ScopedString segment(scope);
+
+ for (int i = 0; i < properties.size() - 1; ++i) {
+ segment = scope.engine->newString(properties.at(i));
+ object = object->get(segment);
+ if (scope.engine->hasException)
+ break;
+ }
+ const QString lastProperty = properties.last();
+ segment = scope.engine->newString(lastProperty);
+ object->put(segment, scope.engine->metaTypeToJS(value.metaType(), value.constData()));
+ if (scope.engine->hasException) {
+ qmlWarning(base, scope.engine->catchExceptionAsQmlError());
+ scope.engine->hasException = false;
+ return false;
+ }
+
+ removePendingQPropertyBinding(object, lastProperty, state.creator());
+ return true;
+ }
+
+ QQmlProperty prop;
+ if (state.hasUnsetRequiredProperties())
+ prop = QQmlComponentPrivate::removePropertyFromRequired(
+ base, name, state.requiredProperties(), engine);
+ else
+ prop = QQmlProperty(base, name, engine);
QQmlPropertyPrivate *privProp = QQmlPropertyPrivate::get(prop);
- if (!prop.isValid() || !privProp->writeValueProperty(value, {})) {
+ const bool isValid = prop.isValid();
+ if (isValid && privProp->writeValueProperty(value, {})) {
+ if (prop.isBindable()) {
+ if (QQmlObjectCreator *creator = state.creator())
+ creator->removePendingBinding(prop.object(), prop.index());
+ }
+ } else {
QQmlError error{};
error.setUrl(url);
- error.setDescription(QLatin1String("Could not set property %1").arg(name));
- state.errors.push_back(error);
+ if (isValid) {
+ error.setDescription(QStringLiteral("Could not set initial property %1").arg(name));
+ } else {
+ error.setDescription(QStringLiteral("Setting initial properties failed: "
+ "%2 does not have a property called %1")
+ .arg(name, QQmlMetaType::prettyTypeName(base)));
+ }
+ qmlWarning(base, error);
return false;
- } else
- return true;
+ }
+
+ return true;
+
}
/*!
@@ -403,35 +443,37 @@ QQmlComponent::~QQmlComponent()
{
Q_D(QQmlComponent);
- if (d->state.completePending) {
+ if (d->state.isCompletePending()) {
qWarning("QQmlComponent: Component destroyed while completion pending");
if (isError()) {
qWarning() << "This may have been caused by one of the following errors:";
- for (const QQmlError &error : qAsConst(d->state.errors))
- qWarning().nospace().noquote() << QLatin1String(" ") << error;
+ for (const QQmlComponentPrivate::AnnotatedQmlError &e : std::as_const(d->state.errors))
+ qWarning().nospace().noquote() << QLatin1String(" ") << e.error;
}
- d->completeCreate();
+ // we might not have the creator anymore if the engine is gone
+ if (d->state.hasCreator())
+ d->completeCreate();
}
if (d->typeData) {
d->typeData->unregisterCallback(d);
- d->typeData = nullptr;
+ d->typeData.reset();
}
}
/*!
\qmlproperty enumeration Component::status
+
This property holds the status of component loading. The status can be one of the
following:
- \list
- \li Component.Null - no data is available for the component
- \li Component.Ready - the component has been loaded, and can be used to create instances.
- \li Component.Loading - the component is currently being loaded
- \li Component.Error - an error occurred while loading the component.
- Calling errorString() will provide a human-readable description of any errors.
- \endlist
+
+ \value Component.Null no data is available for the component
+ \value Component.Ready the component has been loaded, and can be used to create instances.
+ \value Component.Loading the component is currently being loaded
+ \value Component.Error an error occurred while loading the component.
+ Calling \l errorString() will provide a human-readable description of any errors.
*/
/*!
@@ -446,7 +488,7 @@ QQmlComponent::Status QQmlComponent::status() const
return Loading;
else if (!d->state.errors.isEmpty())
return Error;
- else if (d->engine && d->compilationUnit)
+ else if (d->engine && (d->compilationUnit || d->loadedType.isValid()))
return Ready;
else
return Null;
@@ -485,6 +527,18 @@ bool QQmlComponent::isLoading() const
}
/*!
+ Returns true if the component was created in a QML files that specifies
+ \c{pragma ComponentBehavior: Bound}, otherwise returns false.
+
+ \since 6.5
+ */
+bool QQmlComponent::isBound() const
+{
+ Q_D(const QQmlComponent);
+ return d->isBound();
+}
+
+/*!
\qmlproperty real Component::progress
The progress of loading the component, from 0.0 (nothing loaded)
to 1.0 (finished).
@@ -525,7 +579,7 @@ QQmlComponent::QQmlComponent(QQmlEngine *engine, QObject *parent)
Q_D(QQmlComponent);
d->engine = engine;
QObject::connect(engine, &QObject::destroyed, this, [d]() {
- d->state.creator.reset();
+ d->state.clear();
d->engine = nullptr;
});
}
@@ -561,6 +615,36 @@ QQmlComponent::QQmlComponent(QQmlEngine *engine, const QUrl &url, CompilationMod
}
/*!
+ Create a QQmlComponent from the given \a uri and \a typeName and give it
+ the specified \a parent and \a engine. If possible, the component will
+ be loaded synchronously.
+
+ \sa loadFromModule()
+ \since 6.5
+ \overload
+*/
+QQmlComponent::QQmlComponent(QQmlEngine *engine, QAnyStringView uri, QAnyStringView typeName, QObject *parent)
+ : QQmlComponent(engine, uri, typeName, QQmlComponent::PreferSynchronous, parent)
+{
+
+}
+
+/*!
+ Create a QQmlComponent from the given \a uri and \a typeName and give it
+ the specified \a parent and \a engine. If \a mode is \l Asynchronous,
+ the component will be loaded and compiled asynchronously.
+
+ \sa loadFromModule()
+ \since 6.5
+ \overload
+*/
+QQmlComponent::QQmlComponent(QQmlEngine *engine, QAnyStringView uri, QAnyStringView typeName, CompilationMode mode, QObject *parent)
+ : QQmlComponent(engine, parent)
+{
+ loadFromModule(uri, typeName, mode);
+}
+
+/*!
Create a QQmlComponent from the given \a fileName and give it the specified
\a parent and \a engine.
@@ -584,8 +668,12 @@ QQmlComponent::QQmlComponent(QQmlEngine *engine, const QString &fileName,
: QQmlComponent(engine, parent)
{
Q_D(QQmlComponent);
- const QUrl url = QDir::isAbsolutePath(fileName) ? QUrl::fromLocalFile(fileName) : QUrl(fileName);
- d->loadUrl(url, mode);
+ if (fileName.startsWith(u':'))
+ d->loadUrl(QUrl(QLatin1String("qrc") + fileName), mode);
+ else if (QDir::isAbsolutePath(fileName))
+ d->loadUrl(QUrl::fromLocalFile(fileName), mode);
+ else
+ d->loadUrl(QUrl(fileName), mode);
}
/*!
@@ -596,7 +684,7 @@ QQmlComponent::QQmlComponent(QQmlEngine *engine, QV4::ExecutableCompilationUnit
: QQmlComponent(engine, parent)
{
Q_D(QQmlComponent);
- d->compilationUnit = compilationUnit;
+ d->compilationUnit.reset(compilationUnit);
d->start = start;
d->url = compilationUnit->finalUrl();
d->progress = 1.0;
@@ -706,7 +794,7 @@ void QQmlComponentPrivate::loadUrl(const QUrl &newUrl, QQmlComponent::Compilatio
if (newUrl.isEmpty()) {
QQmlError error;
error.setDescription(QQmlComponent::tr("Invalid empty URL"));
- state.errors << error;
+ state.errors.emplaceBack(error);
return;
}
@@ -718,7 +806,6 @@ void QQmlComponentPrivate::loadUrl(const QUrl &newUrl, QQmlComponent::Compilatio
QQmlTypeLoader::Mode loaderMode = (mode == QQmlComponent::Asynchronous)
? QQmlTypeLoader::Asynchronous
: QQmlTypeLoader::PreferSynchronous;
-
QQmlRefPointer<QQmlTypeData> data = QQmlEnginePrivate::get(engine)->typeLoader.getType(url, loaderMode);
if (data->isCompleteOrError()) {
@@ -742,10 +829,11 @@ void QQmlComponentPrivate::loadUrl(const QUrl &newUrl, QQmlComponent::Compilatio
QList<QQmlError> QQmlComponent::errors() const
{
Q_D(const QQmlComponent);
- if (isError())
- return d->state.errors;
- else
- return QList<QQmlError>();
+ QList<QQmlError> errors;
+ errors.reserve(d->state.errors.size());
+ for (const QQmlComponentPrivate::AnnotatedQmlError &annotated : d->state.errors)
+ errors.emplaceBack(annotated.error);
+ return errors;
}
/*!
@@ -761,7 +849,7 @@ QList<QQmlError> QQmlComponent::errors() const
/*!
\internal
- errorString is only meant as a way to get the errors in script
+ errorString() is only meant as a way to get the errors from QML side.
*/
QString QQmlComponent::errorString() const
{
@@ -769,7 +857,8 @@ QString QQmlComponent::errorString() const
QString ret;
if(!isError())
return ret;
- for (const QQmlError &e : d->state.errors) {
+ for (const QQmlComponentPrivate::AnnotatedQmlError &annotated : d->state.errors) {
+ const QQmlError &e = annotated.error;
ret += e.url().toString() + QLatin1Char(':') +
QString::number(e.line()) + QLatin1Char(' ') +
e.description() + QLatin1Char('\n');
@@ -802,9 +891,8 @@ QQmlComponent::QQmlComponent(QQmlComponentPrivate &dd, QObject *parent)
}
/*!
- Create an object instance from this component. Returns \nullptr if creation
- failed. \a context specifies the context within which to create the object
- instance.
+ Create an object instance from this component, within the specified \a context.
+ Returns \nullptr if creation failed.
If \a context is \nullptr (the default), it will create the instance in the
\l {QQmlEngine::rootContext()}{root context} of the engine.
@@ -821,21 +909,20 @@ QQmlComponent::QQmlComponent(QQmlComponentPrivate &dd, QObject *parent)
QObject *QQmlComponent::create(QQmlContext *context)
{
Q_D(QQmlComponent);
-
- QObject *rv = d->doBeginCreate(this, context);
- if (rv)
- completeCreate();
- if (rv && !d->requiredProperties().empty()) {
- delete rv;
- return nullptr;
- }
- return rv;
+ return d->createWithProperties(nullptr, QVariantMap {}, context);
}
/*!
- Create an object instance of this component, and initialize its toplevel
- properties with \a initialProperties. \a context specifies the context
- where the object instance is to be created.
+ Create an object instance of this component, within the specified \a context,
+ and initialize its top-level properties with \a initialProperties.
+
+ \omit
+ TODO: also mention errorString() when QTBUG-93239 is fixed
+ \endomit
+
+ If any of the \a initialProperties cannot be set, a warning is issued. If
+ there are unset required properties, the object creation fails and returns
+ \c nullptr, in which case \l isError() will return \c true.
\sa QQmlComponent::create
\since 5.14
@@ -843,34 +930,65 @@ QObject *QQmlComponent::create(QQmlContext *context)
QObject *QQmlComponent::createWithInitialProperties(const QVariantMap& initialProperties, QQmlContext *context)
{
Q_D(QQmlComponent);
+ return d->createWithProperties(nullptr, initialProperties, context);
+}
- QObject *rv = d->doBeginCreate(this, context);
- if (rv) {
- setInitialProperties(rv, initialProperties);
- completeCreate();
- }
- if (!d->requiredProperties().empty()) {
- d->requiredProperties().clear();
+static void QQmlComponent_setQmlParent(QObject *me, QObject *parent); // forward declaration
+
+/*! \internal
+ */
+QObject *QQmlComponentPrivate::createWithProperties(QObject *parent, const QVariantMap &properties,
+ QQmlContext *context, CreateBehavior behavior)
+{
+ Q_Q(QQmlComponent);
+
+ QObject *rv = doBeginCreate(q, context);
+ if (!rv) {
+ if (state.isCompletePending()) {
+ // overridden completCreate might assume that
+ // the object has actually been created
+ ++creationDepth;
+ QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine);
+ complete(ep, &state);
+ --creationDepth;
+ }
return nullptr;
}
+
+ QQmlComponent_setQmlParent(rv, parent); // internally checks if parent is nullptr
+
+ q->setInitialProperties(rv, properties);
+ q->completeCreate();
+
+ if (state.hasUnsetRequiredProperties()) {
+ if (behavior == CreateWarnAboutRequiredProperties) {
+ for (const auto &unsetRequiredProperty : std::as_const(*state.requiredProperties())) {
+ const QQmlError error = unsetRequiredPropertyToQQmlError(unsetRequiredProperty);
+ qmlWarning(rv, error);
+ }
+ }
+ delete rv;
+ rv = nullptr;
+ }
return rv;
}
/*!
- This method provides advanced control over component instance creation.
+ Create an object instance from this component, within the specified \a context.
+ Returns \nullptr if creation failed.
+
+ \note This method provides advanced control over component instance creation.
In general, programmers should use QQmlComponent::create() to create object
instances.
- Create an object instance from this component. Returns \nullptr if creation
- failed. \a publicContext specifies the context within which to create the object
- instance.
-
When QQmlComponent constructs an instance, it occurs in three steps:
+
\list 1
\li The object hierarchy is created, and constant values are assigned.
\li Property bindings are evaluated for the first time.
\li If applicable, QQmlParserStatus::componentComplete() is called on objects.
\endlist
+
QQmlComponent::beginCreate() differs from QQmlComponent::create() in that it
only performs step 1. QQmlComponent::completeCreate() must be called to
complete steps 2 and 3.
@@ -881,22 +999,32 @@ QObject *QQmlComponent::createWithInitialProperties(const QVariantMap& initialPr
The ownership of the returned object instance is transferred to the caller.
+ \note The categorization of bindings into constant values and actual
+ bindings is intentionally unspecified and may change between versions of Qt
+ and depending on whether and how you are using \l{qmlcachegen}. You should
+ not rely on any particular binding to be evaluated either before or after
+ beginCreate() returns. For example a constant expression like
+ \e{MyType.EnumValue} may be recognized as such at compile time or deferred
+ to be executed as binding. The same holds for constant expressions like
+ \e{-(5)} or \e{"a" + " constant string"}.
+
\sa completeCreate(), QQmlEngine::ObjectOwnership
*/
-QObject *QQmlComponent::beginCreate(QQmlContext *publicContext)
+QObject *QQmlComponent::beginCreate(QQmlContext *context)
{
Q_D(QQmlComponent);
- Q_ASSERT(publicContext);
- return d->beginCreate(QQmlContextData::get(publicContext));
+ Q_ASSERT(context);
+ return d->beginCreate(QQmlContextData::get(context));
}
QObject *QQmlComponentPrivate::beginCreate(QQmlRefPointer<QQmlContextData> context)
{
Q_Q(QQmlComponent);
auto cleanup = qScopeGuard([this] {
- if (!state.errors.isEmpty()) {
- for (const auto &e : qAsConst(state.errors))
- qCDebug(lcQmlComponentGeneral) << "QQmlComponent: " << e.toString();
+ if (!state.errors.isEmpty() && lcQmlComponentGeneral().isDebugEnabled()) {
+ for (const auto &e : std::as_const(state.errors)) {
+ qCDebug(lcQmlComponentGeneral) << "QQmlComponent: " << e.error.toString();
+ }
}
});
if (!context) {
@@ -914,11 +1042,16 @@ QObject *QQmlComponentPrivate::beginCreate(QQmlRefPointer<QQmlContextData> conte
return nullptr;
}
- if (state.completePending) {
+ if (state.isCompletePending()) {
qWarning("QQmlComponent: Cannot create new component instance before completing the previous");
return nullptr;
}
+ // filter out temporary errors as they do not really affect component's
+ // state (they are not part of the document compilation)
+ state.errors.removeIf([](const auto &e) { return e.isTransient; });
+ state.clearRequiredProperties();
+
if (!q->isReady()) {
qWarning("QQmlComponent: Component is not ready");
return nullptr;
@@ -926,7 +1059,7 @@ QObject *QQmlComponentPrivate::beginCreate(QQmlRefPointer<QQmlContextData> conte
// Do not create infinite recursion in object creation
static const int maxCreationDepth = 10;
- if (creationDepth.localData() >= maxCreationDepth) {
+ if (creationDepth >= maxCreationDepth) {
qWarning("QQmlComponent: Component creation is recursing - aborting");
return nullptr;
}
@@ -935,21 +1068,59 @@ QObject *QQmlComponentPrivate::beginCreate(QQmlRefPointer<QQmlContextData> conte
enginePriv->inProgressCreations++;
state.errors.clear();
- state.completePending = true;
+ state.setCompletePending(true);
- enginePriv->referenceScarceResources();
QObject *rv = nullptr;
- state.creator.reset(new QQmlObjectCreator(std::move(context), compilationUnit, creationContext));
- rv = state.creator->create(start);
- if (!rv)
- state.errors = state.creator->errors;
- enginePriv->dereferenceScarceResources();
+
+ if (!loadedType.isValid()) {
+ enginePriv->referenceScarceResources();
+ state.initCreator(std::move(context), compilationUnit, creationContext);
+
+ QQmlObjectCreator::CreationFlags flags;
+ if (const QString *icName = inlineComponentName.get()) {
+ flags = QQmlObjectCreator::InlineComponent;
+ if (start == -1)
+ start = compilationUnit->inlineComponentId(*icName);
+ Q_ASSERT(start > 0);
+ } else {
+ flags = QQmlObjectCreator::NormalObject;
+ }
+
+ rv = state.creator()->create(start, nullptr, nullptr, flags);
+ if (!rv)
+ state.appendCreatorErrors();
+ enginePriv->dereferenceScarceResources();
+ } else {
+ // TODO: extract into function
+ rv = loadedType.createWithQQmlData();
+ QQmlPropertyCache::ConstPtr propertyCache = QQmlData::ensurePropertyCache(rv);
+ QQmlParserStatus *parserStatus = nullptr;
+ const int parserStatusCast = loadedType.parserStatusCast();
+ if (parserStatusCast != -1) {
+ parserStatus = reinterpret_cast<QQmlParserStatus*>(reinterpret_cast<char *>(rv) + parserStatusCast);
+ parserStatus->classBegin();
+ }
+ for (int i = 0, propertyCount = propertyCache->propertyCount(); i < propertyCount; ++i) {
+ if (const QQmlPropertyData *propertyData = propertyCache->property(i); propertyData->isRequired()) {
+ state.ensureRequiredPropertyStorage();
+ RequiredPropertyInfo info;
+ info.propertyName = propertyData->name(rv);
+ state.addPendingRequiredProperty(rv, propertyData, info);
+ }
+ }
+ if (parserStatus)
+ parserStatus->componentComplete();
+ if (const int finalizerCast = loadedType.finalizerCast(); finalizerCast != -1) {
+ auto* hook = reinterpret_cast<QQmlFinalizerHook *>(reinterpret_cast<char *>(rv) + finalizerCast);
+ hook->componentFinalized();
+ }
+ }
if (rv) {
QQmlData *ddata = QQmlData::get(rv);
Q_ASSERT(ddata);
- //top level objects should never get JS ownership.
- //if JS ownership is needed this needs to be explicitly undone (like in component.createObject())
+ // top-level objects should never get JS ownership.
+ // if JS ownership is needed this needs to be explicitly undone (like in createObject())
ddata->indestructible = true;
ddata->explicitIndestructibleSet = true;
ddata->rootObjectInCreation = false;
@@ -964,39 +1135,40 @@ void QQmlComponentPrivate::beginDeferred(QQmlEnginePrivate *enginePriv,
QQmlData *ddata = QQmlData::get(object);
Q_ASSERT(!ddata->deferredData.isEmpty());
- deferredState->constructionStates.reserve(ddata->deferredData.size());
+ deferredState->reserve(ddata->deferredData.size());
- for (QQmlData::DeferredData *deferredData : qAsConst(ddata->deferredData)) {
+ for (QQmlData::DeferredData *deferredData : std::as_const(ddata->deferredData)) {
enginePriv->inProgressCreations++;
- ConstructionState *state = new ConstructionState;
- state->completePending = true;
+ ConstructionState state;
+ state.setCompletePending(true);
- state->creator.reset(new QQmlObjectCreator(
- deferredData->context->parent(), deferredData->compilationUnit,
- QQmlRefPointer<QQmlContextData>()));
+ auto creator = state.initCreator(
+ deferredData->context->parent(),
+ deferredData->compilationUnit,
+ QQmlRefPointer<QQmlContextData>());
- if (!state->creator->populateDeferredProperties(object, deferredData))
- state->errors << state->creator->errors;
+ if (!creator->populateDeferredProperties(object, deferredData))
+ state.appendCreatorErrors();
deferredData->bindings.clear();
- deferredState->constructionStates += state;
+ deferredState->push_back(std::move(state));
}
}
void QQmlComponentPrivate::completeDeferred(QQmlEnginePrivate *enginePriv, QQmlComponentPrivate::DeferredState *deferredState)
{
- for (ConstructionState *state : qAsConst(deferredState->constructionStates))
- complete(enginePriv, state);
+ for (ConstructionState &state : *deferredState)
+ complete(enginePriv, &state);
}
void QQmlComponentPrivate::complete(QQmlEnginePrivate *enginePriv, ConstructionState *state)
{
- if (state->completePending) {
+ if (state->isCompletePending()) {
QQmlInstantiationInterrupt interrupt;
- state->creator->finalize(interrupt);
+ state->creator()->finalize(interrupt);
- state->completePending = false;
+ state->setCompletePending(false);
enginePriv->inProgressCreations--;
@@ -1009,28 +1181,32 @@ void QQmlComponentPrivate::complete(QQmlEnginePrivate *enginePriv, ConstructionS
}
/*!
- * \internal
- * Finds the matching toplevel property with name \a name of the component \a createdComponent.
- * If it was a required property or an alias to a required property contained in \a
- * requiredProperties, it is removed from it.
- *
- * If wasInRequiredProperties is non-null, the referenced boolean is set to true iff the property
- * was found in requiredProperties.
- *
- * Returns the QQmlProperty with name \a name (which might be invalid if there is no such property),
- * for further processing (for instance, actually setting the property value).
- *
- * Note: This method is used in QQmlComponent and QQmlIncubator to manage required properties. Most
- * classes which create components should not need it and should only need to call
- * setInitialProperties.
+ \internal
+ Finds the matching top-level property with name \a name of the component \a createdComponent.
+ If it was a required property or an alias to a required property contained in \a
+ requiredProperties, it is removed from it.
+ \a requiredProperties must be non-null.
+
+ If wasInRequiredProperties is non-null, the referenced boolean is set to true iff the property
+ was found in requiredProperties.
+
+ Returns the QQmlProperty with name \a name (which might be invalid if there is no such property),
+ for further processing (for instance, actually setting the property value).
+
+ Note: This method is used in QQmlComponent and QQmlIncubator to manage required properties. Most
+ classes which create components should not need it and should only need to call
+ setInitialProperties.
*/
-QQmlProperty QQmlComponentPrivate::removePropertyFromRequired(QObject *createdComponent, const QString &name, RequiredProperties &requiredProperties, bool* wasInRequiredProperties)
+QQmlProperty QQmlComponentPrivate::removePropertyFromRequired(
+ QObject *createdComponent, const QString &name, RequiredProperties *requiredProperties,
+ QQmlEngine *engine, bool *wasInRequiredProperties)
{
- QQmlProperty prop(createdComponent, name);
+ Q_ASSERT(requiredProperties);
+ QQmlProperty prop(createdComponent, name, engine);
auto privProp = QQmlPropertyPrivate::get(prop);
if (prop.isValid()) {
// resolve outstanding required properties
- auto targetProp = &privProp->core;
+ const QQmlPropertyData *targetProp = &privProp->core;
if (targetProp->isAlias()) {
auto target = createdComponent;
QQmlPropertyIndex originalIndex(targetProp->coreIndex());
@@ -1046,11 +1222,11 @@ QQmlProperty QQmlComponentPrivate::removePropertyFromRequired(QObject *createdCo
Q_ASSERT(data && data->propertyCache);
targetProp = data->propertyCache->property(targetProp->coreIndex());
}
- auto it = requiredProperties.find(targetProp);
- if (it != requiredProperties.end()) {
+ auto it = requiredProperties->constFind({createdComponent, targetProp});
+ if (it != requiredProperties->cend()) {
if (wasInRequiredProperties)
*wasInRequiredProperties = true;
- requiredProperties.erase(it);
+ requiredProperties->erase(it);
} else {
if (wasInRequiredProperties)
*wasInRequiredProperties = false;
@@ -1078,16 +1254,25 @@ void QQmlComponent::completeCreate()
void QQmlComponentPrivate::completeCreate()
{
- const RequiredProperties& unsetRequiredProperties = requiredProperties();
- for (const auto& unsetRequiredProperty: unsetRequiredProperties) {
- QQmlError error = unsetRequiredPropertyToQQmlError(unsetRequiredProperty);
- state.errors.push_back(error);
+ if (state.hasUnsetRequiredProperties()) {
+ for (const auto& unsetRequiredProperty: std::as_const(*state.requiredProperties())) {
+ QQmlError error = unsetRequiredPropertyToQQmlError(unsetRequiredProperty);
+ state.errors.push_back(QQmlComponentPrivate::AnnotatedQmlError { error, true });
+ }
}
- if (state.completePending) {
- ++creationDepth.localData();
+ if (loadedType.isValid()) {
+ /*
+ We can directly set completePending to false, as finalize is only concerned
+ with setting up pending bindings, but that cannot happen here, as we're
+ dealing with a pure C++ type, which cannot have pending bindings
+ */
+ state.setCompletePending(false);
+ QQmlEnginePrivate::get(engine)->inProgressCreations--;
+ } else if (state.isCompletePending()) {
+ ++creationDepth;
QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine);
complete(ep, &state);
- --creationDepth.localData();
+ --creationDepth;
}
}
@@ -1129,18 +1314,126 @@ QQmlComponentAttached *QQmlComponent::qmlAttachedProperties(QObject *obj)
}
/*!
+ Load the QQmlComponent for \a typeName in the module \a uri.
+ If the type is implemented via a QML file, \a mode is used to
+ load it. Types backed by C++ are always loaded synchronously.
+
+ \code
+ QQmlEngine engine;
+ QQmlComponent component(&engine);
+ component.loadFromModule("QtQuick", "Item");
+ // once the component is ready
+ std::unique_ptr<QObject> item(component.create());
+ Q_ASSERT(item->metaObject() == &QQuickItem::staticMetaObject);
+ \endcode
+
+ \since 6.5
+ \sa loadUrl()
+ */
+void QQmlComponent::loadFromModule(QAnyStringView uri, QAnyStringView typeName,
+ QQmlComponent::CompilationMode mode)
+{
+ Q_D(QQmlComponent);
+ auto [status, type] = d->prepareLoadFromModule(uri, typeName);
+ d->completeLoadFromModule(uri, typeName, type, status, mode);
+}
+
+LoadHelper::ResolveTypeResult QQmlComponentPrivate::prepareLoadFromModule(QAnyStringView uri,
+ QAnyStringView typeName)
+{
+ auto enginePriv = QQmlEnginePrivate::get(engine);
+ // LoadHelper must be on the Heap as it derives from QQmlRefCount
+ auto loadHelper = QQml::makeRefPointer<LoadHelper>(&enginePriv->typeLoader, uri);
+
+ return loadHelper->resolveType(typeName);
+}
+
+void QQmlComponentPrivate::completeLoadFromModule(QAnyStringView uri, QAnyStringView typeName, QQmlType type,
+ LoadHelper::ResolveTypeResult::Status moduleStatus,
+ QQmlComponent::CompilationMode mode)
+{
+ Q_Q(QQmlComponent);
+
+ // we always mimic the progressChanged behavior from loadUrl
+ auto reportError = [&](QString msg) {
+ QQmlError error;
+ error.setDescription(msg);
+ state.errors.push_back(std::move(error));
+ progress = 1;
+ emit q->progressChanged(1);
+ emit q->statusChanged(q->Error);
+ };
+ auto emitProgressReset = [&](){
+ if (progress != 0) {
+ progress = 0;
+ emit q->progressChanged(0);
+ }
+ };
+ auto emitComplete = [&]() {
+ progress = 1;
+ emit q->progressChanged(1);
+ emit q->statusChanged(q->status());
+ };
+ emitProgressReset();
+ if (moduleStatus == LoadHelper::ResolveTypeResult::NoSuchModule) {
+ reportError(QLatin1String(R"(No module named "%1" found)").arg(uri.toString()));
+ } else if (!type.isValid()) {
+ reportError(QLatin1String(R"(Module "%1" contains no type named "%2")")
+ .arg(uri.toString(), typeName.toString()));
+ } else if (type.isCreatable()) {
+ clear();
+ loadedType = type;
+ emitComplete();
+ } else if (type.isComposite()) {
+ // loadUrl takes care of signal emission
+ loadUrl(type.sourceUrl(), mode);
+ } else if (type.isInlineComponentType()) {
+ auto baseUrl = type.sourceUrl();
+ baseUrl.setFragment(QString());
+ {
+ // we don't want to emit status changes from the "helper" loadUrl below
+ // because it would signal success to early
+ QSignalBlocker blockSignals(q);
+ // we really need to continue in a synchronous way, otherwise we can't check the CU
+ loadUrl(baseUrl, QQmlComponent::PreferSynchronous);
+ }
+ if (q->isError()) {
+ emitComplete();
+ return;
+ }
+ QString elementName = type.elementName();
+ if (compilationUnit->inlineComponentId(elementName) == -1) {
+ QString realTypeName = typeName.toString();
+ realTypeName.truncate(realTypeName.indexOf(u'.'));
+ QString errorMessage = R"(Type "%1" from module "%2" contains no inline component named "%3".)"_L1.arg(
+ realTypeName, uri.toString(), elementName);
+ if (elementName == u"qml")
+ errorMessage += " To load the type \"%1\", drop the \".qml\" extension."_L1.arg(realTypeName);
+ reportError(std::move(errorMessage));
+ } else {
+ inlineComponentName = std::make_unique<QString>(std::move(elementName));
+ emitComplete();
+ }
+ } else if (type.isSingleton() || type.isCompositeSingleton()) {
+ reportError(QLatin1String(R"(%1 is a singleton, and cannot be loaded)").arg(typeName.toString()));
+ } else {
+ reportError(QLatin1String("Could not load %1, as the type is uncreatable").arg(typeName.toString()));
+ }
+}
+
+/*!
Create an object instance from this component using the provided
\a incubator. \a context specifies the context within which to create the object
instance.
- If \a context is 0 (the default), it will create the instance in the
+ If \a context is \nullptr (by default), it will create the instance in the
engine's \l {QQmlEngine::rootContext()}{root context}.
\a forContext specifies a context that this object creation depends upon.
If the \a forContext is being created asynchronously, and the
\l QQmlIncubator::IncubationMode is \l QQmlIncubator::AsynchronousIfNested,
- this object will also be created asynchronously. If \a forContext is 0
- (the default), the \a context will be used for this decision.
+ this object will also be created asynchronously.
+ If \a forContext is \nullptr (by default), the \a context will be used for this decision.
The created object and its creation status are available via the
\a incubator.
@@ -1177,6 +1470,14 @@ void QQmlComponent::create(QQmlIncubator &incubator, QQmlContext *context, QQmlC
incubator.clear();
QExplicitlySharedDataPointer<QQmlIncubatorPrivate> p(incubator.d);
+ if (d->loadedType.isValid()) {
+ // there isn't really an incubation process for C++ backed types
+ // so just create the object and signal that we are ready
+
+ p->incubateCppBasedComponent(this, context);
+ return;
+ }
+
QQmlEnginePrivate *enginePriv = QQmlEnginePrivate::get(d->engine);
p->compilationUnit = d->compilationUnit;
@@ -1188,8 +1489,7 @@ void QQmlComponent::create(QQmlIncubator &incubator, QQmlContext *context, QQmlC
}
/*!
- Set toplevel \a properties of the \a component.
-
+ Set top-level \a properties of the \a component.
This method provides advanced control over component instance creation.
In general, programmers should use
@@ -1228,6 +1528,13 @@ void QQmlComponentPrivate::incubateObject(
incubatorPriv->compilationUnit = componentPriv->compilationUnit;
incubatorPriv->enginePriv = enginePriv;
incubatorPriv->creator.reset(new QQmlObjectCreator(context, componentPriv->compilationUnit, componentPriv->creationContext));
+
+ if (start == -1) {
+ if (const QString *icName = componentPriv->inlineComponentName.get()) {
+ start = compilationUnit->inlineComponentId(*icName);
+ Q_ASSERT(start > 0);
+ }
+ }
incubatorPriv->subComponentToCreate = componentPriv->start;
enginePriv->incubate(*incubationTask, forContext);
@@ -1242,14 +1549,14 @@ namespace QV4 {
namespace Heap {
#define QmlIncubatorObjectMembers(class, Member) \
- Member(class, HeapValue, HeapValue, valuemap) \
+ Member(class, HeapValue, HeapValue, valuemapOrObject) \
Member(class, HeapValue, HeapValue, statusChanged) \
Member(class, Pointer, QmlContext *, qmlContext) \
Member(class, NoMark, QQmlComponentIncubator *, incubator) \
Member(class, NoMark, QV4QPointer<QObject>, parent)
DECLARE_HEAP_OBJECT(QmlIncubatorObject, Object) {
- DECLARE_MARKOBJECTS(QmlIncubatorObject);
+ DECLARE_MARKOBJECTS(QmlIncubatorObject)
void init(QQmlIncubator::IncubationMode = QQmlIncubator::Asynchronous);
inline void destroy();
@@ -1269,7 +1576,7 @@ struct QmlIncubatorObject : public QV4::Object
static ReturnedValue method_forceCompletion(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
void statusChanged(QQmlIncubator::Status);
- void setInitialState(QObject *, RequiredProperties &requiredProperties);
+ void setInitialState(QObject *, RequiredProperties *requiredProperties);
};
}
@@ -1310,7 +1617,7 @@ static void QQmlComponent_setQmlParent(QObject *me, QObject *parent)
QList<APF> functions = QQmlMetaType::parentFunctions();
bool needParent = false;
- for (int ii = 0; ii < functions.count(); ++ii) {
+ for (int ii = 0; ii < functions.size(); ++ii) {
QQmlPrivate::AutoParentResult res = functions.at(ii)(me, parent);
if (res == QQmlPrivate::Parented) {
needParent = false;
@@ -1320,13 +1627,12 @@ static void QQmlComponent_setQmlParent(QObject *me, QObject *parent)
}
}
if (needParent)
- qWarning("QQmlComponent: Created graphical object was not "
- "placed in the graphics scene.");
+ qmlWarning(me) << "Created graphical object was not placed in the graphics scene.";
}
}
/*!
- \qmlmethod object Component::createObject(QtObject parent, object properties)
+ \qmlmethod QtObject Component::createObject(QtObject parent, object properties)
Creates and returns an object instance of this component that will have
the given \a parent and \a properties. The \a properties argument is optional.
@@ -1354,11 +1660,12 @@ static void QQmlComponent_setQmlParent(QObject *me, QObject *parent)
The \a properties argument is specified as a map of property-value items. For example, the code
below creates an object with initial \c x and \c y values of 100 and 100, respectively:
- \js
- var component = Qt.createComponent("Button.qml");
- if (component.status == Component.Ready)
- component.createObject(parent, {x: 100, y: 100});
- \endjs
+ \qml
+ const component = Qt.createComponent("Button.qml");
+ if (component.status === Component.Ready) {
+ component.createObject(parent, { x: 100, y: 100 });
+ }
+ \endqml
Dynamically created instances can be deleted with the \c destroy() method.
See \l {Dynamic QML Object Creation from JavaScript} for more information.
@@ -1367,7 +1674,10 @@ static void QQmlComponent_setQmlParent(QObject *me, QObject *parent)
*/
-void QQmlComponentPrivate::setInitialProperties(QV4::ExecutionEngine *engine, QV4::QmlContext *qmlContext, const QV4::Value &o, const QV4::Value &v, RequiredProperties &requiredProperties, QObject *createdComponent)
+void QQmlComponentPrivate::setInitialProperties(
+ QV4::ExecutionEngine *engine, QV4::QmlContext *qmlContext, const QV4::Value &o,
+ const QV4::Value &v, RequiredProperties *requiredProperties, QObject *createdComponent,
+ QQmlObjectCreator *creator)
{
QV4::Scope scope(engine);
QV4::ScopedObject object(scope);
@@ -1379,7 +1689,7 @@ void QQmlComponentPrivate::setInitialProperties(QV4::ExecutionEngine *engine, QV
return;
// js modules (mjs) have no qmlContext
- QV4::ScopedStackFrame frame(scope, qmlContext ? qmlContext->d() : engine->scriptContext()->d());
+ QV4::ScopedStackFrame frame(scope, qmlContext ? qmlContext : engine->scriptContext());
while (1) {
name = it.nextPropertyNameAsString(val);
@@ -1388,25 +1698,37 @@ void QQmlComponentPrivate::setInitialProperties(QV4::ExecutionEngine *engine, QV
object = o;
const QStringList properties = name->toQString().split(QLatin1Char('.'));
bool isTopLevelProperty = properties.size() == 1;
- for (int i = 0; i < properties.length() - 1; ++i) {
+ for (int i = 0; i < properties.size() - 1; ++i) {
name = engine->newString(properties.at(i));
object = object->get(name);
if (engine->hasException || !object) {
break;
}
}
- if (engine->hasException || !object) {
+ if (engine->hasException) {
qmlWarning(createdComponent, engine->catchExceptionAsQmlError());
continue;
}
- name = engine->newString(properties.last());
+ if (!object) {
+ QQmlError error;
+ error.setUrl(qmlContext ? qmlContext->qmlContext()->url() : QUrl());
+ error.setDescription(QLatin1String("Cannot resolve property \"%1\".")
+ .arg(properties.join(u'.')));
+ qmlWarning(createdComponent, error);
+ continue;
+ }
+ const QString lastProperty = properties.last();
+ name = engine->newString(lastProperty);
object->put(name, val);
if (engine->hasException) {
qmlWarning(createdComponent, engine->catchExceptionAsQmlError());
continue;
- } else if (isTopLevelProperty) {
- auto prop = removePropertyFromRequired(createdComponent, name->toQString(), requiredProperties);
+ } else if (isTopLevelProperty && requiredProperties) {
+ auto prop = removePropertyFromRequired(createdComponent, name->toQString(),
+ requiredProperties, engine->qmlEngine());
}
+
+ removePendingQPropertyBinding(object, lastProperty, creator);
}
engine->hasException = false;
@@ -1433,20 +1755,27 @@ QQmlError QQmlComponentPrivate::unsetRequiredPropertyToQQmlError(const RequiredP
}
error.setDescription(description);
error.setUrl(unsetRequiredProperty.fileUrl);
- error.setLine(qmlConvertSourceCoordinate<quint32, int>(unsetRequiredProperty.location.line));
- error.setColumn(qmlConvertSourceCoordinate<quint32, int>(unsetRequiredProperty.location.column));
+ error.setLine(qmlConvertSourceCoordinate<quint32, int>(
+ unsetRequiredProperty.location.line()));
+ error.setColumn(qmlConvertSourceCoordinate<quint32, int>(
+ unsetRequiredProperty.location.column()));
return error;
}
+#if QT_DEPRECATED_SINCE(6, 3)
/*!
\internal
*/
-void QQmlComponent::createObject(QQmlV4Function *args)
+void QQmlComponent::createObject(QQmlV4FunctionPtr args)
{
Q_D(QQmlComponent);
Q_ASSERT(d->engine);
Q_ASSERT(args);
+ qmlWarning(this) << "Unsuitable arguments passed to createObject(). The first argument should "
+ "be a QObject* or null, and the second argument should be a JavaScript "
+ "object or a QVariantMap";
+
QObject *parent = nullptr;
QV4::ExecutionEngine *v4 = args->v4engine();
QV4::Scope scope(v4);
@@ -1485,11 +1814,13 @@ void QQmlComponent::createObject(QQmlV4Function *args)
if (!valuemap->isUndefined()) {
QV4::Scoped<QV4::QmlContext> qmlContext(scope, v4->qmlContext());
- QQmlComponentPrivate::setInitialProperties(v4, qmlContext, object, valuemap, d->requiredProperties(), rv);
+ QQmlComponentPrivate::setInitialProperties(
+ v4, qmlContext, object, valuemap, d->state.requiredProperties(), rv,
+ d->state.creator());
}
- if (!d->requiredProperties().empty()) {
+ if (d->state.hasUnsetRequiredProperties()) {
QList<QQmlError> errors;
- for (const auto &requiredProperty: d->requiredProperties()) {
+ for (const auto &requiredProperty: std::as_const(*d->state.requiredProperties())) {
errors.push_back(QQmlComponentPrivate::unsetRequiredPropertyToQQmlError(requiredProperty));
}
qmlWarning(rv, errors);
@@ -1506,9 +1837,28 @@ void QQmlComponent::createObject(QQmlV4Function *args)
args->setReturnValue(object->asReturnedValue());
}
+#endif
+
+/*!
+ \internal
+ */
+QObject *QQmlComponent::createObject(QObject *parent, const QVariantMap &properties)
+{
+ Q_D(QQmlComponent);
+ Q_ASSERT(d->engine);
+ QObject *rv = d->createWithProperties(parent, properties, creationContext(),
+ QQmlComponentPrivate::CreateWarnAboutRequiredProperties);
+ if (rv) {
+ QQmlData *qmlData = QQmlData::get(rv);
+ Q_ASSERT(qmlData);
+ qmlData->explicitIndestructibleSet = false;
+ qmlData->indestructible = false;
+ }
+ return rv;
+}
/*!
- \qmlmethod object Component::incubateObject(Item parent, object properties, enumeration mode)
+ \qmlmethod object Component::incubateObject(QtObject parent, object properties, enumeration mode)
Creates an incubator for an instance of this component. Incubators allow new component
instances to be instantiated asynchronously and do not cause freezes in the UI.
@@ -1530,31 +1880,31 @@ void QQmlComponent::createObject(QQmlV4Function *args)
properties:
\list
- \li status The status of the incubator. Valid values are Component.Ready, Component.Loading and
+ \li \c status - The status of the incubator. Valid values are Component.Ready, Component.Loading and
Component.Error.
- \li object The created object instance. Will only be available once the incubator is in the
+ \li \c object - The created object instance. Will only be available once the incubator is in the
Ready status.
- \li onStatusChanged Specifies a callback function to be invoked when the status changes. The
+ \li \c onStatusChanged - Specifies a callback function to be invoked when the status changes. The
status is passed as a parameter to the callback.
- \li forceCompletion() Call to complete incubation synchronously.
+ \li \c{forceCompletion()} - Call to complete incubation synchronously.
\endlist
The following example demonstrates how to use an incubator:
- \js
- var component = Qt.createComponent("Button.qml");
+ \qml
+ const component = Qt.createComponent("Button.qml");
- var incubator = component.incubateObject(parent, { x: 10, y: 10 });
- if (incubator.status != Component.Ready) {
+ const incubator = component.incubateObject(parent, { x: 10, y: 10 });
+ if (incubator.status !== Component.Ready) {
incubator.onStatusChanged = function(status) {
- if (status == Component.Ready) {
- print ("Object", incubator.object, "is now ready!");
+ if (status === Component.Ready) {
+ print("Object", incubator.object, "is now ready!");
}
- }
+ };
} else {
- print ("Object", incubator.object, "is ready immediately!");
+ print("Object", incubator.object, "is ready immediately!");
}
- \endjs
+ \endqml
Dynamically created instances can be deleted with the \c destroy() method.
See \l {Dynamic QML Object Creation from JavaScript} for more information.
@@ -1565,7 +1915,7 @@ void QQmlComponent::createObject(QQmlV4Function *args)
/*!
\internal
*/
-void QQmlComponent::incubateObject(QQmlV4Function *args)
+void QQmlComponent::incubateObject(QQmlV4FunctionPtr args)
{
Q_D(QQmlComponent);
Q_ASSERT(d->engine);
@@ -1612,7 +1962,7 @@ void QQmlComponent::incubateObject(QQmlV4Function *args)
r->setPrototypeOf(p);
if (!valuemap->isUndefined())
- r->d()->valuemap.set(scope.engine, valuemap);
+ r->d()->valuemapOrObject.set(scope.engine, valuemap);
r->d()->qmlContext.set(scope.engine, v4->qmlContext());
r->d()->parent = parent;
@@ -1627,7 +1977,7 @@ void QQmlComponent::incubateObject(QQmlV4Function *args)
}
// XXX used by QSGLoader
-void QQmlComponentPrivate::initializeObjectWithInitialProperties(QV4::QmlContext *qmlContext, const QV4::Value &valuemap, QObject *toCreate, RequiredProperties &requiredProperties)
+void QQmlComponentPrivate::initializeObjectWithInitialProperties(QV4::QmlContext *qmlContext, const QV4::Value &valuemap, QObject *toCreate, RequiredProperties *requiredProperties)
{
QV4::ExecutionEngine *v4engine = engine->handle();
QV4::Scope scope(v4engine);
@@ -1635,8 +1985,10 @@ void QQmlComponentPrivate::initializeObjectWithInitialProperties(QV4::QmlContext
QV4::ScopedValue object(scope, QV4::QObjectWrapper::wrap(v4engine, toCreate));
Q_ASSERT(object->as<QV4::Object>());
- if (!valuemap.isUndefined())
- setInitialProperties(v4engine, qmlContext, object, valuemap, requiredProperties, toCreate);
+ if (!valuemap.isUndefined()) {
+ setInitialProperties(
+ v4engine, qmlContext, object, valuemap, requiredProperties, toCreate, state.creator());
+ }
}
QQmlComponentExtension::QQmlComponentExtension(QV4::ExecutionEngine *v4)
@@ -1713,7 +2065,7 @@ QQmlComponentExtension::~QQmlComponentExtension()
void QV4::Heap::QmlIncubatorObject::init(QQmlIncubator::IncubationMode m)
{
Object::init();
- valuemap.set(internalClass->engine, QV4::Value::undefinedValue());
+ valuemapOrObject.set(internalClass->engine, QV4::Value::undefinedValue());
statusChanged.set(internalClass->engine, QV4::Value::undefinedValue());
parent.init();
qmlContext.set(internalClass->engine, nullptr);
@@ -1726,36 +2078,43 @@ void QV4::Heap::QmlIncubatorObject::destroy() {
Object::destroy();
}
-void QV4::QmlIncubatorObject::setInitialState(QObject *o, RequiredProperties &requiredProperties)
+void QV4::QmlIncubatorObject::setInitialState(QObject *o, RequiredProperties *requiredProperties)
{
QQmlComponent_setQmlParent(o, d()->parent);
- if (!d()->valuemap.isUndefined()) {
+ if (!d()->valuemapOrObject.isUndefined()) {
QV4::ExecutionEngine *v4 = engine();
QV4::Scope scope(v4);
QV4::ScopedObject obj(scope, QV4::QObjectWrapper::wrap(v4, o));
QV4::Scoped<QV4::QmlContext> qmlCtxt(scope, d()->qmlContext);
- QQmlComponentPrivate::setInitialProperties(v4, qmlCtxt, obj, d()->valuemap, requiredProperties, o);
+ QQmlComponentPrivate::setInitialProperties(
+ v4, qmlCtxt, obj, d()->valuemapOrObject, requiredProperties, o,
+ QQmlIncubatorPrivate::get(d()->incubator)->creator.data());
}
}
void QV4::QmlIncubatorObject::statusChanged(QQmlIncubator::Status s)
{
QV4::Scope scope(engine());
- // hold the incubated object in a scoped value to prevent it's destruction before this method returns
- QV4::ScopedObject incubatedObject(scope, QV4::QObjectWrapper::wrap(scope.engine, d()->incubator->object()));
+
+ QObject *object = d()->incubator->object();
if (s == QQmlIncubator::Ready) {
- Q_ASSERT(QQmlData::get(d()->incubator->object()));
- QQmlData::get(d()->incubator->object())->explicitIndestructibleSet = false;
- QQmlData::get(d()->incubator->object())->indestructible = false;
+ // We don't need the arguments anymore, but we still want to hold on to the object so
+ // that it doesn't get gc'd
+ d()->valuemapOrObject.set(scope.engine, QV4::QObjectWrapper::wrap(scope.engine, object));
+
+ QQmlData *ddata = QQmlData::get(object);
+ Q_ASSERT(ddata);
+ ddata->explicitIndestructibleSet = false;
+ ddata->indestructible = false;
}
QV4::ScopedFunctionObject f(scope, d()->statusChanged);
if (f) {
- QV4::JSCallData jsCallData(scope, 1);
- *jsCallData->thisObject = this;
- jsCallData->args[0] = QV4::Value::fromUInt32(s);
+ QV4::JSCallArguments jsCallData(scope, 1);
+ *jsCallData.thisObject = this;
+ jsCallData.args[0] = QV4::Value::fromUInt32(s);
f->call(jsCallData);
if (scope.hasException()) {
QQmlError error = scope.engine->catchExceptionAsQmlError();
@@ -1772,3 +2131,4 @@ void QV4::QmlIncubatorObject::statusChanged(QQmlIncubator::Status s)
QT_END_NAMESPACE
#include "moc_qqmlcomponent.cpp"
+#include "moc_qqmlcomponentattached_p.cpp"
diff --git a/src/qml/qml/qqmlcomponent.h b/src/qml/qml/qqmlcomponent.h
index f0d51931a4..2d68c47c11 100644
--- a/src/qml/qml/qqmlcomponent.h
+++ b/src/qml/qml/qqmlcomponent.h
@@ -1,45 +1,12 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLCOMPONENT_H
#define QQMLCOMPONENT_H
+#include <QtCore/qvariant.h>
+#include <QtCore/qmap.h>
+
#include <QtQml/qqml.h>
#include <QtQml/qqmlerror.h>
@@ -54,7 +21,6 @@ class QByteArray;
class QQmlEngine;
class QQmlComponent;
class QQmlIncubator;
-class QQmlV4Function;
class QQmlComponentPrivate;
class QQmlComponentAttached;
@@ -70,9 +36,6 @@ class Q_QML_EXPORT QQmlComponent : public QObject
Q_PROPERTY(qreal progress READ progress NOTIFY progressChanged)
Q_PROPERTY(Status status READ status NOTIFY statusChanged)
Q_PROPERTY(QUrl url READ url CONSTANT)
- QML_NAMED_ELEMENT(Component)
- QML_ADDED_IN_VERSION(2, 0)
- QML_ATTACHED(QQmlComponentAttached)
public:
enum CompilationMode { PreferSynchronous, Asynchronous };
@@ -84,6 +47,10 @@ public:
QQmlComponent(QQmlEngine *, const QString &fileName, CompilationMode mode, QObject *parent = nullptr);
QQmlComponent(QQmlEngine *, const QUrl &url, QObject *parent = nullptr);
QQmlComponent(QQmlEngine *, const QUrl &url, CompilationMode mode, QObject *parent = nullptr);
+
+ explicit QQmlComponent(QQmlEngine *engine, QAnyStringView uri, QAnyStringView typeName, QObject *parent = nullptr);
+ explicit QQmlComponent(QQmlEngine *engine, QAnyStringView uri, QAnyStringView typeName, CompilationMode mode, QObject *parent = nullptr);
+
~QQmlComponent() override;
enum Status { Null, Ready, Loading, Error };
@@ -95,6 +62,8 @@ public:
bool isError() const;
bool isLoading() const;
+ bool isBound() const;
+
QList<QQmlError> errors() const;
Q_INVOKABLE QString errorString() const;
@@ -119,6 +88,8 @@ public:
public Q_SLOTS:
void loadUrl(const QUrl &url);
void loadUrl(const QUrl &url, CompilationMode mode);
+ void loadFromModule(QAnyStringView uri, QAnyStringView typeName,
+ QQmlComponent::CompilationMode mode = PreferSynchronous);
void setData(const QByteArray &, const QUrl &baseUrl);
Q_SIGNALS:
@@ -127,8 +98,15 @@ Q_SIGNALS:
protected:
QQmlComponent(QQmlComponentPrivate &dd, QObject* parent);
- Q_INVOKABLE void createObject(QQmlV4Function *);
- Q_INVOKABLE void incubateObject(QQmlV4Function *);
+
+#if QT_DEPRECATED_SINCE(6, 3)
+ QT_DEPRECATED_X("Use the overload with proper arguments")
+ Q_INVOKABLE void createObject(QQmlV4FunctionPtr);
+#endif
+
+ Q_INVOKABLE QObject *createObject(
+ QObject *parent = nullptr, const QVariantMap &properties = {});
+ Q_INVOKABLE void incubateObject(QQmlV4FunctionPtr);
private:
QQmlComponent(QQmlEngine *, QV4::ExecutableCompilationUnit *compilationUnit, int,
@@ -160,8 +138,6 @@ struct OverridableAttachedType<QQmlComponent, QQmlComponentAttached>
} // namespace QQmlPrivate
-
QT_END_NAMESPACE
-QML_DECLARE_TYPE(QQmlComponent)
#endif // QQMLCOMPONENT_H
diff --git a/src/qml/qml/qqmlcomponent_p.h b/src/qml/qml/qqmlcomponent_p.h
index abc0de7438..21fdee3f7a 100644
--- a/src/qml/qml/qqmlcomponent_p.h
+++ b/src/qml/qml/qqmlcomponent_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLCOMPONENT_P_H
#define QQMLCOMPONENT_P_H
@@ -54,10 +18,7 @@
#include "qqmlcomponent.h"
#include "qqmlengine_p.h"
-#include "qqmltypeloader_p.h"
-#include "qqmlvme_p.h"
#include "qqmlerror.h"
-#include "qqml.h"
#include <private/qqmlobjectcreator_p.h>
#include <private/qqmltypedata_p.h>
#include <private/qqmlguardedcontextdata_p.h>
@@ -65,6 +26,7 @@
#include <QtCore/QString>
#include <QtCore/QStringList>
#include <QtCore/QList>
+#include <QtCore/qtclasshelpermacros.h>
#include <private/qobject_p.h>
@@ -74,20 +36,23 @@ class QQmlComponent;
class QQmlEngine;
class QQmlComponentAttached;
-class Q_QML_PRIVATE_EXPORT QQmlComponentPrivate : public QObjectPrivate, public QQmlTypeData::TypeDataCallback
+class Q_QML_EXPORT QQmlComponentPrivate : public QObjectPrivate, public QQmlTypeData::TypeDataCallback
{
Q_DECLARE_PUBLIC(QQmlComponent)
public:
QQmlComponentPrivate()
- : progress(0.), start(-1), engine(nullptr), creationContext(nullptr) {}
+ : progress(0.), start(-1), engine(nullptr) {}
void loadUrl(const QUrl &newUrl, QQmlComponent::CompilationMode mode = QQmlComponent::PreferSynchronous);
QObject *beginCreate(QQmlRefPointer<QQmlContextData>);
void completeCreate();
- void initializeObjectWithInitialProperties(QV4::QmlContext *qmlContext, const QV4::Value &valuemap, QObject *toCreate, RequiredProperties &requiredProperties);
- static void setInitialProperties(QV4::ExecutionEngine *engine, QV4::QmlContext *qmlContext, const QV4::Value &o, const QV4::Value &v, RequiredProperties &requiredProperties, QObject *createdComponent);
+ void initializeObjectWithInitialProperties(QV4::QmlContext *qmlContext, const QV4::Value &valuemap, QObject *toCreate, RequiredProperties *requiredProperties);
+ static void setInitialProperties(
+ QV4::ExecutionEngine *engine, QV4::QmlContext *qmlContext, const QV4::Value &o,
+ const QV4::Value &v, RequiredProperties *requiredProperties, QObject *createdComponent,
+ QQmlObjectCreator *creator);
static QQmlError unsetRequiredPropertyToQQmlError(const RequiredPropertyInfo &unsetRequiredProperty);
virtual void incubateObject(
@@ -105,39 +70,83 @@ public:
QUrl url;
qreal progress;
+ std::unique_ptr<QString> inlineComponentName;
+ /* points to the sub-object in a QML file that should be instantiated
+ used create instances of QtQml's Component type and indirectly for inline components */
int start;
- RequiredProperties& requiredProperties();
- bool hadRequiredProperties() const;
+
+ bool hadTopLevelRequiredProperties() const;
+ // TODO: merge compilation unit and type
QQmlRefPointer<QV4::ExecutableCompilationUnit> compilationUnit;
+ QQmlType loadedType;
- struct ConstructionState {
- ConstructionState()
- : completePending(false)
- {}
- ~ConstructionState()
+ struct AnnotatedQmlError
+ {
+ AnnotatedQmlError() = default;
+
+ AnnotatedQmlError(QQmlError error)
+ : error(std::move(error))
{
}
- QScopedPointer<QQmlObjectCreator> creator;
- QList<QQmlError> errors;
- bool completePending;
+
+ AnnotatedQmlError(QQmlError error, bool transient)
+ : error(std::move(error)), isTransient(transient)
+ {
+ }
+ QQmlError error;
+ bool isTransient = false; // tells if the error is temporary (e.g. unset required property)
};
- ConstructionState state;
- struct DeferredState {
- ~DeferredState() {
- qDeleteAll(constructionStates);
- constructionStates.clear();
+ struct ConstructionState {
+ ConstructionState() = default;
+ inline ~ConstructionState();
+ Q_DISABLE_COPY(ConstructionState)
+ inline ConstructionState(ConstructionState &&other) noexcept;
+
+ void swap(ConstructionState &other)
+ {
+ m_creatorOrRequiredProperties.swap(other.m_creatorOrRequiredProperties);
}
- QVector<ConstructionState *> constructionStates;
+
+ QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_MOVE_AND_SWAP(QQmlComponentPrivate::ConstructionState);
+
+ inline void ensureRequiredPropertyStorage();
+ inline RequiredProperties *requiredProperties();
+ inline void addPendingRequiredProperty(
+ const QObject *object, const QQmlPropertyData *propData,
+ const RequiredPropertyInfo &info);
+ inline bool hasUnsetRequiredProperties() const;
+ inline void clearRequiredProperties();
+
+ inline void appendErrors(const QList<QQmlError> &qmlErrors);
+ inline void appendCreatorErrors();
+
+ inline QQmlObjectCreator *creator();
+ inline const QQmlObjectCreator *creator() const;
+ inline void clear();
+ inline bool hasCreator() const;
+ inline QQmlObjectCreator *initCreator(QQmlRefPointer<QQmlContextData> parentContext,
+ const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit,
+ const QQmlRefPointer<QQmlContextData> &creationContext);
+
+ QList<AnnotatedQmlError> errors;
+ inline bool isCompletePending() const;
+ inline void setCompletePending(bool isPending);
+
+ private:
+ QBiPointer<QQmlObjectCreator, RequiredProperties> m_creatorOrRequiredProperties;
};
+ ConstructionState state;
+ using DeferredState = std::vector<ConstructionState>;
static void beginDeferred(QQmlEnginePrivate *enginePriv, QObject *object, DeferredState* deferredState);
static void completeDeferred(QQmlEnginePrivate *enginePriv, DeferredState *deferredState);
static void complete(QQmlEnginePrivate *enginePriv, ConstructionState *state);
- static QQmlProperty removePropertyFromRequired(QObject *createdComponent, const QString &name, RequiredProperties& requiredProperties, bool *wasInRequiredProperties = nullptr);
+ static QQmlProperty removePropertyFromRequired(QObject *createdComponent, const QString &name, RequiredProperties *requiredProperties,
+ QQmlEngine *engine, bool *wasInRequiredProperties = nullptr);
QQmlEngine *engine;
QQmlGuardedContextData creationContext;
@@ -150,8 +159,150 @@ public:
QObject *doBeginCreate(QQmlComponent *q, QQmlContext *context);
bool setInitialProperty(QObject *component, const QString &name, const QVariant& value);
+
+ enum CreateBehavior {
+ CreateDefault,
+ CreateWarnAboutRequiredProperties,
+ };
+ QObject *createWithProperties(QObject *parent, const QVariantMap &properties,
+ QQmlContext *context, CreateBehavior behavior = CreateDefault);
+
+ bool isBound() const { return compilationUnit && (compilationUnit->componentsAreBound()); }
+ LoadHelper::ResolveTypeResult prepareLoadFromModule(QAnyStringView uri,
+ QAnyStringView typeName);
+ void completeLoadFromModule(QAnyStringView uri, QAnyStringView typeName, QQmlType type,
+ LoadHelper::ResolveTypeResult::Status moduleStatus,
+ QQmlComponent::CompilationMode mode = QQmlComponent::PreferSynchronous);
};
+QQmlComponentPrivate::ConstructionState::~ConstructionState()
+{
+ if (m_creatorOrRequiredProperties.isT1())
+ delete m_creatorOrRequiredProperties.asT1();
+ else
+ delete m_creatorOrRequiredProperties.asT2();
+}
+
+QQmlComponentPrivate::ConstructionState::ConstructionState(ConstructionState &&other) noexcept
+{
+ errors = std::move(other.errors);
+ m_creatorOrRequiredProperties = std::exchange(other.m_creatorOrRequiredProperties, {});
+}
+
+/*!
+ \internal A list of pending required properties that need
+ to be set in order for object construction to be successful.
+ */
+inline RequiredProperties *QQmlComponentPrivate::ConstructionState::requiredProperties() {
+ if (m_creatorOrRequiredProperties.isNull())
+ return nullptr;
+ else if (m_creatorOrRequiredProperties.isT1())
+ return m_creatorOrRequiredProperties.asT1()->requiredProperties();
+ else
+ return m_creatorOrRequiredProperties.asT2();
+}
+
+inline void QQmlComponentPrivate::ConstructionState::addPendingRequiredProperty(
+ const QObject *object, const QQmlPropertyData *propData, const RequiredPropertyInfo &info)
+{
+ Q_ASSERT(requiredProperties());
+ requiredProperties()->insert({object, propData}, info);
+}
+
+inline bool QQmlComponentPrivate::ConstructionState::hasUnsetRequiredProperties() const {
+ auto properties = const_cast<ConstructionState *>(this)->requiredProperties();
+ return properties && !properties->isEmpty();
+}
+
+inline void QQmlComponentPrivate::ConstructionState::clearRequiredProperties()
+{
+ if (auto reqProps = requiredProperties())
+ reqProps->clear();
+}
+
+inline void QQmlComponentPrivate::ConstructionState::appendErrors(const QList<QQmlError> &qmlErrors)
+{
+ for (const QQmlError &e : qmlErrors)
+ errors.emplaceBack(e);
+}
+
+//! \internal Moves errors from creator into construction state itself
+inline void QQmlComponentPrivate::ConstructionState::appendCreatorErrors()
+{
+ if (!hasCreator())
+ return;
+ auto creatorErrorCount = creator()->errors.size();
+ if (creatorErrorCount == 0)
+ return;
+ auto existingErrorCount = errors.size();
+ errors.resize(existingErrorCount + creatorErrorCount);
+ for (qsizetype i = 0; i < creatorErrorCount; ++i)
+ errors[existingErrorCount + i] = AnnotatedQmlError { std::move(creator()->errors[i]) };
+ creator()->errors.clear();
+}
+
+inline QQmlObjectCreator *QQmlComponentPrivate::ConstructionState::creator()
+{
+ if (m_creatorOrRequiredProperties.isT1())
+ return m_creatorOrRequiredProperties.asT1();
+ return nullptr;
+}
+
+inline const QQmlObjectCreator *QQmlComponentPrivate::ConstructionState::creator() const
+{
+ if (m_creatorOrRequiredProperties.isT1())
+ return m_creatorOrRequiredProperties.asT1();
+ return nullptr;
+}
+
+inline bool QQmlComponentPrivate::ConstructionState::hasCreator() const
+{
+ return creator() != nullptr;
+}
+
+inline void QQmlComponentPrivate::ConstructionState::clear()
+{
+ if (m_creatorOrRequiredProperties.isT1()) {
+ delete m_creatorOrRequiredProperties.asT1();
+ m_creatorOrRequiredProperties = static_cast<QQmlObjectCreator *>(nullptr);
+ }
+}
+
+inline QQmlObjectCreator *QQmlComponentPrivate::ConstructionState::initCreator(QQmlRefPointer<QQmlContextData> parentContext, const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit, const QQmlRefPointer<QQmlContextData> &creationContext)
+{
+ if (m_creatorOrRequiredProperties.isT1())
+ delete m_creatorOrRequiredProperties.asT1();
+ else
+ delete m_creatorOrRequiredProperties.asT2();
+ m_creatorOrRequiredProperties = new QQmlObjectCreator(
+ std::move(parentContext), compilationUnit,
+ creationContext);
+ return m_creatorOrRequiredProperties.asT1();
+}
+
+inline bool QQmlComponentPrivate::ConstructionState::isCompletePending() const
+{
+ return m_creatorOrRequiredProperties.flag();
+}
+
+inline void QQmlComponentPrivate::ConstructionState::setCompletePending(bool isPending)
+{
+ m_creatorOrRequiredProperties.setFlagValue(isPending);
+}
+
+/*!
+ \internal
+ This is meant to be used in the context of QQmlComponent::loadFromModule,
+ when dealing with a C++ type. In that case, we do not have a creator,
+ and need a separate storage for required properties.
+ */
+inline void QQmlComponentPrivate::ConstructionState::ensureRequiredPropertyStorage()
+{
+ Q_ASSERT(m_creatorOrRequiredProperties.isT2() || m_creatorOrRequiredProperties.isNull());
+ if (m_creatorOrRequiredProperties.isNull())
+ m_creatorOrRequiredProperties = new RequiredProperties;
+}
+
QT_END_NAMESPACE
#endif // QQMLCOMPONENT_P_H
diff --git a/src/qml/qml/qqmlcomponentandaliasresolver_p.h b/src/qml/qml/qqmlcomponentandaliasresolver_p.h
new file mode 100644
index 0000000000..a2758d385c
--- /dev/null
+++ b/src/qml/qml/qqmlcomponentandaliasresolver_p.h
@@ -0,0 +1,480 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+#ifndef QQMLCOMPONENTANDALIASRESOLVER_P_H
+#define QQMLCOMPONENTANDALIASRESOLVER_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 <QtQml/qqmlcomponent.h>
+#include <QtQml/qqmlerror.h>
+
+#include <QtCore/qglobal.h>
+#include <QtCore/qhash.h>
+
+#include <private/qqmltypeloader_p.h>
+#include <private/qqmlpropertycachecreator_p.h>
+
+QT_BEGIN_NAMESPACE
+
+Q_DECLARE_LOGGING_CATEGORY(lcQmlTypeCompiler);
+
+// This class primarily resolves component boundaries in a document.
+// With the information about boundaries, it then goes on to resolve aliases and generalized
+// group properties. Both rely on IDs as first part of their expressions and the IDs have
+// to be located in surrounding components. That's why we have to do this with the component
+// boundaries in mind.
+
+template<typename ObjectContainer>
+class QQmlComponentAndAliasResolver
+{
+ Q_DECLARE_TR_FUNCTIONS(QQmlComponentAndAliasResolver)
+public:
+ using CompiledObject = typename ObjectContainer::CompiledObject;
+ using CompiledBinding = typename ObjectContainer::CompiledBinding;
+
+ QQmlComponentAndAliasResolver(
+ ObjectContainer *compiler,
+ QQmlEnginePrivate *enginePrivate,
+ QQmlPropertyCacheVector *propertyCaches);
+
+ [[nodiscard]] QQmlError resolve(int root = 0);
+
+private:
+ enum AliasResolutionResult {
+ NoAliasResolved,
+ SomeAliasesResolved,
+ AllAliasesResolved
+ };
+
+ // To be specialized for each container
+ void allocateNamedObjects(CompiledObject *object) const;
+ void setObjectId(int index) const;
+ [[nodiscard]] bool markAsComponent(int index) const;
+ [[nodiscard]] AliasResolutionResult resolveAliasesInObject(
+ const CompiledObject &component, int objectIndex, QQmlError *error);
+ void resolveGeneralizedGroupProperty(const CompiledObject &component, CompiledBinding *binding);
+ [[nodiscard]] bool wrapImplicitComponent(CompiledBinding *binding);
+
+ [[nodiscard]] QQmlError findAndRegisterImplicitComponents(
+ const CompiledObject *obj, const QQmlPropertyCache::ConstPtr &propertyCache);
+ [[nodiscard]] QQmlError collectIdsAndAliases(int objectIndex);
+ [[nodiscard]] QQmlError resolveAliases(int componentIndex);
+ void resolveGeneralizedGroupProperties(int componentIndex);
+ [[nodiscard]] QQmlError resolveComponentsInInlineComponentRoot(int root);
+
+ QString stringAt(int idx) const { return m_compiler->stringAt(idx); }
+ QV4::ResolvedTypeReference *resolvedType(int id) const { return m_compiler->resolvedType(id); }
+
+ [[nodiscard]] QQmlError error(
+ const QV4::CompiledData::Location &location,
+ const QString &description)
+ {
+ QQmlError error;
+ error.setLine(qmlConvertSourceCoordinate<quint32, int>(location.line()));
+ error.setColumn(qmlConvertSourceCoordinate<quint32, int>(location.column()));
+ error.setDescription(description);
+ error.setUrl(m_compiler->url());
+ return error;
+ }
+
+ template<typename Token>
+ [[nodiscard]] QQmlError error(Token token, const QString &description)
+ {
+ return error(token->location, description);
+ }
+
+ static bool isUsableComponent(const QMetaObject *metaObject)
+ {
+ // The metaObject is a component we're interested in if it either is a QQmlComponent itself
+ // or if any of its parents is a QQmlAbstractDelegateComponent. We don't want to include
+ // qqmldelegatecomponent_p.h because it belongs to QtQmlModels.
+
+ if (metaObject == &QQmlComponent::staticMetaObject)
+ return true;
+
+ for (; metaObject; metaObject = metaObject->superClass()) {
+ if (qstrcmp(metaObject->className(), "QQmlAbstractDelegateComponent") == 0)
+ return true;
+ }
+
+ return false;
+ }
+
+ ObjectContainer *m_compiler = nullptr;
+ QQmlEnginePrivate *m_enginePrivate = nullptr;
+
+ // Implicit component insertion may have added objects and thus we also need
+ // to extend the symmetric propertyCaches. Therefore, non-const propertyCaches.
+ QQmlPropertyCacheVector *m_propertyCaches = nullptr;
+
+ // indices of the objects that are actually Component {}
+ QVector<quint32> m_componentRoots;
+ QVector<int> m_objectsWithAliases;
+ QVector<CompiledBinding *> m_generalizedGroupProperties;
+ typename ObjectContainer::IdToObjectMap m_idToObjectIndex;
+};
+
+template<typename ObjectContainer>
+QQmlComponentAndAliasResolver<ObjectContainer>::QQmlComponentAndAliasResolver(
+ ObjectContainer *compiler,
+ QQmlEnginePrivate *enginePrivate,
+ QQmlPropertyCacheVector *propertyCaches)
+ : m_compiler(compiler)
+ , m_enginePrivate(enginePrivate)
+ , m_propertyCaches(propertyCaches)
+{
+}
+
+template<typename ObjectContainer>
+QQmlError QQmlComponentAndAliasResolver<ObjectContainer>::findAndRegisterImplicitComponents(
+ const CompiledObject *obj, const QQmlPropertyCache::ConstPtr &propertyCache)
+{
+ QQmlPropertyResolver propertyResolver(propertyCache);
+
+ const QQmlPropertyData *defaultProperty = obj->indexOfDefaultPropertyOrAlias != -1
+ ? propertyCache->parent()->defaultProperty()
+ : propertyCache->defaultProperty();
+
+ for (auto binding = obj->bindingsBegin(), end = obj->bindingsEnd(); binding != end; ++binding) {
+ if (binding->type() != QV4::CompiledData::Binding::Type_Object)
+ continue;
+ if (binding->hasFlag(QV4::CompiledData::Binding::IsSignalHandlerObject))
+ continue;
+
+ auto targetObject = m_compiler->objectAt(binding->value.objectIndex);
+ auto typeReference = resolvedType(targetObject->inheritedTypeNameIndex);
+ Q_ASSERT(typeReference);
+
+ const QMetaObject *firstMetaObject = nullptr;
+ const auto type = typeReference->type();
+ if (type.isValid())
+ firstMetaObject = type.metaObject();
+ else if (const auto compilationUnit = typeReference->compilationUnit())
+ firstMetaObject = compilationUnit->rootPropertyCache()->firstCppMetaObject();
+ if (isUsableComponent(firstMetaObject))
+ continue;
+
+ // if here, not a QQmlComponent, so needs wrapping
+ const QQmlPropertyData *pd = nullptr;
+ if (binding->propertyNameIndex != quint32(0)) {
+ bool notInRevision = false;
+ pd = propertyResolver.property(stringAt(binding->propertyNameIndex), &notInRevision);
+ } else {
+ pd = defaultProperty;
+ }
+ if (!pd || !pd->isQObject())
+ continue;
+
+ // If the version is given, use it and look up by QQmlType.
+ // Otherwise, make sure we look up by metaobject.
+ // TODO: Is this correct?
+ QQmlPropertyCache::ConstPtr pc = pd->typeVersion().hasMinorVersion()
+ ? QQmlMetaType::rawPropertyCacheForType(pd->propType(), pd->typeVersion())
+ : QQmlMetaType::rawPropertyCacheForType(pd->propType());
+ const QMetaObject *mo = pc ? pc->firstCppMetaObject() : nullptr;
+ while (mo) {
+ if (mo == &QQmlComponent::staticMetaObject)
+ break;
+ mo = mo->superClass();
+ }
+
+ if (!mo)
+ continue;
+
+ if (!wrapImplicitComponent(binding))
+ return error(binding, tr("Cannot wrap implicit component"));
+ }
+
+ return QQmlError();
+}
+
+template<typename ObjectContainer>
+QQmlError QQmlComponentAndAliasResolver<ObjectContainer>::resolveComponentsInInlineComponentRoot(
+ int root)
+{
+ // Find implicit components in the inline component itself. Also warn about inline
+ // components being explicit components.
+
+ const auto rootObj = m_compiler->objectAt(root);
+ Q_ASSERT(rootObj->hasFlag(QV4::CompiledData::Object::IsInlineComponentRoot));
+
+ if (const int typeName = rootObj->inheritedTypeNameIndex) {
+ const auto *tref = resolvedType(typeName);
+ Q_ASSERT(tref);
+ if (tref->type().metaObject() == &QQmlComponent::staticMetaObject) {
+ qCWarning(lcQmlTypeCompiler).nospace().noquote()
+ << m_compiler->url().toString() << ":" << rootObj->location.line() << ":"
+ << rootObj->location.column()
+ << ": Using a Component as the root of an inline component is deprecated: "
+ "inline components are "
+ "automatically wrapped into Components when needed.";
+ return QQmlError();
+ }
+ }
+
+ const QQmlPropertyCache::ConstPtr rootCache = m_propertyCaches->at(root);
+ Q_ASSERT(rootCache);
+
+ return findAndRegisterImplicitComponents(rootObj, rootCache);
+}
+
+// Resolve ignores everything relating to inline components, except for implicit components.
+template<typename ObjectContainer>
+QQmlError QQmlComponentAndAliasResolver<ObjectContainer>::resolve(int root)
+{
+ // Detect real Component {} objects as well as implicitly defined components, such as
+ // someItemDelegate: Item {}
+ // In the implicit case Item is surrounded by a synthetic Component {} because the property
+ // on the left hand side is of QQmlComponent type.
+ const int objCountWithoutSynthesizedComponents = m_compiler->objectCount();
+
+ if (root != 0) {
+ const QQmlError error = resolveComponentsInInlineComponentRoot(root);
+ if (error.isValid())
+ return error;
+ }
+
+ // root+1, as ic root is handled at the end
+ const int startObjectIndex = root == 0 ? root : root+1;
+
+ for (int i = startObjectIndex; i < objCountWithoutSynthesizedComponents; ++i) {
+ auto obj = m_compiler->objectAt(i);
+ const bool isInlineComponentRoot
+ = obj->hasFlag(QV4::CompiledData::Object::IsInlineComponentRoot);
+ const bool isPartOfInlineComponent
+ = obj->hasFlag(QV4::CompiledData::Object::IsPartOfInlineComponent);
+ QQmlPropertyCache::ConstPtr cache = m_propertyCaches->at(i);
+
+ if (root == 0) {
+ // normal component root, skip over anything inline component related
+ if (isInlineComponentRoot || isPartOfInlineComponent)
+ continue;
+ } else if (!isPartOfInlineComponent || isInlineComponentRoot) {
+ // When handling an inline component, stop where the inline component ends
+ // Note: We do not support nested inline components. Therefore, isInlineComponentRoot
+ // tells us that the element after the current inline component is again an
+ // inline component
+ break;
+ }
+
+ if (obj->inheritedTypeNameIndex == 0 && !cache)
+ continue;
+
+ bool isExplicitComponent = false;
+ if (obj->inheritedTypeNameIndex) {
+ auto *tref = resolvedType(obj->inheritedTypeNameIndex);
+ Q_ASSERT(tref);
+ if (tref->type().metaObject() == &QQmlComponent::staticMetaObject)
+ isExplicitComponent = true;
+ }
+
+ if (!isExplicitComponent) {
+ if (cache) {
+ const QQmlError error = findAndRegisterImplicitComponents(obj, cache);
+ if (error.isValid())
+ return error;
+ }
+ continue;
+ }
+
+ if (!markAsComponent(i))
+ return error(obj, tr("Cannot mark object as component"));
+
+ // check if this object is the root
+ if (i == 0) {
+ if (isExplicitComponent)
+ qCWarning(lcQmlTypeCompiler).nospace().noquote()
+ << m_compiler->url().toString() << ":" << obj->location.line() << ":"
+ << obj->location.column()
+ << ": Using a Component as the root of a QML document is deprecated: types "
+ "defined in qml documents are "
+ "automatically wrapped into Components when needed.";
+ }
+
+ if (obj->functionCount() > 0)
+ return error(obj, tr("Component objects cannot declare new functions."));
+ if (obj->propertyCount() > 0 || obj->aliasCount() > 0)
+ return error(obj, tr("Component objects cannot declare new properties."));
+ if (obj->signalCount() > 0)
+ return error(obj, tr("Component objects cannot declare new signals."));
+
+ if (obj->bindingCount() == 0)
+ return error(obj, tr("Cannot create empty component specification"));
+
+ const auto rootBinding = obj->bindingsBegin();
+ const auto bindingsEnd = obj->bindingsEnd();
+
+ // Produce the more specific "no properties" error rather than the "invalid body" error
+ // where possible.
+ for (auto b = rootBinding; b != bindingsEnd; ++b) {
+ if (b->propertyNameIndex == 0)
+ continue;
+
+ return error(b, tr("Component elements may not contain properties other than id"));
+ }
+
+ if (auto b = rootBinding;
+ b->type() != QV4::CompiledData::Binding::Type_Object || ++b != bindingsEnd) {
+ return error(obj, tr("Invalid component body specification"));
+ }
+
+ // For the root object, we are going to collect ids/aliases and resolve them for as a
+ // separate last pass.
+ if (i != 0)
+ m_componentRoots.append(i);
+ }
+
+ for (int i = 0; i < m_componentRoots.size(); ++i) {
+ CompiledObject *component = m_compiler->objectAt(m_componentRoots.at(i));
+ const auto rootBinding = component->bindingsBegin();
+
+ m_idToObjectIndex.clear();
+ m_objectsWithAliases.clear();
+ m_generalizedGroupProperties.clear();
+
+ if (const QQmlError error = collectIdsAndAliases(rootBinding->value.objectIndex);
+ error.isValid()) {
+ return error;
+ }
+
+ allocateNamedObjects(component);
+
+ if (const QQmlError error = resolveAliases(m_componentRoots.at(i)); error.isValid())
+ return error;
+
+ resolveGeneralizedGroupProperties(m_componentRoots.at(i));
+ }
+
+ // Collect ids and aliases for root
+ m_idToObjectIndex.clear();
+ m_objectsWithAliases.clear();
+ m_generalizedGroupProperties.clear();
+
+ if (const QQmlError error = collectIdsAndAliases(root); error.isValid())
+ return error;
+
+ allocateNamedObjects(m_compiler->objectAt(root));
+ if (const QQmlError error = resolveAliases(root); error.isValid())
+ return error;
+
+ resolveGeneralizedGroupProperties(root);
+ return QQmlError();
+}
+
+template<typename ObjectContainer>
+QQmlError QQmlComponentAndAliasResolver<ObjectContainer>::collectIdsAndAliases(int objectIndex)
+{
+ auto obj = m_compiler->objectAt(objectIndex);
+
+ if (obj->idNameIndex != 0) {
+ if (m_idToObjectIndex.contains(obj->idNameIndex))
+ return error(obj->locationOfIdProperty, tr("id is not unique"));
+ setObjectId(objectIndex);
+ m_idToObjectIndex.insert(obj->idNameIndex, objectIndex);
+ }
+
+ if (obj->aliasCount() > 0)
+ m_objectsWithAliases.append(objectIndex);
+
+ // Stop at Component boundary
+ if (obj->hasFlag(QV4::CompiledData::Object::IsComponent) && objectIndex != /*root object*/0)
+ return QQmlError();
+
+ for (auto binding = obj->bindingsBegin(), end = obj->bindingsEnd();
+ binding != end; ++binding) {
+ switch (binding->type()) {
+ case QV4::CompiledData::Binding::Type_GroupProperty: {
+ const auto *inner = m_compiler->objectAt(binding->value.objectIndex);
+ if (m_compiler->stringAt(inner->inheritedTypeNameIndex).isEmpty()) {
+ const auto cache = m_propertyCaches->at(objectIndex);
+ if (!cache || !cache->property(
+ m_compiler->stringAt(binding->propertyNameIndex), nullptr, nullptr)) {
+ m_generalizedGroupProperties.append(binding);
+ }
+ }
+ }
+ Q_FALLTHROUGH();
+ case QV4::CompiledData::Binding::Type_Object:
+ case QV4::CompiledData::Binding::Type_AttachedProperty:
+ if (const QQmlError error = collectIdsAndAliases(binding->value.objectIndex);
+ error.isValid()) {
+ return error;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ return QQmlError();
+}
+
+template<typename ObjectContainer>
+QQmlError QQmlComponentAndAliasResolver<ObjectContainer>::resolveAliases(int componentIndex)
+{
+ if (m_objectsWithAliases.isEmpty())
+ return QQmlError();
+
+ QQmlPropertyCacheAliasCreator<ObjectContainer> aliasCacheCreator(m_propertyCaches, m_compiler);
+
+ bool atLeastOneAliasResolved;
+ do {
+ atLeastOneAliasResolved = false;
+ QVector<int> pendingObjects;
+
+ for (int objectIndex: std::as_const(m_objectsWithAliases)) {
+
+ QQmlError error;
+ const auto &component = *m_compiler->objectAt(componentIndex);
+ const auto result = resolveAliasesInObject(component, objectIndex, &error);
+ if (error.isValid())
+ return error;
+
+ if (result == AllAliasesResolved) {
+ QQmlError error = aliasCacheCreator.appendAliasesToPropertyCache(
+ component, objectIndex, m_enginePrivate);
+ if (error.isValid())
+ return error;
+ atLeastOneAliasResolved = true;
+ } else if (result == SomeAliasesResolved) {
+ atLeastOneAliasResolved = true;
+ pendingObjects.append(objectIndex);
+ } else {
+ pendingObjects.append(objectIndex);
+ }
+ }
+ qSwap(m_objectsWithAliases, pendingObjects);
+ } while (!m_objectsWithAliases.isEmpty() && atLeastOneAliasResolved);
+
+ if (!atLeastOneAliasResolved && !m_objectsWithAliases.isEmpty()) {
+ const CompiledObject *obj = m_compiler->objectAt(m_objectsWithAliases.first());
+ for (auto alias = obj->aliasesBegin(), end = obj->aliasesEnd(); alias != end; ++alias) {
+ if (!alias->hasFlag(QV4::CompiledData::Alias::Resolved))
+ return error(alias->location, tr("Circular alias reference detected"));
+ }
+ }
+
+ return QQmlError();
+}
+
+template<typename ObjectContainer>
+void QQmlComponentAndAliasResolver<ObjectContainer>::resolveGeneralizedGroupProperties(
+ int componentIndex)
+{
+ const auto &component = *m_compiler->objectAt(componentIndex);
+ for (CompiledBinding *binding : m_generalizedGroupProperties)
+ resolveGeneralizedGroupProperty(component, binding);
+}
+
+QT_END_NAMESPACE
+
+#endif // QQMLCOMPONENTANDALIASRESOLVER_P_H
diff --git a/src/qml/qml/qqmlcomponentattached_p.h b/src/qml/qml/qqmlcomponentattached_p.h
index b94d474d1f..303fea7b46 100644
--- a/src/qml/qml/qqmlcomponentattached_p.h
+++ b/src/qml/qml/qqmlcomponentattached_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLCOMPONENTATTACHED_P_H
#define QQMLCOMPONENTATTACHED_P_H
@@ -52,21 +16,17 @@
//
#include <QtQml/qqml.h>
+#include <QtQml/qqmlcomponent.h>
#include <private/qtqmlglobal_p.h>
#include <QtCore/QObject>
QT_BEGIN_NAMESPACE
-class Q_QML_PRIVATE_EXPORT QQmlComponentAttached : public QObject
+// implemented in qqmlcomponent.cpp
+class Q_QML_EXPORT QQmlComponentAttached : public QObject
{
Q_OBJECT
-
- // Used as attached object for QQmlComponent. We want qqmlcomponentattached_p.h to be #include'd
- // when registering QQmlComponent, but we cannot #include it from qqmlcomponent.h. Therefore we
- // force an anonymous type registration here.
- QML_ANONYMOUS
- QML_ADDED_IN_VERSION(2, 0)
public:
QQmlComponentAttached(QObject *parent = nullptr);
~QQmlComponentAttached();
@@ -102,4 +62,7 @@ private:
QT_END_NAMESPACE
+// TODO: We still need this because we cannot properly use QML_ATTACHED with QML_FOREIGN.
+QML_DECLARE_TYPEINFO(QQmlComponent, QML_HAS_ATTACHED_PROPERTIES)
+
#endif // QQMLCOMPONENTATTACHED_P_H
diff --git a/src/qml/qml/qqmlcontext.cpp b/src/qml/qml/qqmlcontext.cpp
index 797ab34937..cf6736deb9 100644
--- a/src/qml/qml/qqmlcontext.cpp
+++ b/src/qml/qml/qqmlcontext.cpp
@@ -1,43 +1,6 @@
-/****************************************************************************
-**
-** 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 "qqmlcontext.h"
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
#include "qqmlcontext_p.h"
#include "qqmlcomponentattached_p.h"
@@ -60,30 +23,44 @@ QT_BEGIN_NAMESPACE
\brief The QQmlContext class defines a context within a QML engine.
\inmodule QtQml
- Contexts allow data to be exposed to the QML components instantiated by the
- QML engine.
+ Contexts hold the objects identified by \e id in a QML document. You
+ can use \l{nameForObject()} and \l{objectForName()} to retrieve them.
+
+ \note It is the responsibility of the creator to delete any QQmlContext it
+ constructs. If a QQmlContext is no longer needed, it must be destroyed
+ explicitly. The simplest way to ensure this is to give the QQmlContext a
+ \l{QObject::setParent()}{parent}.
+
+ \section2 The Context Hierarchy
+
+ Contexts form a hierarchy. The root of this hierarchy is the QML engine's
+ \l {QQmlEngine::rootContext()}{root context}. Each QML component creates its
+ own context when instantiated and some QML elements create extra contexts
+ for themselves.
+
+ While QML objects instantiated in a context are not strictly owned by that
+ context, their bindings are. If a context is destroyed, the property bindings of
+ outstanding QML objects will stop evaluating.
+
+ \section2 Context Properties
+
+ Contexts also allow data to be exposed to the QML components instantiated
+ by the QML engine. Such data is invisible to any tooling, including the
+ \l{Qt Quick Compiler} and to future readers of the QML documents in
+ question. It will only be exposed if the QML component is instantiated in
+ the specific C++ context you are envisioning. In other places, different
+ context data may be exposed instead.
+
+ Instead of using the QML context to expose data to your QML components, you
+ should either create additional object properties to hold the data or use
+ \l{QML_SINGLETON}{singletons}. See
+ \l{qtqml-cppintegration-exposecppstate.html}{Exposing C++ State to QML} for
+ a detailed explanation.
Each QQmlContext contains a set of properties, distinct from its QObject
properties, that allow data to be explicitly bound to a context by name. The
- context properties are defined and updated by calling
- QQmlContext::setContextProperty(). The following example shows a Qt model
- being bound to a context and then accessed from a QML file.
-
- \code
- QQmlEngine engine;
- QStringListModel modelData;
- QQmlContext *context = new QQmlContext(engine.rootContext());
- context->setContextProperty("myModel", &modelData);
-
- QQmlComponent component(&engine);
- component.setData("import QtQuick 2.0\nListView { model: myModel }", QUrl());
- QObject *window = component.create(context);
- \endcode
-
- Note it is the responsibility of the creator to delete any QQmlContext it
- constructs. If the \c context object in the example is no longer needed when the
- \c window component instance is destroyed, the \c context must be destroyed explicitly.
- The simplest way to ensure this is to set \c window as the parent of \c context.
+ context properties can be defined and updated by calling
+ QQmlContext::setContextProperty().
To simplify binding and maintaining larger data sets, a context object can be set
on a QQmlContext. All the properties of the context object are available
@@ -92,59 +69,17 @@ QT_BEGIN_NAMESPACE
detected through the property's notify signal. Setting a context object is both
faster and easier than manually adding and maintaining context property values.
- The following example has the same effect as the previous one, but it uses a context
- object.
-
- \code
- class MyDataSet : ... {
- ...
- Q_PROPERTY(QAbstractItemModel *myModel READ model NOTIFY modelChanged)
- ...
- };
-
- MyDataSet myDataSet;
- QQmlEngine engine;
- QQmlContext *context = new QQmlContext(engine.rootContext());
- context->setContextObject(&myDataSet);
-
- QQmlComponent component(&engine);
- component.setData("import QtQuick 2.0\nListView { model: myModel }", QUrl());
- component.create(context);
- \endcode
-
All properties added explicitly by QQmlContext::setContextProperty() take
precedence over the context object's properties.
- \section2 The Context Hierarchy
-
- Contexts form a hierarchy. The root of this hierarchy is the QML engine's
- \l {QQmlEngine::rootContext()}{root context}. Child contexts inherit
- the context properties of their parents; if a child context sets a context property
- that already exists in its parent, the new context property overrides that of the
- parent.
-
- The following example defines two contexts - \c context1 and \c context2. The
- second context overrides the "b" context property inherited from the first with a
- new value.
-
- \code
- QQmlEngine engine;
- QQmlContext *context1 = new QQmlContext(engine.rootContext());
- QQmlContext *context2 = new QQmlContext(context1);
-
- context1->setContextProperty("a", 12);
- context1->setContextProperty("b", 12);
-
- context2->setContextProperty("b", 15);
- \endcode
+ Child contexts inherit the context properties of their parents; if a child
+ context sets a context property that already exists in its parent, the new
+ context property overrides that of the parent.
- While QML objects instantiated in a context are not strictly owned by that
- context, their bindings are. If a context is destroyed, the property bindings of
- outstanding QML objects will stop evaluating.
-
- \warning Setting the context object or adding new context properties after an object
- has been created in that context is an expensive operation (essentially forcing all bindings
- to reevaluate). Thus whenever possible you should complete "setup" of the context
+ \warning Setting the context object or adding new context properties after
+ an object has been created in that context is an expensive operation
+ (essentially forcing all bindings to re-evaluate). Thus, if you need to use
+ context properties, you should at least complete the "setup" of the context
before using it to create any objects.
\sa {qtqml-cppintegration-exposecppattributes.html}{Exposing Attributes of C++ Types to QML}
@@ -152,7 +87,7 @@ QT_BEGIN_NAMESPACE
/*! \internal */
QQmlContext::QQmlContext(QQmlEngine *e, bool)
- : QObject(*(new QQmlContextPrivate(this, nullptr, e)))
+ : QObject(*(new QQmlContextPrivate(this, QQmlRefPointer<QQmlContextData>(), e)))
{
}
@@ -161,9 +96,9 @@ QQmlContext::QQmlContext(QQmlEngine *e, bool)
QObject \a parent.
*/
QQmlContext::QQmlContext(QQmlEngine *engine, QObject *parent)
- : QObject(*(new QQmlContextPrivate(
- this, engine ? QQmlContextData::get(engine->rootContext()).data() : nullptr)),
- parent)
+ : QObject(*(new QQmlContextPrivate(this, engine
+ ? QQmlContextData::get(engine->rootContext())
+ : QQmlRefPointer<QQmlContextData>())), parent)
{
}
@@ -172,9 +107,9 @@ QQmlContext::QQmlContext(QQmlEngine *engine, QObject *parent)
QObject \a parent.
*/
QQmlContext::QQmlContext(QQmlContext *parentContext, QObject *parent)
- : QObject(*(new QQmlContextPrivate(
- this, parentContext ? QQmlContextData::get(parentContext).data() : nullptr)),
- parent)
+ : QObject(*(new QQmlContextPrivate(this, parentContext
+ ? QQmlContextData::get(parentContext)
+ : QQmlRefPointer<QQmlContextData>())), parent)
{
}
@@ -212,7 +147,7 @@ bool QQmlContext::isValid() const
}
/*!
- Return the context's QQmlEngine, or 0 if the context has no QQmlEngine or the
+ Return the context's QQmlEngine, or \nullptr if the context has no QQmlEngine or the
QQmlEngine was destroyed.
*/
QQmlEngine *QQmlContext::engine() const
@@ -222,7 +157,7 @@ QQmlEngine *QQmlContext::engine() const
}
/*!
- Return the context's parent QQmlContext, or 0 if this context has no
+ Return the context's parent QQmlContext, or \nullptr if this context has no
parent or if the parent has been destroyed.
*/
QQmlContext *QQmlContext::parentContext() const
@@ -235,7 +170,7 @@ QQmlContext *QQmlContext::parentContext() const
}
/*!
- Return the context object, or 0 if there is no context object.
+ Return the context object, or \nullptr if there is no context object.
*/
QObject *QQmlContext::contextObject() const
{
@@ -245,6 +180,9 @@ QObject *QQmlContext::contextObject() const
/*!
Set the context \a object.
+
+ \note You should not use context objects to inject values into your QML
+ components. Use singletons or regular object properties instead.
*/
void QQmlContext::setContextObject(QObject *object)
{
@@ -268,6 +206,9 @@ void QQmlContext::setContextObject(QObject *object)
/*!
Set a the \a value of the \a name property on this context.
+
+ \note You should not use context properties to inject values into your QML
+ components. Use singletons or regular object properties instead.
*/
void QQmlContext::setContextProperty(const QString &name, const QVariant &value)
{
@@ -287,10 +228,14 @@ void QQmlContext::setContextProperty(const QString &name, const QVariant &value)
return;
}
- QV4::IdentifierHash *properties = data->detachedPropertyNames();
- int idx = properties->value(name);
+ if (bool isNumber = false; name.toUInt(&isNumber), isNumber) {
+ qWarning("QQmlContext: Using numbers as context properties will be disallowed in a future Qt version.");
+ QT7_ONLY(return;)
+ }
+
+ int idx = data->propertyIndex(name);
if (idx == -1) {
- properties->add(name, data->numIdValues() + d->numPropertyValues());
+ data->addPropertyNameAndIndex(name, data->numIdValues() + d->numPropertyValues());
d->appendPropertyValue(value);
data->refreshExpressions();
} else {
@@ -309,6 +254,9 @@ void QQmlContext::setContextProperty(const QString &name, const QVariant &value)
Set the \a value of the \a name property on this context.
QQmlContext does \b not take ownership of \a value.
+
+ \note You should not use context properties to inject values into your QML
+ components. Use singletons or regular object properties instead.
*/
void QQmlContext::setContextProperty(const QString &name, QObject *value)
{
@@ -324,6 +272,9 @@ void QQmlContext::setContextProperty(const QString &name, QObject *value)
refreshing expressions, and is therefore recommended
instead of calling \l setContextProperty() for each individual property.
+ \note You should not use context properties to inject values into your QML
+ components. Use singletons or regular object properties instead.
+
\sa QQmlContext::setContextProperty()
*/
void QQmlContext::setContextProperties(const QList<PropertyPair> &properties)
@@ -354,48 +305,68 @@ void QQmlContext::setContextProperties(const QList<PropertyPair> &properties)
\sa QQmlContext::setContextProperties()
*/
+static bool readObjectProperty(
+ const QQmlRefPointer<QQmlContextData> &data, QObject *object, const QString &name,
+ QVariant *target)
+{
+ QQmlPropertyData local;
+ if (const QQmlPropertyData *property = QQmlPropertyCache::property(object, name, data, &local)) {
+ *target = object->metaObject()->property(property->coreIndex()).read(object);
+ return true;
+ }
+ return false;
+}
+
/*!
- Returns the value of the \a name property for this context
- as a QVariant.
+ Returns the value of the \a name property for this context as a QVariant.
+ If you know that the property you're looking for is a QObject assigned using
+ a QML id in the current context, \l objectForName() is more convenient and
+ faster. In contrast to \l objectForName() and \l nameForObject(), this method
+ does traverse the context hierarchy and searches in parent contexts if the
+ \a name is not found in the current one. It also considers any
+ \l contextObject() you may have set.
+
+ \sa objectForName(), nameForObject(), contextObject()
*/
QVariant QQmlContext::contextProperty(const QString &name) const
{
Q_D(const QQmlContext);
- QVariant value;
- int idx = -1;
- QQmlRefPointer<QQmlContextData> data = d->m_data;
-
- const QV4::IdentifierHash properties = data->propertyNames();
- if (properties.count())
- idx = properties.value(name);
+ const QQmlRefPointer<QQmlContextData> data = d->m_data;
+ const int idx = data->propertyIndex(name);
if (idx == -1) {
if (QObject *obj = data->contextObject()) {
- QQmlPropertyData local;
- QQmlPropertyData *property =
- QQmlPropertyCache::property(data->engine(), obj, name, data, &local);
-
- if (property) value = obj->metaObject()->property(property->coreIndex()).read(obj);
+ QVariant value;
+ if (readObjectProperty(data, obj, name, &value))
+ return value;
}
- if (!value.isValid() && parentContext())
- value = parentContext()->contextProperty(name);
+
+ if (parentContext())
+ return parentContext()->contextProperty(name);
} else {
if (idx >= d->numPropertyValues())
- value = QVariant::fromValue(data->idValue(idx - d->numPropertyValues()));
+ return QVariant::fromValue(data->idValue(idx - d->numPropertyValues()));
else
- value = d->propertyValue(idx);
+ return d->propertyValue(idx);
}
- return value;
+ return QVariant();
}
/*!
-Returns the name of \a object in this context, or an empty string if \a object
-is not named in the context. Objects are named by setContextProperty(), or by ids in
-the case of QML created contexts.
+ Returns the name of \a object in this context, or an empty string if \a object
+ is not named in the context. Objects are named by \l setContextProperty(), or
+ as properties of a context object, or by ids in the case of QML created
+ contexts.
+
+ If the object has multiple names, the first is returned.
-If the object has multiple names, the first is returned.
+ In contrast to \l contextProperty(), this method does not traverse the
+ context hierarchy. If the name is not found in the current context, an empty
+ String is returned.
+
+ \sa contextProperty(), objectForName()
*/
QString QQmlContext::nameForObject(const QObject *object) const
{
@@ -405,6 +376,40 @@ QString QQmlContext::nameForObject(const QObject *object) const
}
/*!
+ \since 6.2
+
+ Returns the object for a given \a name in this context. Returns nullptr if
+ \a name is not available in the context or if the value associated with
+ \a name is not a QObject. Objects are named by \l setContextProperty(),
+ or as properties of a context object, or by ids in the case of QML created
+ contexts. In contrast to \l contextProperty(), this method does not traverse
+ the context hierarchy. If the name is not found in the current context,
+ nullptr is returned.
+
+ \sa contextProperty(), nameForObject()
+*/
+QObject *QQmlContext::objectForName(const QString &name) const
+{
+ Q_D(const QQmlContext);
+
+ QQmlRefPointer<QQmlContextData> data = d->m_data;
+ if (const int propertyIndex = data->propertyIndex(name); propertyIndex >= 0) {
+ const int numPropertyValues = d->numPropertyValues();
+ if (propertyIndex < numPropertyValues)
+ return qvariant_cast<QObject *>(d->propertyValue(propertyIndex));
+ return data->idValue(propertyIndex - numPropertyValues);
+ }
+
+ if (QObject *obj = data->contextObject()) {
+ QVariant result;
+ if (readObjectProperty(data, obj, name, &result))
+ return qvariant_cast<QObject *>(result);
+ }
+
+ return nullptr;
+}
+
+/*!
Resolves the URL \a src relative to the URL of the
containing component.
@@ -441,11 +446,14 @@ QUrl QQmlContext::baseUrl() const
return d->m_data->baseUrl();
}
+/*!
+ * \internal
+ */
QJSValue QQmlContext::importedScript(const QString &name) const
{
Q_D(const QQmlContext);
- QQmlTypeNameCache::Result r = d->m_data->imports()->query(name);
+ QQmlTypeNameCache::Result r = d->m_data->imports()->query(name, QQmlTypeLoader::get(engine()));
QV4::Scope scope(engine()->handle());
QV4::ScopedObject scripts(scope, d->m_data->importedScripts().valueRef());
return scripts ? QJSValuePrivate::fromReturnedValue(scripts->get(r.scriptIndex))
@@ -461,7 +469,7 @@ qsizetype QQmlContextPrivate::context_count(QQmlListProperty<QObject> *prop)
if (d->propertyValue(contextProperty).userType() != qMetaTypeId<QList<QObject*> >())
return 0;
else
- return ((const QList<QObject> *)d->propertyValue(contextProperty).constData())->count();
+ return ((const QList<QObject> *)d->propertyValue(contextProperty).constData())->size();
}
QObject *QQmlContextPrivate::context_at(QQmlListProperty<QObject> *prop, qsizetype index)
@@ -481,7 +489,7 @@ void QQmlContextPrivate::dropDestroyedQObject(const QString &name, QObject *dest
if (!m_data->isValid())
return;
- const int idx = m_data->propertyNames().value(name);
+ const int idx = m_data->propertyIndex(name);
Q_ASSERT(idx >= 0);
if (qvariant_cast<QObject *>(propertyValue(idx)) != destroyed)
return;
@@ -499,7 +507,8 @@ void QQmlContextPrivate::emitDestruction()
// deref'd. It's OK to pass a half-created publicContext here. We will not dereference it during
// construction.
QQmlContextPrivate::QQmlContextPrivate(
- QQmlContext *publicContext, QQmlContextData *parent, QQmlEngine *engine) :
+ QQmlContext *publicContext, const QQmlRefPointer<QQmlContextData> &parent,
+ QQmlEngine *engine) :
m_data(new QQmlContextData(QQmlContextData::OwnedByPublicContext, publicContext,
parent, engine))
{
diff --git a/src/qml/qml/qqmlcontext.h b/src/qml/qml/qqmlcontext.h
index 5eda300b36..b02aefe1d6 100644
--- a/src/qml/qml/qqmlcontext.h
+++ b/src/qml/qml/qqmlcontext.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLCONTEXT_H
#define QQMLCONTEXT_H
@@ -53,7 +17,6 @@ QT_BEGIN_NAMESPACE
class QString;
class QQmlEngine;
-class QQmlRefCount;
class QQmlContextPrivate;
class QQmlCompositeTypeData;
class QQmlContextData;
@@ -84,6 +47,7 @@ public:
void setContextProperties(const QList<PropertyPair> &properties);
QString nameForObject(const QObject *) const;
+ QObject *objectForName(const QString &) const;
QUrl resolvedUrl(const QUrl &) const;
@@ -107,6 +71,4 @@ private:
};
QT_END_NAMESPACE
-Q_DECLARE_METATYPE(QList<QObject*>)
-
#endif // QQMLCONTEXT_H
diff --git a/src/qml/qml/qqmlcontext_p.h b/src/qml/qml/qqmlcontext_p.h
index 1c2cb7ff67..aeaa1a3cd5 100644
--- a/src/qml/qml/qqmlcontext_p.h
+++ b/src/qml/qml/qqmlcontext_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLCONTEXT_P_H
#define QQMLCONTEXT_P_H
@@ -86,7 +50,11 @@ public:
int notifyIndex() const { return m_notifyIndex; }
void setNotifyIndex(int notifyIndex) { m_notifyIndex = notifyIndex; }
- int numPropertyValues() const { return m_propertyValues.count(); }
+ int numPropertyValues() const {
+ auto size = m_propertyValues.size();
+ Q_ASSERT(size <= std::numeric_limits<int>::max());
+ return int(size);
+ }
void appendPropertyValue(const QVariant &value) { m_propertyValues.append(value); }
void setPropertyValue(int index, const QVariant &value) { m_propertyValues[index] = value; }
QVariant propertyValue(int index) const { return m_propertyValues[index]; }
@@ -105,7 +73,7 @@ private:
friend class QQmlContextData;
QQmlContextPrivate(QQmlContextData *data) : m_data(data) {}
- QQmlContextPrivate(QQmlContext *publicContext, QQmlContextData *parent,
+ QQmlContextPrivate(QQmlContext *publicContext, const QQmlRefPointer<QQmlContextData> &parent,
QQmlEngine *engine = nullptr);
// Intentionally a bare pointer. QQmlContextData knows whether it owns QQmlContext or vice
diff --git a/src/qml/qml/qqmlcontextdata.cpp b/src/qml/qml/qqmlcontextdata.cpp
index e1aa3dd887..8667a1ce81 100644
--- a/src/qml/qml/qqmlcontextdata.cpp
+++ b/src/qml/qml/qqmlcontextdata.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2020 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$
-**
-****************************************************************************/
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qqmlcontextdata_p.h"
@@ -46,6 +10,29 @@
QT_BEGIN_NAMESPACE
+void QQmlContextData::installContext(QQmlData *ddata, QQmlContextData::QmlObjectKind kind)
+{
+ Q_ASSERT(ddata);
+ if (kind == QQmlContextData::DocumentRoot) {
+ if (ddata->context) {
+ Q_ASSERT(ddata->context != this);
+ Q_ASSERT(ddata->outerContext);
+ Q_ASSERT(ddata->outerContext != this);
+ QQmlRefPointer<QQmlContextData> c = ddata->context;
+ while (QQmlRefPointer<QQmlContextData> linked = c->linkedContext())
+ c = linked;
+ c->setLinkedContext(this);
+ } else {
+ ddata->context = this;
+ }
+ ddata->ownContext.reset(ddata->context);
+ } else if (!ddata->context) {
+ ddata->context = this;
+ }
+
+ addOwnedObject(ddata);
+}
+
QUrl QQmlContextData::resolvedUrl(const QUrl &src) const
{
QUrl resolved;
@@ -152,7 +139,7 @@ QQmlContextData::~QQmlContextData()
addref();
if (m_engine)
invalidate();
- m_linkedContext = nullptr;
+ m_linkedContext.reset();
Q_ASSERT(refCount() == 1);
clearContext();
@@ -172,8 +159,9 @@ QQmlContextData::~QQmlContextData()
QQmlGuardedContextData *contextGuard = m_contextGuards;
while (contextGuard) {
+ // TODO: Is this dead code? Why?
QQmlGuardedContextData *next = contextGuard->next();
- next->reset();
+ contextGuard->setContextData({});
contextGuard = next;
}
m_contextGuards = nullptr;
@@ -281,37 +269,35 @@ void QQmlContextData::setIdValue(int idx, QObject *obj)
QString QQmlContextData::findObjectId(const QObject *obj) const
{
- const QV4::IdentifierHash &properties = propertyNames();
- if (m_propertyNameCache.isEmpty())
- return QString();
-
for (int ii = 0; ii < m_idValueCount; ii++) {
if (m_idValues[ii] == obj)
- return properties.findId(ii);
+ return propertyName(ii);
}
+ const QVariant objVariant = QVariant::fromValue(obj);
if (m_publicContext) {
QQmlContextPrivate *p = QQmlContextPrivate::get(m_publicContext);
for (int ii = 0; ii < p->numPropertyValues(); ++ii)
- if (p->propertyValue(ii) == QVariant::fromValue(const_cast<QObject *>(obj)))
- return properties.findId(ii);
+ if (p->propertyValue(ii) == objVariant)
+ return propertyName(ii);
}
- if (m_linkedContext)
- return m_linkedContext->findObjectId(obj);
- return QString();
-}
-
-QQmlContext *QQmlContextData::asQQmlContext()
-{
- if (!m_publicContext)
- m_publicContext = new QQmlContext(*new QQmlContextPrivate(this));
- return m_publicContext;
-}
+ if (m_contextObject) {
+ // This is expensive, but nameForObject should really mirror contextProperty()
+ for (const QMetaObject *metaObject = m_contextObject->metaObject();
+ metaObject; metaObject = metaObject->superClass()) {
+ for (int i = metaObject->propertyOffset(), end = metaObject->propertyCount();
+ i != end; ++i) {
+ const QMetaProperty prop = metaObject->property(i);
+ if (prop.metaType().flags() & QMetaType::PointerToQObject
+ && prop.read(m_contextObject) == objVariant) {
+ return QString::fromUtf8(prop.name());
+ }
+ }
+ }
+ }
-QQmlContextPrivate *QQmlContextData::asQQmlContextPrivate()
-{
- return QQmlContextPrivate::get(asQQmlContext());
+ return QString();
}
void QQmlContextData::initFromTypeCompilationUnit(const QQmlRefPointer<QV4::ExecutableCompilationUnit> &unit, int subComponentIndex)
@@ -334,22 +320,13 @@ void QQmlContextData::addExpression(QQmlJavaScriptExpression *expression)
expression->insertIntoList(&m_expressions);
}
-QV4::IdentifierHash QQmlContextData::propertyNames() const
-{
- if (m_propertyNameCache.isEmpty()) {
- if (m_typeCompilationUnit)
- m_propertyNameCache = m_typeCompilationUnit->namedObjectsPerComponent(m_componentObjectIndex);
- else
- m_propertyNameCache = QV4::IdentifierHash(m_engine->handle());
- }
- return m_propertyNameCache;
-}
-
-QV4::IdentifierHash *QQmlContextData::detachedPropertyNames()
+void QQmlContextData::initPropertyNames() const
{
- propertyNames();
- m_propertyNameCache.detach();
- return &m_propertyNameCache;
+ if (m_typeCompilationUnit)
+ m_propertyNameCache = m_typeCompilationUnit->namedObjectsPerComponent(m_componentObjectIndex);
+ else
+ m_propertyNameCache = QV4::IdentifierHash(m_engine->handle());
+ Q_ASSERT(!m_propertyNameCache.isEmpty());
}
QUrl QQmlContextData::url() const
diff --git a/src/qml/qml/qqmlcontextdata_p.h b/src/qml/qml/qqmlcontextdata_p.h
index 0fc3c23a0e..c8e362ec8d 100644
--- a/src/qml/qml/qqmlcontextdata_p.h
+++ b/src/qml/qml/qqmlcontextdata_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2020 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$
-**
-****************************************************************************/
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLCONTEXTDATA_P_H
#define QQMLCONTEXTDATA_P_H
@@ -51,10 +15,11 @@
// We mean it.
//
-#include <QtQml/private/qqmlglobal_p.h>
+#include <QtQml/private/qtqmlglobal_p.h>
#include <QtQml/private/qqmlcontext_p.h>
#include <QtQml/private/qqmlguard_p.h>
#include <QtQml/private/qqmltypenamecache_p.h>
+#include <QtQml/private/qqmlnotifier_p.h>
#include <QtQml/private/qv4identifierhash_p.h>
#include <QtQml/private/qv4executablecompilationunit_p.h>
@@ -65,7 +30,7 @@ class QQmlGuardedContextData;
class QQmlJavaScriptExpression;
class QQmlIncubatorPrivate;
-class Q_QML_PRIVATE_EXPORT QQmlContextData
+class Q_QML_EXPORT QQmlContextData
{
public:
static QQmlRefPointer<QQmlContextData> createRefCounted(
@@ -138,16 +103,53 @@ public:
QQmlData *ownedObjects() const { return m_ownedObjects; }
void setOwnedObjects(QQmlData *ownedObjects) { m_ownedObjects = ownedObjects; }
+ enum QmlObjectKind {
+ OrdinaryObject,
+ DocumentRoot,
+ };
+ void installContext(QQmlData *ddata, QmlObjectKind kind);
+
QUrl resolvedUrl(const QUrl &) const;
// My containing QQmlContext. If isInternal is true this owns publicContext.
// If internal is false publicContext owns this.
- QQmlContext *asQQmlContext();
- QQmlContextPrivate *asQQmlContextPrivate();
+ QQmlContext *asQQmlContext()
+ {
+ if (!m_publicContext)
+ m_publicContext = new QQmlContext(*new QQmlContextPrivate(this));
+ return m_publicContext;
+ }
+
+ QQmlContextPrivate *asQQmlContextPrivate()
+ {
+ return QQmlContextPrivate::get(asQQmlContext());
+ }
QObject *contextObject() const { return m_contextObject; }
void setContextObject(QObject *contextObject) { m_contextObject = contextObject; }
+ template<typename HandleSelf, typename HandleLinked>
+ void deepClearContextObject(
+ QObject *contextObject, HandleSelf &&handleSelf, HandleLinked &&handleLinked) {
+ for (QQmlContextData *lc = m_linkedContext.data(); lc; lc = lc->m_linkedContext.data()) {
+ handleLinked(lc);
+ if (lc->m_contextObject == contextObject)
+ lc->m_contextObject = nullptr;
+ }
+
+ handleSelf(this);
+ if (m_contextObject == contextObject)
+ m_contextObject = nullptr;
+ }
+
+ void deepClearContextObject(QObject *contextObject)
+ {
+ deepClearContextObject(
+ contextObject,
+ [](QQmlContextData *self) { self->emitDestruction(); },
+ [](QQmlContextData *){});
+ }
+
QQmlEngine *engine() const { return m_engine; }
void setEngine(QQmlEngine *engine) { m_engine = engine; }
@@ -164,8 +166,29 @@ public:
}
}
- QV4::IdentifierHash propertyNames() const;
- QV4::IdentifierHash *detachedPropertyNames();
+ int propertyIndex(const QString &name) const
+ {
+ ensurePropertyNames();
+ return m_propertyNameCache.value(name);
+ }
+
+ int propertyIndex(QV4::String *name) const
+ {
+ ensurePropertyNames();
+ return m_propertyNameCache.value(name);
+ }
+
+ QString propertyName(int index) const
+ {
+ ensurePropertyNames();
+ return m_propertyNameCache.findId(index);
+ }
+
+ void addPropertyNameAndIndex(const QString &name, int index)
+ {
+ Q_ASSERT(!m_propertyNameCache.isEmpty());
+ m_propertyNameCache.add(name, index);
+ }
void setExpressions(QQmlJavaScriptExpression *expressions) { m_expressions = expressions; }
QQmlJavaScriptExpression *takeExpressions()
@@ -265,6 +288,10 @@ public:
void addExpression(QQmlJavaScriptExpression *expression);
+ bool valueTypesAreAddressable() const {
+ return m_typeCompilationUnit && m_typeCompilationUnit->valueTypesAreAddressable();
+ }
+
private:
friend class QQmlGuardedContextData;
friend class QQmlContextPrivate;
@@ -283,9 +310,8 @@ private:
ObjectWasSet
};
- inline ContextGuard() : m_context(nullptr) {}
+ inline ContextGuard() : QQmlGuard<QObject>(&ContextGuard::objectDestroyedImpl, nullptr), m_context(nullptr) {}
inline ContextGuard &operator=(QObject *obj);
- inline void objectDestroyed(QObject *) override;
inline bool wasSet() const;
@@ -296,6 +322,7 @@ private:
}
private:
+ inline static void objectDestroyedImpl(QQmlGuardImpl *);
// Not refcounted, as it always belongs to the QQmlContextData.
QTaggedPointer<QQmlContextData, Tag> m_context;
QQmlNotifier m_bindings;
@@ -334,6 +361,14 @@ private:
void refreshExpressionsRecursive(bool isGlobal);
void refreshExpressionsRecursive(QQmlJavaScriptExpression *);
+ void initPropertyNames() const;
+
+ void ensurePropertyNames() const
+ {
+ if (m_propertyNameCache.isEmpty())
+ initPropertyNames();
+ Q_ASSERT(!m_propertyNameCache.isEmpty());
+ }
// My parent context and engine
QQmlContextData *m_parent = nullptr;
@@ -349,7 +384,7 @@ private:
quint32 m_ownedByParent:1;
quint32 m_ownedByPublicContext:1;
quint32 m_hasExtraObject:1; // used in QQmlDelegateModelItem::dataForObject to find the corresponding QQmlDelegateModelItem of an object
- quint32 m_dummy:23;
+ Q_DECL_UNUSED_MEMBER quint32 m_dummy:23;
QQmlContext *m_publicContext = nullptr;
union {
@@ -414,11 +449,12 @@ QQmlContextData::ContextGuard &QQmlContextData::ContextGuard::operator=(QObject
return *this;
}
-void QQmlContextData::ContextGuard::objectDestroyed(QObject *)
+ void QQmlContextData::ContextGuard::objectDestroyedImpl(QQmlGuardImpl *impl)
{
- if (QObject *contextObject = m_context->contextObject()) {
+ auto This = static_cast<QQmlContextData::ContextGuard *>(impl);
+ if (QObject *contextObject = This->m_context->contextObject()) {
if (!QObjectPrivate::get(contextObject)->wasDeleted)
- m_bindings.notify();
+ This->m_bindings.notify();
}
}
diff --git a/src/qml/qml/qqmlcustomparser.cpp b/src/qml/qml/qqmlcustomparser.cpp
index b0df4f26dc..bd632d25a6 100644
--- a/src/qml/qml/qqmlcustomparser.cpp
+++ b/src/qml/qml/qqmlcustomparser.cpp
@@ -1,42 +1,7 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+#include "qml/qqmlpropertyvalidator_p.h"
#include "qqmlcustomparser_p.h"
#include <private/qv4compileddata_p.h>
@@ -102,8 +67,8 @@ void QQmlCustomParser::clearErrors()
void QQmlCustomParser::error(const QV4::CompiledData::Location &location, const QString &description)
{
QQmlError error;
- error.setLine(qmlConvertSourceCoordinate<quint32, int>(location.line));
- error.setColumn(qmlConvertSourceCoordinate<quint32, int>(location.column));
+ error.setLine(qmlConvertSourceCoordinate<quint32, int>(location.line()));
+ error.setColumn(qmlConvertSourceCoordinate<quint32, int>(location.column()));
error.setDescription(description);
exceptions << error;
@@ -117,7 +82,7 @@ void QQmlCustomParser::error(const QV4::CompiledData::Location &location, const
A valid \a ok must be provided, or the function will assert.
*/
-int QQmlCustomParser::evaluateEnum(const QByteArray& script, bool *ok) const
+int QQmlCustomParser::evaluateEnum(const QString &script, bool *ok) const
{
Q_ASSERT_X(ok, "QQmlCustomParser::evaluateEnum", "ok must not be a null pointer");
*ok = false;
@@ -127,40 +92,57 @@ int QQmlCustomParser::evaluateEnum(const QByteArray& script, bool *ok) const
// * <TypeName>.<ScopedEnumName>.<EnumValue>
auto nextDot = [&](int dot) {
- const int nextDot = script.indexOf('.', dot + 1);
- return (nextDot == script.length() - 1) ? -1 : nextDot;
+ const int nextDot = script.indexOf(u'.', dot + 1);
+ return (nextDot == script.size() - 1) ? -1 : nextDot;
};
int dot = nextDot(-1);
if (dot == -1)
return -1;
- QString scope = QString::fromUtf8(script.left(dot));
+ const QString scope = script.left(dot);
if (scope != QLatin1String("Qt")) {
- if (imports.isNull())
+ if (!engine || imports.isNull())
return -1;
QQmlType type;
+ QQmlTypeLoader *typeLoader = QQmlTypeLoader::get(engine);
+ Q_ASSERT(typeLoader);
+
if (imports.isT1()) {
QQmlImportNamespace *ns = nullptr;
- if (!imports.asT1()->resolveType(scope, &type, nullptr, &ns))
+
+ // Pass &recursionDetected to resolveType because that implicitly allows recursion.
+ // This way we can find the QQmlType of the document we're currently validating.
+ bool recursionDetected = false;
+
+ if (!imports.asT1()->resolveType(
+ typeLoader, scope, &type, nullptr, &ns, nullptr,
+ QQmlType::AnyRegistrationType, &recursionDetected)) {
return -1;
+ }
+
if (!type.isValid() && ns != nullptr) {
dot = nextDot(dot);
- if (dot == -1 || !imports.asT1()->resolveType(QString::fromUtf8(script.left(dot)),
- &type, nullptr, nullptr)) {
+ if (dot == -1 || !imports.asT1()->resolveType(
+ typeLoader, script.left(dot), &type, nullptr, nullptr, nullptr,
+ QQmlType::AnyRegistrationType, &recursionDetected)) {
return -1;
}
}
} else {
- QQmlTypeNameCache::Result result = imports.asT2()->query(scope);
+ // Allow recursion so that we can find enums from the same document.
+ const QQmlTypeNameCache::Result result
+ = imports.asT2()->query<QQmlImport::AllowRecursion>(scope, typeLoader);
if (result.isValid()) {
type = result.type;
} else if (result.importNamespace) {
dot = nextDot(dot);
- if (dot != -1)
- type = imports.asT2()->query(QString::fromUtf8(script.left(dot))).type;
+ if (dot != -1) {
+ type = imports.asT2()->query<QQmlImport::AllowRecursion>(
+ script.left(dot), typeLoader).type;
+ }
}
}
@@ -169,19 +151,44 @@ int QQmlCustomParser::evaluateEnum(const QByteArray& script, bool *ok) const
const int dot2 = nextDot(dot);
const bool dot2Valid = (dot2 != -1);
- QByteArray enumValue = script.mid(dot2Valid ? dot2 + 1 : dot + 1);
- QByteArray scopedEnumName = (dot2Valid ? script.mid(dot + 1, dot2 - dot - 1) : QByteArray());
+ const QString enumValue = script.mid(dot2Valid ? dot2 + 1 : dot + 1);
+ const QString scopedEnumName = dot2Valid ? script.mid(dot + 1, dot2 - dot - 1) : QString();
+
+ // If we're currently validating the same document, we won't be able to find its enums using
+ // the QQmlType. However, we do have the property cache already, and that one contains the
+ // enums.
+ const QUrl documentUrl = validator ? validator->documentSourceUrl() : QUrl();
+ if (documentUrl.isValid() && documentUrl == type.sourceUrl()) {
+ Q_ASSERT(validator);
+ const QQmlPropertyCache::ConstPtr rootCache = validator->rootPropertyCache();
+ const int count = rootCache->qmlEnumCount();
+ for (int ii = 0; ii < count; ++ii) {
+ const QQmlEnumData *enumData = rootCache->qmlEnum(ii);
+ if (!scopedEnumName.isEmpty() && scopedEnumName != enumData->name)
+ continue;
+
+ for (int jj = 0; jj < enumData->values.size(); ++jj) {
+ const QQmlEnumValue value = enumData->values.at(jj);
+ if (value.namedValue == enumValue) {
+ *ok = true;
+ return value.value;
+ }
+ }
+ }
+ return -1;
+ }
+
if (!scopedEnumName.isEmpty())
return type.scopedEnumValue(engine, scopedEnumName, enumValue, ok);
else
- return type.enumValue(engine, QHashedCStringRef(enumValue.constData(), enumValue.length()), ok);
+ return type.enumValue(engine, enumValue, ok);
}
- QByteArray enumValue = script.mid(dot + 1);
+ const QString enumValue = script.mid(dot + 1);
const QMetaObject *mo = &Qt::staticMetaObject;
int i = mo->enumeratorCount();
while (i--) {
- int v = mo->enumerator(i).keyToValue(enumValue.constData(), ok);
+ int v = mo->enumerator(i).keyToValue(enumValue.toUtf8().constData(), ok);
if (*ok)
return v;
}
@@ -194,10 +201,10 @@ int QQmlCustomParser::evaluateEnum(const QByteArray& script, bool *ok) const
*/
const QMetaObject *QQmlCustomParser::resolveType(const QString& name) const
{
- if (!imports.isT1())
+ if (!engine || !imports.isT1())
return nullptr;
QQmlType qmltype;
- if (!imports.asT1()->resolveType(name, &qmltype, nullptr, nullptr, nullptr))
+ if (!imports.asT1()->resolveType(QQmlTypeLoader::get(engine), name, &qmltype, nullptr, nullptr))
return nullptr;
return qmltype.metaObject();
}
diff --git a/src/qml/qml/qqmlcustomparser_p.h b/src/qml/qml/qqmlcustomparser_p.h
index 4eb709228e..4a3628fdb1 100644
--- a/src/qml/qml/qqmlcustomparser_p.h
+++ b/src/qml/qml/qqmlcustomparser_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLCUSTOMPARSER_H
#define QQMLCUSTOMPARSER_H
@@ -51,19 +15,18 @@
// We mean it.
//
-#include "qqmlerror.h"
-#include "qqmlbinding_p.h"
+#include <QtQml/qqmlerror.h>
+#include <QtQml/private/qqmlbinding_p.h>
#include <private/qv4compileddata_p.h>
#include <QtCore/qbytearray.h>
-#include <QtCore/qxmlstream.h>
QT_BEGIN_NAMESPACE
class QQmlPropertyValidator;
class QQmlEnginePrivate;
-class Q_QML_PRIVATE_EXPORT QQmlCustomParser
+class Q_QML_EXPORT QQmlCustomParser
{
public:
enum Flag {
@@ -92,7 +55,7 @@ protected:
{ error(object->location, description); }
void error(const QV4::CompiledData::Location &location, const QString& description);
- int evaluateEnum(const QByteArray&, bool *ok) const;
+ int evaluateEnum(const QString &, bool *ok) const;
const QMetaObject *resolveType(const QString&) const;
diff --git a/src/qml/qml/qqmldata_p.h b/src/qml/qml/qqmldata_p.h
index ed77c1851b..7055ca94e6 100644
--- a/src/qml/qml/qqmldata_p.h
+++ b/src/qml/qml/qqmldata_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLDATA_P_H
#define QQMLDATA_P_H
@@ -57,6 +21,7 @@
#include <private/qv4value_p.h>
#include <private/qv4persistent_p.h>
#include <private/qqmlrefcount_p.h>
+#include <private/qqmlpropertycache_p.h>
#include <qqmlprivate.h>
#include <qjsengine.h>
#include <qvector.h>
@@ -87,10 +52,12 @@ struct Binding;
// default state for elemental object allocations. This is crucial in the
// workings of the QQmlInstruction::CreateSimpleObject instruction.
// Don't change anything here without first considering that case!
-class Q_QML_PRIVATE_EXPORT QQmlData : public QAbstractDeclarativeData
+class Q_QML_EXPORT QQmlData : public QAbstractDeclarativeData
{
public:
- QQmlData();
+ enum Ownership { DoesNotOwnMemory, OwnsMemory };
+
+ QQmlData(Ownership ownership);
~QQmlData();
static inline void init() {
@@ -98,7 +65,6 @@ public:
if (!initialized) {
initialized = true;
QAbstractDeclarativeData::destroyed = destroyed;
- QAbstractDeclarativeData::parentChanged = nullptr;
QAbstractDeclarativeData::signalEmitted = signalEmitted;
QAbstractDeclarativeData::receivers = receivers;
QAbstractDeclarativeData::isSignalConnected = isSignalConnected;
@@ -133,13 +99,15 @@ public:
quint32 isQueuedForDeletion:1;
/*
* rootObjectInCreation should be true only when creating top level CPP and QML objects,
- * v8 GC will check this flag, only deletes the objects when rootObjectInCreation is false.
+ * v4 GC will check this flag, only deletes the objects when rootObjectInCreation is false.
*/
quint32 rootObjectInCreation:1;
// set when at least one of the object's properties is intercepted
quint32 hasInterceptorMetaObject:1;
quint32 hasVMEMetaObject:1;
- quint32 dummy:8;
+ // If we have another wrapper for a const QObject * in the multiply wrapped QObjects.
+ quint32 hasConstWrapper: 1;
+ quint32 dummy:7;
// When bindingBitsSize < sizeof(ptr), we store the binding bit flags inside
// bindingBitsValue. When we need more than sizeof(ptr) bits, we allocated
@@ -156,24 +124,24 @@ public:
};
struct NotifyList {
- quint64 connectionMask;
-
- quint16 maximumTodoIndex;
- quint16 notifiesSize;
-
- QQmlNotifierEndpoint *todo;
- QQmlNotifierEndpoint**notifies;
+ QAtomicInteger<quint64> connectionMask;
+ QQmlNotifierEndpoint *todo = nullptr;
+ QQmlNotifierEndpoint**notifies = nullptr;
+ quint16 maximumTodoIndex = 0;
+ quint16 notifiesSize = 0;
void layout();
private:
void layout(QQmlNotifierEndpoint*);
};
- NotifyList *notifyList;
+ QAtomicPointer<NotifyList> notifyList;
- inline QQmlNotifierEndpoint *notify(int index);
+ inline QQmlNotifierEndpoint *notify(int index) const;
void addNotify(int index, QQmlNotifierEndpoint *);
int endpointCount(int index);
bool signalHasEndpoint(int index) const;
- void disconnectNotifiers();
+
+ enum class DeleteNotifyList { Yes, No };
+ void disconnectNotifiers(DeleteNotifyList doDelete);
// The context that created the C++ object; not refcounted to prevent cycles
QQmlContextData *context = nullptr;
@@ -181,13 +149,13 @@ public:
QQmlContextData *outerContext = nullptr;
QQmlRefPointer<QQmlContextData> ownContext;
- QQmlAbstractBinding *bindings;
- QQmlBoundSignal *signalHandlers;
+ QQmlAbstractBinding *bindings = nullptr;
+ QQmlBoundSignal *signalHandlers = nullptr;
std::vector<QQmlPropertyObserver> propertyObservers;
// Linked list for QQmlContext::contextObjects
- QQmlData *nextContextObject;
- QQmlData**prevContextObject;
+ QQmlData *nextContextObject = nullptr;
+ QQmlData**prevContextObject = nullptr;
inline bool hasBindingBit(int) const;
inline void setBindingBit(QObject *obj, int);
@@ -197,10 +165,10 @@ public:
inline void setPendingBindingBit(QObject *obj, int);
inline void clearPendingBindingBit(int);
- quint16 lineNumber;
- quint16 columnNumber;
+ quint16 lineNumber = 0;
+ quint16 columnNumber = 0;
- quint32 jsEngineId; // id of the engine that created the jsWrapper
+ quint32 jsEngineId = 0; // id of the engine that created the jsWrapper
struct DeferredData {
DeferredData();
@@ -224,12 +192,11 @@ public:
QV4::WeakValue jsWrapper;
- QQmlPropertyCache *propertyCache;
+ QQmlPropertyCache::ConstPtr propertyCache;
- QQmlGuardImpl *guards;
+ QQmlGuardImpl *guards = nullptr;
- static QQmlData *get(const QObject *object, bool create = false) {
- QObjectPrivate *priv = QObjectPrivate::get(const_cast<QObject *>(object));
+ static QQmlData *get(QObjectPrivate *priv, bool create) {
// If QObjectData::isDeletingChildren is set then access to QObjectPrivate::declarativeData has
// to be avoided because QObjectPrivate::currentChildBeingDeleted is in use.
if (priv->isDeletingChildren || priv->wasDeleted) {
@@ -244,6 +211,25 @@ public:
}
}
+ static QQmlData *get(const QObjectPrivate *priv) {
+ // If QObjectData::isDeletingChildren is set then access to QObjectPrivate::declarativeData has
+ // to be avoided because QObjectPrivate::currentChildBeingDeleted is in use.
+ if (priv->isDeletingChildren || priv->wasDeleted)
+ return nullptr;
+ if (priv->declarativeData)
+ return static_cast<QQmlData *>(priv->declarativeData);
+ return nullptr;
+ }
+
+ static QQmlData *get(QObject *object, bool create) {
+ return QQmlData::get(QObjectPrivate::get(object), create);
+ }
+
+ static QQmlData *get(const QObject *object) {
+ return QQmlData::get(QObjectPrivate::get(object));
+
+ }
+
static bool keepAliveDuringGarbageCollection(const QObject *object) {
QQmlData *ddata = get(object);
if (!ddata || ddata->indestructible || ddata->rootObjectInCreation)
@@ -255,19 +241,20 @@ public:
QHash<QQmlAttachedPropertiesFunc, QObject *> *attachedProperties() const;
static inline bool wasDeleted(const QObject *);
+ static inline bool wasDeleted(const QObjectPrivate *);
static void markAsDeleted(QObject *);
static void setQueuedForDeletion(QObject *);
- static inline void flushPendingBinding(QObject *, QQmlPropertyIndex propertyIndex);
+ static inline void flushPendingBinding(QObject *object, int coreIndex);
+ void flushPendingBinding(int coreIndex);
- static QQmlPropertyCache *ensurePropertyCache(QJSEngine *engine, QObject *object)
+ static QQmlPropertyCache::ConstPtr ensurePropertyCache(QObject *object)
{
- Q_ASSERT(engine);
QQmlData *ddata = QQmlData::get(object, /*create*/true);
if (Q_LIKELY(ddata->propertyCache))
return ddata->propertyCache;
- return createPropertyCache(engine, object);
+ return createPropertyCache(object);
}
Q_ALWAYS_INLINE static uint offsetForBit(int bit) { return static_cast<uint>(bit) / BitsPerType; }
@@ -275,12 +262,10 @@ public:
private:
// For attachedProperties
- mutable QQmlDataExtended *extendedData;
+ mutable QQmlDataExtended *extendedData = nullptr;
Q_NEVER_INLINE static QQmlData *createQQmlData(QObjectPrivate *priv);
- Q_NEVER_INLINE static QQmlPropertyCache *createPropertyCache(QJSEngine *engine, QObject *object);
-
- void flushPendingBindingImpl(QQmlPropertyIndex index);
+ Q_NEVER_INLINE static QQmlPropertyCache::ConstPtr createPropertyCache(QObject *object);
Q_ALWAYS_INLINE bool hasBitSet(int bit) const
{
@@ -312,39 +297,52 @@ private:
Q_NEVER_INLINE BindingBitsType *growBits(QObject *obj, int bit);
- Q_DISABLE_COPY(QQmlData);
+ Q_DISABLE_COPY_MOVE(QQmlData);
};
+bool QQmlData::wasDeleted(const QObjectPrivate *priv)
+{
+ if (!priv || priv->wasDeleted || priv->isDeletingChildren)
+ return true;
+
+ const QQmlData *ddata = QQmlData::get(priv);
+ return ddata && ddata->isQueuedForDeletion;
+}
+
bool QQmlData::wasDeleted(const QObject *object)
{
if (!object)
return true;
const QObjectPrivate *priv = QObjectPrivate::get(object);
- if (!priv || priv->wasDeleted || priv->isDeletingChildren)
- return true;
+ return QQmlData::wasDeleted(priv);
+}
- const QQmlData *ddata = QQmlData::get(object);
- return ddata && ddata->isQueuedForDeletion;
+inline bool isIndexInConnectionMask(quint64 connectionMask, int index)
+{
+ return connectionMask & (1ULL << quint64(index % 64));
}
-QQmlNotifierEndpoint *QQmlData::notify(int index)
+QQmlNotifierEndpoint *QQmlData::notify(int index) const
{
+ // Can only happen on "home" thread. We apply relaxed semantics when loading the atomics.
+
Q_ASSERT(index <= 0xFFFF);
- if (!notifyList || !(notifyList->connectionMask & (1ULL << quint64(index % 64)))) {
+ NotifyList *list = notifyList.loadRelaxed();
+ if (!list || !isIndexInConnectionMask(list->connectionMask.loadRelaxed(), index))
return nullptr;
- } else if (index < notifyList->notifiesSize) {
- return notifyList->notifies[index];
- } else if (index <= notifyList->maximumTodoIndex) {
- notifyList->layout();
- }
- if (index < notifyList->notifiesSize) {
- return notifyList->notifies[index];
- } else {
- return nullptr;
+ if (index < list->notifiesSize)
+ return list->notifies[index];
+
+ if (index <= list->maximumTodoIndex) {
+ list->layout();
+ if (index < list->notifiesSize)
+ return list->notifies[index];
}
+
+ return nullptr;
}
/*
@@ -353,7 +351,19 @@ QQmlNotifierEndpoint *QQmlData::notify(int index)
*/
inline bool QQmlData::signalHasEndpoint(int index) const
{
- return notifyList && (notifyList->connectionMask & (1ULL << quint64(index % 64)));
+ // This can be called from any thread.
+ // We still use relaxed semantics. If we're on a thread different from the "home" thread
+ // of the QQmlData, two interesting things might happen:
+ //
+ // 1. The list might go away while we hold it. In that case we are dealing with an object whose
+ // QObject dtor is being executed concurrently. This is UB already without the notify lists.
+ // Therefore, we don't need to consider it.
+ // 2. The connectionMask may be amended or zeroed while we are looking at it. In that case
+ // we "misreport" the endpoint. Since ordering of events across threads is inherently
+ // nondeterministic, either result is correct in that case. We can accept it.
+
+ NotifyList *list = notifyList.loadRelaxed();
+ return list && isIndexInConnectionMask(list->connectionMask.loadRelaxed(), index);
}
bool QQmlData::hasBindingBit(int coreIndex) const
@@ -400,11 +410,11 @@ void QQmlData::clearPendingBindingBit(int coreIndex)
clearBit(coreIndex * 2 + 1);
}
-void QQmlData::flushPendingBinding(QObject *o, QQmlPropertyIndex propertyIndex)
+void QQmlData::flushPendingBinding(QObject *object, int coreIndex)
{
- QQmlData *data = QQmlData::get(o, false);
- if (data && data->hasPendingBindingBit(propertyIndex.coreIndex()))
- data->flushPendingBindingImpl(propertyIndex);
+ QQmlData *data = QQmlData::get(object, false);
+ if (data && data->hasPendingBindingBit(coreIndex))
+ data->flushPendingBinding(coreIndex);
}
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmldatablob.cpp b/src/qml/qml/qqmldatablob.cpp
index f0dc0d77d3..6b354c337f 100644
--- a/src/qml/qml/qqmldatablob.cpp
+++ b/src/qml/qml/qqmldatablob.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 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$
-**
-****************************************************************************/
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <private/qqmldatablob_p.h>
#include <private/qqmlglobal_p.h>
@@ -56,6 +20,8 @@
DEFINE_BOOL_CONFIG_OPTION(dumpErrors, QML_DUMP_ERRORS);
+Q_DECLARE_LOGGING_CATEGORY(lcCycle)
+
QT_BEGIN_NAMESPACE
/*!
@@ -73,16 +39,14 @@ The QQmlTypeLoader invokes callbacks on the QQmlDataBlob as data becomes availab
This enum describes the status of the data blob.
-\list
-\li Null The blob has not yet been loaded by a QQmlTypeLoader
-\li Loading The blob is loading network data. The QQmlDataBlob::setData() callback has not yet been
- invoked or has not yet returned.
-\li WaitingForDependencies The blob is waiting for dependencies to be done before continuing.
- This status only occurs after the QQmlDataBlob::setData() callback has been made, and when the
- blob has outstanding dependencies.
-\li Complete The blob's data has been loaded and all dependencies are done.
-\li Error An error has been set on this blob.
-\endlist
+\value Null The blob has not yet been loaded by a QQmlTypeLoader
+\value Loading The blob is loading network data. The QQmlDataBlob::setData() callback has
+ not yet been invoked or has not yet returned.
+\value WaitingForDependencies The blob is waiting for dependencies to be done before continuing.
+ This status only occurs after the QQmlDataBlob::setData() callback has been made,
+ and when the blob has outstanding dependencies.
+\value Complete The blob's data has been loaded and all dependencies are done.
+\value Error An error has been set on this blob.
*/
/*!
@@ -90,11 +54,9 @@ This enum describes the status of the data blob.
This enum describes the type of the data blob.
-\list
-\li QmlFile This is a QQmlTypeData
-\li JavaScriptFile This is a QQmlScriptData
-\li QmldirFile This is a QQmlQmldirData
-\endlist
+\value QmlFile This is a QQmlTypeData
+\value JavaScriptFile This is a QQmlScriptData
+\value QmldirFile This is a QQmlQmldirData
*/
/*!
@@ -290,7 +252,7 @@ void QQmlDataBlob::setError(const QList<QQmlError> &errors)
Q_ASSERT(m_errors.isEmpty());
// m_errors must be set before the m_data fence
- m_errors.reserve(errors.count());
+ m_errors.reserve(errors.size());
for (const QQmlError &error : errors) {
if (error.url().isEmpty()) {
QQmlError mutableError = error;
@@ -305,7 +267,7 @@ void QQmlDataBlob::setError(const QList<QQmlError> &errors)
if (dumpErrors()) {
qWarning().nospace() << "Errors for " << urlString();
- for (int ii = 0; ii < errors.count(); ++ii)
+ for (int ii = 0; ii < errors.size(); ++ii)
qWarning().nospace() << " " << qPrintable(errors.at(ii).toString());
}
cancelAllWaitingFor();
@@ -349,7 +311,7 @@ void QQmlDataBlob::addDependency(QQmlDataBlob *blob)
status() == Error || status() == Complete || m_isDone)
return;
- for (const auto &existingDep: qAsConst(m_waitingFor))
+ for (const auto &existingDep: std::as_const(m_waitingFor))
if (existingDep.data() == blob)
return;
@@ -360,7 +322,8 @@ void QQmlDataBlob::addDependency(QQmlDataBlob *blob)
// Check circular dependency
if (m_waitingOnMe.indexOf(blob) >= 0) {
- qWarning() << "Cyclic dependency detected between" << this->url().toString() << "and" << blob->url().toString();
+ qCWarning(lcCycle) << "Cyclic dependency detected between" << this->url().toString()
+ << "and" << blob->url().toString();
m_data.setStatus(Error);
}
}
@@ -539,7 +502,7 @@ void QQmlDataBlob::tryDone()
void QQmlDataBlob::cancelAllWaitingFor()
{
- while (m_waitingFor.count()) {
+ while (m_waitingFor.size()) {
QQmlRefPointer<QQmlDataBlob> blob = m_waitingFor.takeLast();
Q_ASSERT(blob->m_waitingOnMe.contains(this));
@@ -550,7 +513,7 @@ void QQmlDataBlob::cancelAllWaitingFor()
void QQmlDataBlob::notifyAllWaitingOnMe()
{
- while (m_waitingOnMe.count()) {
+ while (m_waitingOnMe.size()) {
QQmlDataBlob *blob = m_waitingOnMe.takeLast();
Q_ASSERT(std::any_of(blob->m_waitingFor.constBegin(), blob->m_waitingFor.constEnd(),
@@ -569,7 +532,7 @@ void QQmlDataBlob::notifyComplete(QQmlDataBlob *blob)
m_inCallback = true;
QQmlRefPointer<QQmlDataBlob> blobRef;
- for (int i = 0; i < m_waitingFor.count(); ++i) {
+ for (int i = 0; i < m_waitingFor.size(); ++i) {
if (m_waitingFor.at(i).data() == blob) {
blobRef = m_waitingFor.takeAt(i);
break;
@@ -612,7 +575,7 @@ QString QQmlDataBlob::SourceCodeData::readAll(QString *error) const
}
QByteArray data(fileSize, Qt::Uninitialized);
- if (f.read(data.data(), data.length()) != data.length()) {
+ if (f.read(data.data(), data.size()) != data.size()) {
*error = f.errorString();
return QString();
}
diff --git a/src/qml/qml/qqmldatablob_p.h b/src/qml/qml/qqmldatablob_p.h
index 87e31a38f9..87a7e8e2e8 100644
--- a/src/qml/qml/qqmldatablob_p.h
+++ b/src/qml/qml/qqmldatablob_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 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$
-**
-****************************************************************************/
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLDATABLOB_P_H
#define QQMLDATABLOB_P_H
@@ -53,7 +17,6 @@
#include <private/qqmlrefcount_p.h>
#include <private/qqmljsdiagnosticmessage_p.h>
-#include <private/qv4compileddata_p.h>
#if QT_CONFIG(qml_network)
#include <QtNetwork/qnetworkreply.h>
@@ -71,9 +34,11 @@
QT_BEGIN_NAMESPACE
class QQmlTypeLoader;
-class Q_QML_PRIVATE_EXPORT QQmlDataBlob : public QQmlRefCount
+class Q_QML_EXPORT QQmlDataBlob : public QQmlRefCounted<QQmlDataBlob>
{
public:
+ using Ptr = QQmlRefPointer<QQmlDataBlob>;
+
enum Status {
Null, // Prior to QQmlTypeLoader::load()
Loading, // Prior to data being received and dataReceived() being called
@@ -90,7 +55,7 @@ public:
};
QQmlDataBlob(const QUrl &, Type, QQmlTypeLoader* manager);
- ~QQmlDataBlob() override;
+ virtual ~QQmlDataBlob();
void startLoading();
@@ -121,6 +86,11 @@ public:
QDateTime sourceTimeStamp() const;
bool exists() const;
bool isEmpty() const;
+ bool isValid() const
+ {
+ return hasInlineSourceCode || !fileInfo.filePath().isEmpty();
+ }
+
private:
friend class QQmlDataBlob;
friend class QQmlTypeLoader;
@@ -210,13 +180,14 @@ private:
}
}
- inline quint8 progress() const
+ inline qreal progress() const
{
- return quint8((_p.loadRelaxed() & ProgressMask) >> ProgressShift);
+ return quint8((_p.loadRelaxed() & ProgressMask) >> ProgressShift) / float(0xFF);
}
- inline void setProgress(quint8 v)
+ inline void setProgress(qreal progress)
{
+ quint8 v = 0xFF * progress;
while (true) {
int d = _p.loadRelaxed();
int nd = (d & ~ProgressMask) | ((v << ProgressShift) & ProgressMask);
diff --git a/src/qml/qml/qqmldelayedcallqueue.cpp b/src/qml/qml/qqmldelayedcallqueue.cpp
index 141c55c0ec..efd8519a58 100644
--- a/src/qml/qml/qqmldelayedcallqueue.cpp
+++ b/src/qml/qml/qqmldelayedcallqueue.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qqmldelayedcallqueue_p.h"
#include <private/qqmlengine_p.h>
@@ -67,16 +31,16 @@ void QQmlDelayedCallQueue::DelayedFunctionCall::execute(QV4::ExecutionEngine *en
const QV4::FunctionObject *callback = m_function.as<QV4::FunctionObject>();
Q_ASSERT(callback);
const int argCount = array ? array->getLength() : 0;
- QV4::JSCallData jsCallData(scope, argCount);
- *jsCallData->thisObject = QV4::Encode::undefined();
+ QV4::JSCallArguments jsCallData(scope, argCount);
+ *jsCallData.thisObject = QV4::Encode::undefined();
for (int i = 0; i < argCount; i++) {
- jsCallData->args[i] = array->get(i);
+ jsCallData.args[i] = array->get(i);
}
callback->call(jsCallData);
- if (scope.engine->hasException) {
+ if (scope.hasException()) {
QQmlError error = scope.engine->catchExceptionAsQmlError();
error.setDescription(error.description() + QLatin1String(" (exception occurred during delayed function evaluation)"));
QQmlEnginePrivate::warning(QQmlEnginePrivate::get(scope.engine->qmlEngine()), error);
@@ -106,22 +70,22 @@ void QQmlDelayedCallQueue::init(QV4::ExecutionEngine* engine)
m_tickedMethod = metaObject.method(methodIndex);
}
-QV4::ReturnedValue QQmlDelayedCallQueue::addUniquelyAndExecuteLater(const QV4::FunctionObject *b, const QV4::Value *, const QV4::Value *argv, int argc)
+QV4::ReturnedValue QQmlDelayedCallQueue::addUniquelyAndExecuteLater(QV4::ExecutionEngine *engine, QQmlV4FunctionPtr args)
{
- QV4::ExecutionEngine *engine = b->engine();
QQmlDelayedCallQueue *self = engine->delayedCallQueue();
- QV4::Scope scope(b);
- if (argc == 0)
+ QV4::Scope scope(engine);
+ if (args->length() == 0)
THROW_GENERIC_ERROR("Qt.callLater: no arguments given");
- const QV4::FunctionObject *func = argv[0].as<QV4::FunctionObject>();
+ QV4::ScopedValue firstArgument(scope, (*args)[0]);
+
+ const QV4::FunctionObject *func = firstArgument->as<QV4::FunctionObject>();
if (!func)
THROW_GENERIC_ERROR("Qt.callLater: first argument not a function or signal");
QPair<QObject *, int> functionData = QV4::QObjectMethod::extractQtMethod(func);
- QV4::ReturnedValue arg0 = argc ? argv[0].asReturnedValue() : QV4::Encode::undefined();
QVector<DelayedFunctionCall>::Iterator iter;
if (functionData.second != -1) {
@@ -140,7 +104,7 @@ QV4::ReturnedValue QQmlDelayedCallQueue::addUniquelyAndExecuteLater(const QV4::F
iter = self->m_delayedFunctionCalls.begin();
while (iter != self->m_delayedFunctionCalls.end()) {
DelayedFunctionCall& dfc = *iter;
- if (arg0 == dfc.m_function.value()) {
+ if (firstArgument->asReturnedValue() == dfc.m_function.value()) {
break; // Already stored!
}
++iter;
@@ -153,7 +117,7 @@ QV4::ReturnedValue QQmlDelayedCallQueue::addUniquelyAndExecuteLater(const QV4::F
self->m_delayedFunctionCalls.erase(iter);
self->m_delayedFunctionCalls.append(dfc);
} else {
- self->m_delayedFunctionCalls.append(QV4::PersistentValue(engine, arg0));
+ self->m_delayedFunctionCalls.append(QV4::PersistentValue(engine, firstArgument));
}
DelayedFunctionCall& dfc = self->m_delayedFunctionCalls.last();
@@ -169,7 +133,7 @@ QV4::ReturnedValue QQmlDelayedCallQueue::addUniquelyAndExecuteLater(const QV4::F
dfc.m_guarded = true;
}
}
- self->storeAnyArguments(dfc, argv, argc, 1, engine);
+ self->storeAnyArguments(dfc, args, 1, engine);
if (!self->m_callbackOutstanding) {
self->m_tickedMethod.invoke(self, Qt::QueuedConnection);
@@ -178,9 +142,9 @@ QV4::ReturnedValue QQmlDelayedCallQueue::addUniquelyAndExecuteLater(const QV4::F
return QV4::Encode::undefined();
}
-void QQmlDelayedCallQueue::storeAnyArguments(DelayedFunctionCall &dfc, const QV4::Value *argv, int argc, int offset, QV4::ExecutionEngine *engine)
+void QQmlDelayedCallQueue::storeAnyArguments(DelayedFunctionCall &dfc, QQmlV4FunctionPtr args, int offset, QV4::ExecutionEngine *engine)
{
- const int length = argc - offset;
+ const int length = args->length() - offset;
if (length == 0) {
dfc.m_args.clear();
return;
@@ -188,8 +152,8 @@ void QQmlDelayedCallQueue::storeAnyArguments(DelayedFunctionCall &dfc, const QV4
QV4::Scope scope(engine);
QV4::ScopedArrayObject array(scope, engine->newArrayObject(length));
uint i = 0;
- for (int j = offset, ej = argc; j < ej; ++i, ++j)
- array->put(i, argv[j]);
+ for (int j = offset, ej = args->length(); j < ej; ++i, ++j)
+ array->put(i, (*args)[j]);
dfc.m_args.set(engine, array);
}
diff --git a/src/qml/qml/qqmldelayedcallqueue_p.h b/src/qml/qml/qqmldelayedcallqueue_p.h
index 48ee38bbb9..88f0c4d118 100644
--- a/src/qml/qml/qqmldelayedcallqueue_p.h
+++ b/src/qml/qml/qqmldelayedcallqueue_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLDELAYEDCALLQUEUE_P_H
#define QQMLDELAYEDCALLQUEUE_P_H
@@ -69,9 +33,8 @@ public:
void init(QV4::ExecutionEngine *);
- static QV4::ReturnedValue addUniquelyAndExecuteLater(
- const QV4::FunctionObject *, const QV4::Value *thisObject,
- const QV4::Value *argv, int argc);
+ static QV4::ReturnedValue addUniquelyAndExecuteLater(QV4::ExecutionEngine *engine,
+ QQmlV4FunctionPtr args);
public Q_SLOTS:
void ticked();
@@ -91,7 +54,7 @@ private:
bool m_guarded;
};
- void storeAnyArguments(DelayedFunctionCall& dfc, const QV4::Value *argv, int argc, int offset, QV4::ExecutionEngine *engine);
+ void storeAnyArguments(DelayedFunctionCall& dfc, QQmlV4FunctionPtr args, int offset, QV4::ExecutionEngine *engine);
void executeAllExpired_Later();
QV4::ExecutionEngine *m_engine;
diff --git a/src/qml/qml/qqmldirdata.cpp b/src/qml/qml/qqmldirdata.cpp
index 9c42cbec13..8997146dba 100644
--- a/src/qml/qml/qqmldirdata.cpp
+++ b/src/qml/qml/qqmldirdata.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 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$
-**
-****************************************************************************/
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <private/qqmldirdata_p.h>
@@ -51,30 +15,18 @@ const QString &QQmlQmldirData::content() const
return m_content;
}
-QQmlTypeLoader::Blob::PendingImportPtr QQmlQmldirData::import(QQmlTypeLoader::Blob *blob) const
+QV4::CompiledData::Location QQmlQmldirData::importLocation(QQmlTypeLoader::Blob *blob) const
{
- auto it = m_imports.find(blob);
- if (it == m_imports.end())
- return nullptr;
- return *it;
+ auto it = m_imports.constFind(blob);
+ if (it == m_imports.constEnd())
+ return QV4::CompiledData::Location();
+ return it->import->location;
}
-void QQmlQmldirData::setImport(QQmlTypeLoader::Blob *blob, QQmlTypeLoader::Blob::PendingImportPtr import)
+void QQmlQmldirData::setPriority(QQmlTypeLoader::Blob *blob,
+ QQmlTypeLoader::Blob::PendingImportPtr import, int priority)
{
- m_imports[blob] = std::move(import);
-}
-
-int QQmlQmldirData::priority(QQmlTypeLoader::Blob *blob) const
-{
- QHash<QQmlTypeLoader::Blob *, int>::const_iterator it = m_priorities.find(blob);
- if (it == m_priorities.end())
- return 0;
- return *it;
-}
-
-void QQmlQmldirData::setPriority(QQmlTypeLoader::Blob *blob, int priority)
-{
- m_priorities[blob] = priority;
+ m_imports.insert(blob, { std::move(import), priority });
}
void QQmlQmldirData::dataReceived(const SourceCodeData &data)
diff --git a/src/qml/qml/qqmldirdata_p.h b/src/qml/qml/qqmldirdata_p.h
index d8ca7886e6..777e3854eb 100644
--- a/src/qml/qml/qqmldirdata_p.h
+++ b/src/qml/qml/qqmldirdata_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 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$
-**
-****************************************************************************/
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLDIRDATA_P_H
#define QQMLDIRDATA_P_H
@@ -64,21 +28,39 @@ private:
public:
const QString &content() const;
+ QV4::CompiledData::Location importLocation(Blob *blob) const;
- PendingImportPtr import(QQmlTypeLoader::Blob *) const;
- void setImport(QQmlTypeLoader::Blob *, PendingImportPtr);
+ template<typename Callback>
+ bool processImports(Blob *blob, const Callback &callback) const
+ {
+ bool result = true;
+ const auto range = m_imports.equal_range(blob);
+ for (auto it = range.first; it != range.second; ++it) {
+ // Do we need to resolve this import?
+ if ((it->import->priority == 0) || (it->import->priority > it->priority)) {
+ // This is the (current) best resolution for this import
+ if (!callback(it->import))
+ result = false;
+ it->import->priority = it->priority;
+ }
+ }
+ return result;
+ }
- int priority(QQmlTypeLoader::Blob *) const;
- void setPriority(QQmlTypeLoader::Blob *, int);
+ void setPriority(Blob *, PendingImportPtr, int);
protected:
void dataReceived(const SourceCodeData &) override;
void initializeFromCachedUnit(const QQmlPrivate::CachedQmlUnit *) override;
private:
+ struct PrioritizedImport {
+ PendingImportPtr import;
+ int priority = 0;
+ };
+
QString m_content;
- QHash<QQmlTypeLoader::Blob *, QQmlTypeLoader::Blob::PendingImportPtr> m_imports;
- QHash<QQmlTypeLoader::Blob *, int> m_priorities;
+ QMultiHash<Blob *, PrioritizedImport> m_imports;
};
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlengine.cpp b/src/qml/qml/qqmlengine.cpp
index 30f24a8091..c7812059a1 100644
--- a/src/qml/qml/qqmlengine.cpp
+++ b/src/qml/qml/qqmlengine.cpp
@@ -1,67 +1,23 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qqmlengine_p.h"
#include "qqmlengine.h"
-#include "qqmlcomponentattached_p.h"
#include "qqmlcontext_p.h"
#include "qqml.h"
#include "qqmlcontext.h"
-#include "qqmlexpression.h"
-#include "qqmlcomponent.h"
-#include "qqmlvme_p.h"
-#include "qqmlstringconverters_p.h"
#include "qqmlscriptstring.h"
#include "qqmlglobal_p.h"
-#include "qqmlcomponent_p.h"
-#include "qqmlextensioninterface.h"
-#include "qqmllist_p.h"
-#include "qqmltypenamecache_p.h"
#include "qqmlnotifier_p.h"
#include "qqmlincubator.h"
#include "qqmlabstracturlinterceptor.h"
-#include "qqmlsourcecoordinate_p.h"
+
#include <private/qqmldirparser_p.h>
#include <private/qqmlboundsignal_p.h>
#include <private/qqmljsdiagnosticmessage_p.h>
#include <private/qqmltype_p_p.h>
+#include <private/qqmlpluginimporter_p.h>
#include <QtCore/qstandardpaths.h>
#include <QtCore/qmetaobject.h>
#include <QDebug>
@@ -71,6 +27,10 @@
#include <QtCore/qmutex.h>
#include <QtCore/qthread.h>
#include <private/qthread_p.h>
+#include <private/qqmlscriptdata_p.h>
+#include <QtQml/private/qqmlcomponentattached_p.h>
+#include <QtQml/private/qqmlsourcecoordinate_p.h>
+#include <QtQml/private/qqmlcomponent_p.h>
#if QT_CONFIG(qml_network)
#include "qqmlnetworkaccessmanagerfactory.h"
@@ -89,10 +49,7 @@
#endif
#include <private/qqmlplatform_p.h>
#include <private/qqmlloggingcategory_p.h>
-
-#if QT_CONFIG(qml_sequence_object)
#include <private/qv4sequenceobject_p.h>
-#endif
#ifdef Q_OS_WIN // for %APPDATA%
# include <qt_windows.h>
@@ -105,6 +62,8 @@
QT_BEGIN_NAMESPACE
+void qml_register_types_QML();
+
/*!
\qmltype QtObject
\instantiates QObject
@@ -161,7 +120,7 @@ QT_BEGIN_NAMESPACE
\endcode
*/
-bool QQmlEnginePrivate::qml_debugging_enabled = false;
+Q_CONSTINIT std::atomic<bool> QQmlEnginePrivate::qml_debugging_enabled{false};
bool QQmlEnginePrivate::s_designerMode = false;
bool QQmlEnginePrivate::designerMode()
@@ -238,426 +197,64 @@ QQmlImageProviderBase::~QQmlImageProviderBase()
{
}
-
-/*!
-\qmltype Qt
-\inqmlmodule QtQml
-\instantiates QQmlEnginePrivate
-\ingroup qml-utility-elements
-\keyword QmlGlobalQtObject
-\brief Provides a global object with useful enums and functions from Qt.
-
-The \c Qt object is a global object with utility functions, properties and enums.
-
-It is not instantiable; to use it, call the members of the global \c Qt object directly.
-For example:
-
-\qml
-import QtQuick 2.0
-
-Text {
- color: Qt.rgba(1, 0, 0, 1)
- text: Qt.md5("hello, world")
-}
-\endqml
-
-
-\section1 Enums
-
-The Qt object contains the enums available in the \l [QtCore]{Qt}{Qt Namespace}. For example, you can access
-the \l Qt::LeftButton and \l Qt::RightButton enumeration values as \c Qt.LeftButton and \c Qt.RightButton.
-
-
-\section1 Types
-
-The Qt object also contains helper functions for creating objects of specific
-data types. This is primarily useful when setting the properties of an item
-when the property has one of the following types:
-\list
-\li \c rect - use \l{Qt::rect()}{Qt.rect()}
-\li \c point - use \l{Qt::point()}{Qt.point()}
-\li \c size - use \l{Qt::size()}{Qt.size()}
-\endlist
-
-If the \c QtQuick module has been imported, the following helper functions for
-creating objects of specific data types are also available for clients to use:
-\list
-\li \c color - use \l{Qt::rgba()}{Qt.rgba()}, \l{Qt::hsla()}{Qt.hsla()}, \l{Qt::darker()}{Qt.darker()}, \l{Qt::lighter()}{Qt.lighter()} or \l{Qt::tint()}{Qt.tint()}
-\li \c font - use \l{Qt::font()}{Qt.font()}
-\li \c vector2d - use \l{Qt::vector2d()}{Qt.vector2d()}
-\li \c vector3d - use \l{Qt::vector3d()}{Qt.vector3d()}
-\li \c vector4d - use \l{Qt::vector4d()}{Qt.vector4d()}
-\li \c quaternion - use \l{Qt::quaternion()}{Qt.quaternion()}
-\li \c matrix4x4 - use \l{Qt::matrix4x4()}{Qt.matrix4x4()}
-\endlist
-
-There are also string based constructors for these types. See \l{qtqml-typesystem-basictypes.html}{QML Basic Types} for more information.
-
-\section1 Date/Time Formatters
-
-The Qt object contains several functions for formatting QDateTime, QDate and QTime values.
-
-\list
- \li \l{Qt::formatDateTime}{string Qt.formatDateTime(datetime date, variant format)}
- \li \l{Qt::formatDate}{string Qt.formatDate(datetime date, variant format)}
- \li \l{Qt::formatTime}{string Qt.formatTime(datetime date, variant format)}
-\endlist
-
-The format specification is described at \l{Qt::formatDateTime}{Qt.formatDateTime}.
-
-
-\section1 Dynamic Object Creation
-The following functions on the global object allow you to dynamically create QML
-items from files or strings. See \l{Dynamic QML Object Creation from JavaScript} for an overview
-of their use.
-
-\list
- \li \l{Qt::createComponent()}{object Qt.createComponent(url)}
- \li \l{Qt::createQmlObject()}{object Qt.createQmlObject(string qml, object parent, string filepath)}
-\endlist
-
-
-\section1 Other Functions
-
-The following functions are also on the Qt object.
-
-\list
- \li \l{Qt::quit()}{Qt.quit()}
- \li \l{Qt::md5()}{Qt.md5(string)}
- \li \l{Qt::btoa()}{string Qt.btoa(string)}
- \li \l{Qt::atob()}{string Qt.atob(string)}
- \li \l{Qt::binding()}{object Qt.binding(function)}
- \li \l{Qt::locale()}{object Qt.locale()}
- \li \l{Qt::resolvedUrl()}{string Qt.resolvedUrl(string)}
- \li \l{Qt::openUrlExternally()}{Qt.openUrlExternally(string)}
- \li \l{Qt::fontFamilies()}{list<string> Qt.fontFamilies()}
-\endlist
-*/
-
-/*!
- \qmlproperty object Qt::platform
- \since 5.1
-
- The \c platform object provides info about the underlying platform.
-
- Its properties are:
-
- \table
- \row
- \li \c platform.os
- \li
-
- This read-only property contains the name of the operating system.
-
- Possible values are:
-
- \list
- \li \c "android" - Android
- \li \c "ios" - iOS
- \li \c "tvos" - tvOS
- \li \c "linux" - Linux
- \li \c "osx" - \macos
- \li \c "qnx" - QNX (since Qt 5.9.3)
- \li \c "unix" - Other Unix-based OS
- \li \c "windows" - Windows
- \li \c "wasm" - WebAssembly
- \endlist
-
- \row
- \li \c platform.pluginName
- \li This is the name of the platform set on the QGuiApplication instance
- as returned by \l QGuiApplication::platformName()
-
- \endtable
-*/
-
-/*!
- \qmlproperty object Qt::application
- \since 5.1
-
- The \c application object provides access to global application state
- properties shared by many QML components.
-
- Its properties are:
-
- \table
- \row
- \li \c application.active
- \li
- Deprecated, use Qt.application.state == Qt.ApplicationActive instead.
-
- \row
- \li \c application.state
- \li
- This read-only property indicates the current state of the application.
-
- Possible values are:
-
- \list
- \li Qt.ApplicationActive - The application is the top-most and focused application, and the
- user is able to interact with the application.
- \li Qt.ApplicationInactive - The application is visible or partially visible, but not selected
- to be in front, the user cannot interact with the application.
- On desktop platforms, this typically means that the user activated
- another application. On mobile platforms, it is more common to
- enter this state when the OS is interrupting the user with for
- example incoming calls, SMS-messages or dialogs. This is usually a
- transient state during which the application is paused. The user
- may return focus to your application, but most of the time it will
- be the first indication that the application is going to be suspended.
- While in this state, consider pausing or stopping any activity that
- should not continue when the user cannot interact with your
- application, such as a video, a game, animations, or sensors.
- You should also avoid performing CPU-intensive tasks which might
- slow down the application in front.
- \li Qt.ApplicationSuspended - The application is suspended and not visible to the user. On
- mobile platforms, the application typically enters this state when
- the user returns to the home screen or switches to another
- application. While in this state, the application should ensure
- that the user perceives it as always alive and does not lose his
- progress, saving any persistent data. The application should cease
- all activities and be prepared for code execution to stop. While
- suspended, the application can be killed at any time without
- further warnings (for example when low memory forces the OS to purge
- suspended applications).
- \li Qt.ApplicationHidden - The application is hidden and runs in the background. This is the
- normal state for applications that need to do background processing,
- like playing music, while the user interacts with other applications.
- The application should free up all graphical resources when entering
- this state. A Qt Quick application should not usually handle this state
- at the QML level. Instead, you should unload the entire UI and reload
- the QML files whenever the application becomes active again.
- \endlist
-
- \row
- \li \c application.layoutDirection
- \li
- This read-only property can be used to query the default layout direction of the
- application. On system start-up, the default layout direction depends on the
- application's language. The property has a value of \c Qt.RightToLeft in locales
- where text and graphic elements are read from right to left, and \c Qt.LeftToRight
- where the reading direction flows from left to right. You can bind to this
- property to customize your application layouts to support both layout directions.
-
- Possible values are:
-
- \list
- \li Qt.LeftToRight - Text and graphics elements should be positioned
- from left to right.
- \li Qt.RightToLeft - Text and graphics elements should be positioned
- from right to left.
- \endlist
- \row
- \li \c application.font
- \li This read-only property holds the default application font as
- returned by \l QGuiApplication::font().
- \row
- \li \c application.arguments
- \li This is a string list of the arguments the executable was invoked with.
- \row
- \li \c application.name
- \li This is the application name set on the QCoreApplication instance. This property can be written
- to in order to set the application name.
- \row
- \li \c application.displayName (since Qt 5.9)
- \li This is the application display name set on the QGuiApplication instance. This property can be written
- to in order to set the application display name.
- \row
- \li \c application.version
- \li This is the application version set on the QCoreApplication instance. This property can be written
- to in order to set the application version.
- \row
- \li \c application.organization
- \li This is the organization name set on the QCoreApplication instance. This property can be written
- to in order to set the organization name.
- \row
- \li \c application.domain
- \li This is the organization domain set on the QCoreApplication instance. This property can be written
- to in order to set the organization domain.
-
- \row
- \li \c application.supportsMultipleWindows
- \li This read-only property can be used to determine whether or not the
- platform supports multiple windows. Some embedded platforms do not support
- multiple windows, for example.
-
- \row
- \li \c application.screens
- \li An array containing the descriptions of all connected screens. The
- elements of the array are objects with the same properties as the
- \l{Screen} attached object. In practice the array corresponds to the screen
- list returned by QGuiApplication::screens(). In addition to examining
- properties like name, width, height, etc., the array elements can also be
- assigned to the screen property of Window items, thus serving as an
- alternative to the C++ side's QWindow::setScreen(). This property has been
- added in Qt 5.9.
-
- \endtable
-
- The object also has one signal, aboutToQuit(), which is the same as \l QCoreApplication::aboutToQuit().
-
- The following example uses the \c application object to indicate
- whether the application is currently active:
-
- \snippet qml/application.qml document
-
- Note that when using QML without a QGuiApplication, the following properties will be undefined:
- \list
- \li application.active
- \li application.state
- \li application.layoutDirection
- \li application.font
- \endlist
-
- \sa Screen, Window, {Window::screen}{Window.screen}
-*/
-
-/*!
- \qmlproperty object Qt::inputMethod
- \since 5.0
-
- The \c inputMethod object allows access to application's QInputMethod object
- and all its properties and slots. See the QInputMethod documentation for
- further details.
-*/
-
-/*!
- \qmlproperty object Qt::styleHints
- \since 5.5
-
- The \c styleHints object provides platform-specific style hints and settings.
- See the QStyleHints documentation for further details.
-
- \note The \c styleHints object is only available when using the Qt Quick module.
-
- The following example uses the \c styleHints object to determine whether an
- item should gain focus on mouse press or touch release:
- \code
- import QtQuick 2.4
-
- MouseArea {
- id: button
-
- onPressed: {
- if (!Qt.styleHints.setFocusOnTouchRelease)
- button.forceActiveFocus()
- }
- onReleased: {
- if (Qt.styleHints.setFocusOnTouchRelease)
- button.forceActiveFocus()
- }
- }
- \endcode
-*/
-
-/*!
-\qmlmethod object Qt::include(string url, jsobject callback)
-\deprecated
-
-This method should not be used. Use ECMAScript modules instead and the native
-JavaScript \c import and \c export statements instead.
-
-Includes another JavaScript file. This method can only be used from within JavaScript files,
-and not regular QML files.
-
-This imports all functions from \a url into the current script's namespace.
-
-Qt.include() returns an object that describes the status of the operation. The object has
-a single property, \c {status}, that is set to one of the following values:
-
-\table
-\header \li Symbol \li Value \li Description
-\row \li result.OK \li 0 \li The include completed successfully.
-\row \li result.LOADING \li 1 \li Data is being loaded from the network.
-\row \li result.NETWORK_ERROR \li 2 \li A network error occurred while fetching the url.
-\row \li result.EXCEPTION \li 3 \li A JavaScript exception occurred while executing the included code.
-An additional \c exception property will be set in this case.
-\endtable
-
-The \c status property will be updated as the operation progresses.
-
-If provided, \a callback is invoked when the operation completes. The callback is passed
-the same object as is returned from the Qt.include() call.
-*/
-// Qt.include() is implemented in qv4include.cpp
-
-QQmlEnginePrivate::QQmlEnginePrivate(QQmlEngine *e)
-: propertyCapture(nullptr), rootContext(nullptr),
-#if QT_CONFIG(qml_debug)
- profiler(nullptr),
-#endif
- outputWarningsToMsgLog(true),
- erroredBindings(nullptr), inProgressCreations(0),
-#if QT_CONFIG(qml_worker_script)
- workerScriptEngine(nullptr),
-#endif
- activeObjectCreator(nullptr),
-#if QT_CONFIG(qml_network)
- networkAccessManager(nullptr), networkAccessManagerFactory(nullptr),
-#endif
- scarceResourcesRefCount(0), importDatabase(e), typeLoader(e),
- uniqueId(1), incubatorCount(0), incubationController(nullptr)
-{
-}
-
QQmlEnginePrivate::~QQmlEnginePrivate()
{
if (inProgressCreations)
qWarning() << QQmlEngine::tr("There are still \"%1\" items in the process of being created at engine destruction.").arg(inProgressCreations);
- doDeleteInEngineThread();
-
if (incubationController) incubationController->d = nullptr;
incubationController = nullptr;
QQmlMetaType::freeUnusedTypesAndCaches();
- for (auto iter = m_compositeTypes.cbegin(), end = m_compositeTypes.cend(); iter != end; ++iter)
- iter.value()->isRegisteredWithEngine = false;
#if QT_CONFIG(qml_debug)
delete profiler;
#endif
+ qDeleteAll(cachedValueTypeInstances);
}
void QQmlPrivate::qdeclarativeelement_destructor(QObject *o)
{
- if (QQmlData *d = QQmlData::get(o)) {
+ QObjectPrivate *p = QObjectPrivate::get(o);
+ if (QQmlData *d = QQmlData::get(p)) {
+ const auto invalidate = [](QQmlContextData *c) {c->invalidate();};
if (d->ownContext) {
- for (QQmlRefPointer<QQmlContextData> lc = d->ownContext->linkedContext().data(); lc;
- lc = lc->linkedContext()) {
- lc->invalidate();
- if (lc->contextObject() == o)
- lc->setContextObject(nullptr);
- }
- d->ownContext->invalidate();
- if (d->ownContext->contextObject() == o)
- d->ownContext->setContextObject(nullptr);
- d->ownContext = nullptr;
+ d->ownContext->deepClearContextObject(o, invalidate, invalidate);
+ d->ownContext.reset();
d->context = nullptr;
+ Q_ASSERT(!d->outerContext || d->outerContext->contextObject() != o);
+ } else if (d->outerContext && d->outerContext->contextObject() == o) {
+ d->outerContext->deepClearContextObject(o, invalidate, invalidate);
}
- if (d->outerContext && d->outerContext->contextObject() == o)
- d->outerContext->setContextObject(nullptr);
+ if (d->hasVMEMetaObject || d->hasInterceptorMetaObject) {
+ // This is somewhat dangerous because another thread might concurrently
+ // try to resolve the dynamic metaobject. In practice this will then
+ // lead to either the code path that still returns the interceptor
+ // metaobject or the code path that returns the string casted one. Both
+ // is fine if you cannot actually touch the object itself. Since the
+ // other thread is obviously not synchronized to this one, it can't.
+ //
+ // In particular we do this when delivering the frameSwapped() signal
+ // in QQuickWindow. The handler for frameSwapped() is written in a way
+ // that is thread safe as long as QQuickWindow's dtor hasn't finished.
+ // QQuickWindow's dtor does synchronize with the render thread, but it
+ // runs _after_ qdeclarativeelement_destructor.
+ static_cast<QQmlInterceptorMetaObject *>(p->metaObject)->invalidate();
+ d->hasVMEMetaObject = d->hasInterceptorMetaObject = false;
+ }
// Mark this object as in the process of deletion to
// prevent it resolving in bindings
QQmlData::markAsDeleted(o);
-
- // Disconnect the notifiers now - during object destruction this would be too late, since
- // the disconnect call wouldn't be able to call disconnectNotify(), as it isn't possible to
- // get the metaobject anymore.
- d->disconnectNotifiers();
}
}
-QQmlData::QQmlData()
- : ownMemory(true), indestructible(true), explicitIndestructibleSet(false),
+QQmlData::QQmlData(Ownership ownership)
+ : ownMemory(ownership == OwnsMemory), indestructible(true), explicitIndestructibleSet(false),
hasTaintedV4Object(false), isQueuedForDeletion(false), rootObjectInCreation(false),
- hasInterceptorMetaObject(false), hasVMEMetaObject(false),
- bindingBitsArraySize(InlineBindingArraySize), notifyList(nullptr),
- bindings(nullptr), signalHandlers(nullptr), nextContextObject(nullptr), prevContextObject(nullptr),
- lineNumber(0), columnNumber(0), jsEngineId(0),
- propertyCache(nullptr), guards(nullptr), extendedData(nullptr)
+ hasInterceptorMetaObject(false), hasVMEMetaObject(false), hasConstWrapper(false), dummy(0),
+ bindingBitsArraySize(InlineBindingArraySize)
{
memset(bindingBitsValue, 0, sizeof(bindingBitsValue));
init();
@@ -707,7 +304,10 @@ void QQmlData::signalEmitted(QAbstractDeclarativeData *, QObject *object, int in
// QQmlEngine to emit signals from a different thread. These signals are then automatically
// marshalled back onto the QObject's thread and handled by QML from there. This is tested
// by the qqmlecmascript::threadSignal() autotest.
- if (!ddata->notifyList)
+
+ // Relaxed semantics here. If we're on a different thread we might schedule a useless event,
+ // but that should be rare.
+ if (!ddata->notifyList.loadRelaxed())
return;
auto objectThreadData = QObjectPrivate::get(object)->threadData.loadRelaxed();
@@ -718,14 +318,14 @@ void QQmlData::signalEmitted(QAbstractDeclarativeData *, QObject *object, int in
QMetaMethod m = QMetaObjectPrivate::signal(object->metaObject(), index);
QList<QByteArray> parameterTypes = m.parameterTypes();
- QScopedPointer<QMetaCallEvent> ev(new QMetaCallEvent(m.methodIndex(), 0, nullptr,
- object, index,
- parameterTypes.count() + 1));
+ auto ev = std::make_unique<QMetaCallEvent>(m.methodIndex(), 0, nullptr,
+ object, index,
+ parameterTypes.size() + 1);
void **args = ev->args();
QMetaType *types = ev->types();
- for (int ii = 0; ii < parameterTypes.count(); ++ii) {
+ for (int ii = 0; ii < parameterTypes.size(); ++ii) {
const QByteArray &typeName = parameterTypes.at(ii);
if (typeName.endsWith('*'))
types[ii + 1] = QMetaType(QMetaType::VoidStar);
@@ -745,7 +345,7 @@ void QQmlData::signalEmitted(QAbstractDeclarativeData *, QObject *object, int in
QQmlThreadNotifierProxyObject *mpo = new QQmlThreadNotifierProxyObject;
mpo->target = object;
mpo->moveToThread(objectThreadData->thread.loadAcquire());
- QCoreApplication::postEvent(mpo, ev.take());
+ QCoreApplication::postEvent(mpo, ev.release());
} else {
QQmlNotifierEndpoint *ep = ddata->notify(index);
@@ -781,11 +381,15 @@ int QQmlData::endpointCount(int index)
void QQmlData::markAsDeleted(QObject *o)
{
- QQmlData::setQueuedForDeletion(o);
-
- QObjectPrivate *p = QObjectPrivate::get(o);
- for (QList<QObject *>::const_iterator it = p->children.constBegin(), end = p->children.constEnd(); it != end; ++it) {
- QQmlData::markAsDeleted(*it);
+ QVarLengthArray<QObject *> workStack;
+ workStack.push_back(o);
+ while (!workStack.isEmpty()) {
+ auto currentObject = workStack.last();
+ workStack.pop_back();
+ QQmlData::setQueuedForDeletion(currentObject);
+ auto currentObjectPriv = QObjectPrivate::get(currentObject);
+ for (QObject *child: std::as_const(currentObjectPriv->children))
+ workStack.push_back(child);
}
}
@@ -795,39 +399,69 @@ void QQmlData::setQueuedForDeletion(QObject *object)
if (QQmlData *ddata = QQmlData::get(object)) {
if (ddata->ownContext) {
Q_ASSERT(ddata->ownContext.data() == ddata->context);
- ddata->context->emitDestruction();
- if (ddata->ownContext->contextObject() == object)
- ddata->ownContext->setContextObject(nullptr);
- ddata->ownContext = nullptr;
+ ddata->ownContext->deepClearContextObject(object);
+ ddata->ownContext.reset();
ddata->context = nullptr;
}
ddata->isQueuedForDeletion = true;
+
+ // Disconnect the notifiers now - during object destruction this would be too late,
+ // since the disconnect call wouldn't be able to call disconnectNotify(), as it isn't
+ // possible to get the metaobject anymore.
+ // Also, there is no point in evaluating bindings in order to set properties on
+ // half-deleted objects.
+ ddata->disconnectNotifiers(DeleteNotifyList::No);
}
}
}
-void QQmlData::flushPendingBindingImpl(QQmlPropertyIndex index)
+void QQmlData::flushPendingBinding(int coreIndex)
{
- clearPendingBindingBit(index.coreIndex());
+ clearPendingBindingBit(coreIndex);
// Find the binding
QQmlAbstractBinding *b = bindings;
- while (b && (b->targetPropertyIndex().coreIndex() != index.coreIndex() ||
+ while (b && (b->targetPropertyIndex().coreIndex() != coreIndex ||
b->targetPropertyIndex().hasValueTypeIndex()))
b = b->nextBinding();
- if (b && b->targetPropertyIndex().coreIndex() == index.coreIndex() &&
+ if (b && b->targetPropertyIndex().coreIndex() == coreIndex &&
!b->targetPropertyIndex().hasValueTypeIndex())
b->setEnabled(true, QQmlPropertyData::BypassInterceptor |
QQmlPropertyData::DontRemoveBinding);
}
-QQmlData::DeferredData::DeferredData()
-{
-}
+QQmlData::DeferredData::DeferredData() = default;
+QQmlData::DeferredData::~DeferredData() = default;
-QQmlData::DeferredData::~DeferredData()
-{
+template<>
+int qmlRegisterType<void>(const char *uri, int versionMajor, int versionMinor, const char *qmlName)
+{
+ QQmlPrivate::RegisterType type = {
+ QQmlPrivate::RegisterType::CurrentVersion,
+ QMetaType(),
+ QMetaType(),
+ 0, nullptr, nullptr,
+ QString(),
+ nullptr,
+ uri,
+ QTypeRevision::fromVersion(versionMajor, versionMinor),
+ qmlName,
+ nullptr,
+ nullptr,
+ nullptr,
+ -1,
+ -1,
+ -1,
+ nullptr,
+ nullptr,
+ nullptr,
+ QTypeRevision::zero(),
+ -1,
+ QQmlPrivate::ValueTypeCreationMethod::None,
+ };
+
+ return QQmlPrivate::qmlregister(QQmlPrivate::TypeRegistration, &type);
}
bool QQmlEnginePrivate::baseModulesUninitialized = true;
@@ -836,23 +470,25 @@ void QQmlEnginePrivate::init()
Q_Q(QQmlEngine);
if (baseModulesUninitialized) {
+ // Register builtins
+ qml_register_types_QML();
+
+ // No need to specifically register those.
+ static_assert(std::is_same_v<QStringList, QList<QString>>);
+ static_assert(std::is_same_v<QVariantList, QList<QVariant>>);
- // required for the Compiler.
- qmlRegisterType<QObject>("QML", 1, 0, "QtObject");
- qmlRegisterType<QQmlComponent>("QML", 1, 0, "Component");
+ qRegisterMetaType<QQmlScriptString>();
+ qRegisterMetaType<QQmlComponent::Status>();
+ qRegisterMetaType<QList<QObject*> >();
+ qRegisterMetaType<QQmlBinding*>();
+
+ // Protect the module: We don't want any URL interceptor to mess with the builtins.
+ qmlProtectModule("QML", 1);
QQmlData::init();
baseModulesUninitialized = false;
}
- qRegisterMetaType<QVariant>();
- qRegisterMetaType<QQmlScriptString>();
- qRegisterMetaType<QJSValue>();
- qRegisterMetaType<QQmlComponent::Status>();
- qRegisterMetaType<QList<QObject*> >();
- qRegisterMetaType<QList<int> >();
- qRegisterMetaType<QQmlBinding*>();
-
q->handle()->setQmlEngine(q);
rootContext = new QQmlContext(q,true);
@@ -864,29 +500,16 @@ void QQmlEnginePrivate::init()
\inmodule QtQml
\brief The QQmlEngine class provides an environment for instantiating QML components.
- Each QML component is instantiated in a QQmlContext.
- QQmlContext's are essential for passing data to QML
- components. In QML, contexts are arranged hierarchically and this
- hierarchy is managed by the QQmlEngine.
-
- Prior to creating any QML components, an application must have
- created a QQmlEngine to gain access to a QML context. The
- following example shows how to create a simple Text item.
-
- \code
- QQmlEngine engine;
- QQmlComponent component(&engine);
- component.setData("import QtQuick 2.0\nText { text: \"Hello world!\" }", QUrl());
- QQuickItem *item = qobject_cast<QQuickItem *>(component.create());
-
- //add item to view, etc
- ...
- \endcode
+ A QQmlEngine is used to manage \l{QQmlComponent}{components} and objects created from
+ them and execute their bindings and functions. QQmlEngine also inherits from
+ \l{QJSEngine} which allows seamless integration between your QML components and
+ JavaScript code.
- In this case, the Text item will be created in the engine's
- \l {QQmlEngine::rootContext()}{root context}.
+ Each QML component is instantiated in a QQmlContext. In QML, contexts are arranged
+ hierarchically and this hierarchy is managed by the QQmlEngine. By default,
+ components are instantiated in the \l {QQmlEngine::rootContext()}{root context}.
- \sa QQmlComponent, QQmlContext, {QML Global Object}
+ \sa QQmlComponent, QQmlContext, {QML Global Object}, QQmlApplicationEngine
*/
/*!
@@ -917,11 +540,12 @@ QQmlEngine::QQmlEngine(QQmlEnginePrivate &dd, QObject *parent)
invalidated, but not destroyed (unless they are parented to the
QQmlEngine object).
- See QJSEngine docs for details on cleaning up the JS engine.
+ See ~QJSEngine() for details on cleaning up the JS engine.
*/
QQmlEngine::~QQmlEngine()
{
Q_D(QQmlEngine);
+ handle()->inShutdown = true;
QJSEnginePrivate::removeFromDebugServer(this);
// Emit onDestruction signals for the root context before
@@ -933,9 +557,7 @@ QQmlEngine::~QQmlEngine()
// we do this here and not in the private dtor since otherwise a crash can
// occur (if we are the QObject parent of the QObject singleton instance)
// XXX TODO: performance -- store list of singleton types separately?
- const QList<QQmlType> singletonTypes = QQmlMetaType::qmlSingletonTypes();
- for (const QQmlType &currType : singletonTypes)
- d->destroySingletonInstance(currType);
+ d->singletonInstances.clear();
delete d->rootContext;
d->rootContext = nullptr;
@@ -977,14 +599,35 @@ QQmlEngine::~QQmlEngine()
Once the component cache has been cleared, components must be loaded before
any new objects can be created.
- \sa trimComponentCache()
+ \note Any existing objects created from QML components retain their types,
+ even if you clear the component cache. This includes singleton objects. If you
+ create more objects from the same QML code after clearing the cache, the new
+ objects will be of different types than the old ones. Assigning such a new
+ object to a property of its declared type belonging to an object created
+ before clearing the cache won't work.
+
+ As a general rule of thumb, make sure that no objects created from QML
+ components are alive when you clear the component cache.
+
+ \sa trimComponentCache(), clearSingletons()
*/
void QQmlEngine::clearComponentCache()
{
Q_D(QQmlEngine);
+
+ // Contexts can hold on to CUs but live on the JS heap.
+ // Use a non-incremental GC run to get rid of those.
+ QV4::MemoryManager *mm = handle()->memoryManager;
+ auto oldLimit = mm->gcStateMachine->timeLimit;
+ mm->setGCTimeLimit(-1);
+ mm->runGC();
+ mm->gcStateMachine->timeLimit = std::move(oldLimit);
+
+ handle()->clearCompilationUnits();
d->typeLoader.lock();
d->typeLoader.clearCache();
d->typeLoader.unlock();
+ QQmlMetaType::freeUnusedTypesAndCaches();
}
/*!
@@ -1002,10 +645,32 @@ void QQmlEngine::clearComponentCache()
void QQmlEngine::trimComponentCache()
{
Q_D(QQmlEngine);
+ handle()->trimCompilationUnits();
d->typeLoader.trimCache();
}
/*!
+ Clears all singletons the engine owns.
+
+ This function drops all singleton instances, deleting any QObjects owned by
+ the engine among them. This is useful to make sure that no QML-created objects
+ are left before calling clearComponentCache().
+
+ QML properties holding QObject-based singleton instances become null if the
+ engine owns the singleton or retain their value if the engine doesn't own it.
+ The singletons are not automatically re-created by accessing existing
+ QML-created objects. Only when new components are instantiated, the singletons
+ are re-created.
+
+ \sa clearComponentCache()
+ */
+void QQmlEngine::clearSingletons()
+{
+ Q_D(QQmlEngine);
+ d->singletonInstances.clear();
+}
+
+/*!
Returns the engine's root context.
The root context is automatically created by the QQmlEngine.
@@ -1080,20 +745,19 @@ QUrl QQmlEngine::interceptUrl(const QUrl &url, QQmlAbstractUrlInterceptor::DataT
return result;
}
-void QQmlEnginePrivate::registerFinalizeCallback(QObject *obj, int index)
+/*!
+ Returns the list of currently active URL interceptors.
+ */
+QList<QQmlAbstractUrlInterceptor *> QQmlEngine::urlInterceptors() const
{
- if (activeObjectCreator) {
- activeObjectCreator->finalizeCallbacks()->append(qMakePair(QPointer<QObject>(obj), index));
- } else {
- void *args[] = { nullptr };
- QMetaObject::metacall(obj, QMetaObject::InvokeMetaMethod, index, args);
- }
+ Q_D(const QQmlEngine);
+ return d->urlInterceptors;
}
QSharedPointer<QQmlImageProviderBase> QQmlEnginePrivate::imageProvider(const QString &providerId) const
{
const QString providerIdLower = providerId.toLower();
- QMutexLocker locker(&mutex);
+ QMutexLocker locker(&imageProviderMutex);
return imageProviders.value(providerIdLower);
}
@@ -1188,7 +852,7 @@ void QQmlEngine::addImageProvider(const QString &providerId, QQmlImageProviderBa
Q_D(QQmlEngine);
QString providerIdLower = providerId.toLower();
QSharedPointer<QQmlImageProviderBase> sp(provider);
- QMutexLocker locker(&d->mutex);
+ QMutexLocker locker(&d->imageProviderMutex);
d->imageProviders.insert(std::move(providerIdLower), std::move(sp));
}
@@ -1201,7 +865,7 @@ QQmlImageProviderBase *QQmlEngine::imageProvider(const QString &providerId) cons
{
Q_D(const QQmlEngine);
const QString providerIdLower = providerId.toLower();
- QMutexLocker locker(&d->mutex);
+ QMutexLocker locker(&d->imageProviderMutex);
return d->imageProviders.value(providerIdLower).data();
}
@@ -1214,7 +878,7 @@ void QQmlEngine::removeImageProvider(const QString &providerId)
{
Q_D(QQmlEngine);
const QString providerIdLower = providerId.toLower();
- QMutexLocker locker(&d->mutex);
+ QMutexLocker locker(&d->imageProviderMutex);
d->imageProviders.take(providerIdLower);
}
@@ -1279,6 +943,45 @@ void QQmlEngine::setOutputWarningsToStandardError(bool enabled)
d->outputWarningsToMsgLog = enabled;
}
+
+/*!
+ \since 6.6
+ If this method is called inside of a function that is part of
+ a binding in QML, the binding will be treated as a translation binding.
+
+ \code
+ class I18nAwareClass : public QObject {
+
+ //...
+
+ QString text() const
+ {
+ if (auto engine = qmlEngine(this))
+ engine->markCurrentFunctionAsTranslationBinding();
+ return tr("Hello, world!");
+ }
+ };
+ \endcode
+
+ \note This function is mostly useful if you wish to provide your
+ own alternative to the qsTr function. To ensure that properties
+ exposed from C++ classes are updated on language changes, it is
+ instead recommended to react to \c LanguageChange events. That
+ is a more general mechanism which also works when the class is
+ used in a non-QML context, and has slightly less overhead. However,
+ using \c markCurrentFunctionAsTranslationBinding can be acceptable
+ when the class is already closely tied to the QML engine.
+ For more details, see \l {Prepare for Dynamic Language Changes}
+
+ \sa QQmlEngine::retranslate
+*/
+void QQmlEngine::markCurrentFunctionAsTranslationBinding()
+{
+ Q_D(QQmlEngine);
+ if (auto propertyCapture = d->propertyCapture)
+ propertyCapture->captureTranslation();
+}
+
/*!
\internal
@@ -1343,7 +1046,7 @@ template<>
QJSValue QQmlEngine::singletonInstance<QJSValue>(int qmlTypeId)
{
Q_D(QQmlEngine);
- QQmlType type = QQmlMetaType::qmlType(qmlTypeId, QQmlMetaType::TypeIdCategory::QmlType);
+ QQmlType type = QQmlMetaType::qmlTypeById(qmlTypeId);
if (!type.isValid() || !type.isSingleton())
return QJSValue();
@@ -1351,6 +1054,48 @@ QJSValue QQmlEngine::singletonInstance<QJSValue>(int qmlTypeId)
return d->singletonInstance<QJSValue>(type);
}
+
+/*!
+ \fn template<typename T> T QQmlEngine::singletonInstance(QAnyStringView uri, QAnyStringView typeName)
+
+ \overload
+ Returns the instance of a singleton type named \a typeName from the module specified by \a uri.
+
+ This method can be used as an alternative to calling qmlTypeId followed by the id based overload of
+ singletonInstance. This is convenient when one only needs to do a one time setup of a
+ singleton; if repeated access to the singleton is required, caching its typeId will allow
+ faster subsequent access via the
+ \l {QQmlEngine::singletonInstance(int qmlTypeId)}{type-id based overload}.
+
+ The template argument \e T may be either QJSValue or a pointer to a QObject-derived
+ type and depends on how the singleton was registered. If no instance of \e T has been
+ created yet, it is created now. If \a typeName does not represent a valid singleton
+ type, either a default constructed QJSValue or a \c nullptr is returned.
+
+ \snippet code/src_qml_qqmlengine.cpp 5
+
+ \sa QML_SINGLETON, qmlRegisterSingletonType(), qmlTypeId()
+ \since 6.5
+*/
+template<>
+QJSValue QQmlEngine::singletonInstance<QJSValue>(QAnyStringView uri, QAnyStringView typeName)
+{
+ Q_D(QQmlEngine);
+
+ auto loadHelper = QQml::makeRefPointer<LoadHelper>(&d->typeLoader, uri);
+
+ auto [moduleStatus, type] = loadHelper->resolveType(typeName);
+
+ if (moduleStatus == LoadHelper::ResolveTypeResult::NoSuchModule)
+ return {};
+ if (!type.isValid())
+ return {};
+ if (!type.isSingleton())
+ return {};
+
+ return d->singletonInstance<QJSValue>(type);
+}
+
/*!
Refreshes all binding expressions that use strings marked for translation.
@@ -1358,31 +1103,23 @@ QJSValue QQmlEngine::singletonInstance<QJSValue>(int qmlTypeId)
QCoreApplication::installTranslator, to ensure that your user-interface
shows up-to-date translations.
- \note Due to a limitation in the implementation, this function
- refreshes all the engine's bindings, not only those that use strings
- marked for translation.
- This may be optimized in a future release.
-
\since 5.10
*/
void QQmlEngine::retranslate()
{
Q_D(QQmlEngine);
- for (QQmlRefPointer<QQmlContextData> context
- = QQmlContextData::get(d->rootContext)->childContexts();
- context; context = context->nextChild()) {
- context->refreshExpressions();
- }
+ d->translationLanguage.notify();
}
/*!
- Returns the QQmlContext for the \a object, or 0 if no
+ Returns the QQmlContext for the \a object, or nullptr if no
context has been set.
- When the QQmlEngine instantiates a QObject, the context is
- set automatically.
+ When the QQmlEngine instantiates a QObject, an internal context is assigned
+ to it automatically. Such internal contexts are read-only. You cannot set
+ context properties on them.
- \sa qmlContext(), qmlEngine()
+ \sa qmlContext(), qmlEngine(), QQmlContext::setContextProperty()
*/
QQmlContext *QQmlEngine::contextForObject(const QObject *object)
{
@@ -1426,27 +1163,13 @@ void QQmlEngine::setContextForObject(QObject *object, QQmlContext *context)
*/
bool QQmlEngine::event(QEvent *e)
{
- Q_D(QQmlEngine);
- if (e->type() == QEvent::User)
- d->doDeleteInEngineThread();
- else if (e->type() == QEvent::LanguageChange) {
+ if (e->type() == QEvent::LanguageChange) {
retranslate();
}
return QJSEngine::event(e);
}
-void QQmlEnginePrivate::doDeleteInEngineThread()
-{
- QFieldList<Deletable, &Deletable::next> list;
- mutex.lock();
- list.copyAndClear(toDeleteInEngineThread);
- mutex.unlock();
-
- while (Deletable *d = list.takeFirst())
- delete d;
-}
-
class QQmlDataExtended {
public:
QQmlDataExtended();
@@ -1526,13 +1249,14 @@ void QQmlData::deferData(
deferData->context = context;
const QV4::CompiledData::Object *compiledObject = compilationUnit->objectAt(objectIndex);
- const QV4::BindingPropertyData &propertyData = compilationUnit->bindingPropertyDataPerObject.at(objectIndex);
+ const QV4::CompiledData::BindingPropertyData *propertyData
+ = compilationUnit->bindingPropertyDataPerObjectAt(objectIndex);
const QV4::CompiledData::Binding *binding = compiledObject->bindingTable();
for (quint32 i = 0; i < compiledObject->nBindings; ++i, ++binding) {
- const QQmlPropertyData *property = propertyData.at(i);
- if (property && binding->flags & QV4::CompiledData::Binding::IsDeferredBinding)
- deferData->bindings.insert(property->coreIndex(), binding);
+ const QQmlPropertyData *property = propertyData->at(i);
+ if (binding->hasFlag(QV4::CompiledData::Binding::IsDeferredBinding))
+ deferData->bindings.insert(property ? property->coreIndex() : -1, binding);
}
deferredData.append(deferData);
@@ -1554,49 +1278,73 @@ void QQmlData::releaseDeferredData()
void QQmlData::addNotify(int index, QQmlNotifierEndpoint *endpoint)
{
- if (!notifyList) {
- notifyList = (NotifyList *)malloc(sizeof(NotifyList));
- notifyList->connectionMask = 0;
- notifyList->maximumTodoIndex = 0;
- notifyList->notifiesSize = 0;
- notifyList->todo = nullptr;
- notifyList->notifies = nullptr;
+ // Can only happen on "home" thread. We apply relaxed semantics when loading the atomics.
+
+ NotifyList *list = notifyList.loadRelaxed();
+
+ if (!list) {
+ list = new NotifyList;
+ // We don't really care when this change takes effect on other threads. The notifyList can
+ // only become non-null once in the life time of a QQmlData. It becomes null again when the
+ // underlying QObject is deleted. At that point any interaction with the QQmlData is UB
+ // anyway. So, for all intents and purposese, the list becomes non-null once and then stays
+ // non-null "forever". We can apply relaxed semantics.
+ notifyList.storeRelaxed(list);
}
Q_ASSERT(!endpoint->isConnected());
index = qMin(index, 0xFFFF - 1);
- notifyList->connectionMask |= (1ULL << quint64(index % 64));
- if (index < notifyList->notifiesSize) {
+ // Likewise, we don't really care _when_ the change in the connectionMask is propagated to other
+ // threads. Cross-thread event ordering is inherently nondeterministic. Therefore, when querying
+ // the conenctionMask in the presence of concurrent modification, any result is correct.
+ list->connectionMask.storeRelaxed(
+ list->connectionMask.loadRelaxed() | (1ULL << quint64(index % 64)));
- endpoint->next = notifyList->notifies[index];
+ if (index < list->notifiesSize) {
+ endpoint->next = list->notifies[index];
if (endpoint->next) endpoint->next->prev = &endpoint->next;
- endpoint->prev = &notifyList->notifies[index];
- notifyList->notifies[index] = endpoint;
-
+ endpoint->prev = &list->notifies[index];
+ list->notifies[index] = endpoint;
} else {
- notifyList->maximumTodoIndex = qMax(int(notifyList->maximumTodoIndex), index);
+ list->maximumTodoIndex = qMax(int(list->maximumTodoIndex), index);
- endpoint->next = notifyList->todo;
+ endpoint->next = list->todo;
if (endpoint->next) endpoint->next->prev = &endpoint->next;
- endpoint->prev = &notifyList->todo;
- notifyList->todo = endpoint;
+ endpoint->prev = &list->todo;
+ list->todo = endpoint;
}
}
-void QQmlData::disconnectNotifiers()
+void QQmlData::disconnectNotifiers(QQmlData::DeleteNotifyList doDelete)
{
- if (notifyList) {
- while (notifyList->todo)
- notifyList->todo->disconnect();
- for (int ii = 0; ii < notifyList->notifiesSize; ++ii) {
- while (QQmlNotifierEndpoint *ep = notifyList->notifies[ii])
+ // Can only happen on "home" thread. We apply relaxed semantics when loading the atomics.
+ if (NotifyList *list = notifyList.loadRelaxed()) {
+ while (QQmlNotifierEndpoint *todo = list->todo)
+ todo->disconnect();
+ for (int ii = 0; ii < list->notifiesSize; ++ii) {
+ while (QQmlNotifierEndpoint *ep = list->notifies[ii])
ep->disconnect();
}
- free(notifyList->notifies);
- free(notifyList);
- notifyList = nullptr;
+ free(list->notifies);
+
+ if (doDelete == DeleteNotifyList::Yes) {
+ // We can only get here from QQmlData::destroyed(), and that can only come from the
+ // the QObject dtor. If you're still sending signals at that point you have UB already
+ // without any threads. Therefore, it's enough to apply relaxed semantics.
+ notifyList.storeRelaxed(nullptr);
+ delete list;
+ } else {
+ // We can use relaxed semantics here. The worst thing that can happen is that some
+ // signal is falsely reported as connected. Signal connectedness across threads
+ // is not quite deterministic anyway.
+ list->connectionMask.storeRelaxed(0);
+ list->maximumTodoIndex = 0;
+ list->notifiesSize = 0;
+ list->notifies = nullptr;
+
+ }
}
}
@@ -1623,7 +1371,7 @@ void QQmlData::destroyed(QObject *object)
if (bindings && !bindings->ref.deref())
delete bindings;
- compilationUnit = nullptr;
+ compilationUnit.reset();
qDeleteAll(deferredData);
deferredData.clear();
@@ -1670,17 +1418,18 @@ void QQmlData::destroyed(QObject *object)
free(bindingBits);
if (propertyCache)
- propertyCache->release();
+ propertyCache.reset();
- ownContext = nullptr;
+ ownContext.reset();
while (guards) {
- QQmlGuard<QObject> *guard = static_cast<QQmlGuard<QObject> *>(guards);
- *guard = (QObject *)nullptr;
- guard->objectDestroyed(object);
+ auto *guard = guards;
+ guard->setObject(nullptr);
+ if (guard->objectDestroyed)
+ guard->objectDestroyed(guard);
}
- disconnectNotifiers();
+ disconnectNotifiers(DeleteNotifyList::Yes);
if (extendedData)
delete extendedData;
@@ -1721,14 +1470,14 @@ QQmlData *QQmlData::createQQmlData(QObjectPrivate *priv)
{
Q_ASSERT(priv);
Q_ASSERT(!priv->isDeletingChildren);
- priv->declarativeData = new QQmlData;
+ priv->declarativeData = new QQmlData(OwnsMemory);
return static_cast<QQmlData *>(priv->declarativeData);
}
-QQmlPropertyCache *QQmlData::createPropertyCache(QJSEngine *engine, QObject *object)
+QQmlPropertyCache::ConstPtr QQmlData::createPropertyCache(QObject *object)
{
QQmlData *ddata = QQmlData::get(object, /*create*/true);
- ddata->propertyCache = QJSEnginePrivate::get(engine)->cache(object, QTypeRevision {}, true);
+ ddata->propertyCache = QQmlMetaType::propertyCache(object, QTypeRevision {});
return ddata->propertyCache;
}
@@ -1778,14 +1527,14 @@ static void dumpwarning(const QQmlError &error)
static void dumpwarning(const QList<QQmlError> &errors)
{
- for (int ii = 0; ii < errors.count(); ++ii)
+ for (int ii = 0; ii < errors.size(); ++ii)
dumpwarning(errors.at(ii));
}
void QQmlEnginePrivate::warning(const QQmlError &error)
{
Q_Q(QQmlEngine);
- q->warnings(QList<QQmlError>() << error);
+ emit q->warnings(QList<QQmlError>({error}));
if (outputWarningsToMsgLog)
dumpwarning(error);
}
@@ -1793,7 +1542,7 @@ void QQmlEnginePrivate::warning(const QQmlError &error)
void QQmlEnginePrivate::warning(const QList<QQmlError> &errors)
{
Q_Q(QQmlEngine);
- q->warnings(errors);
+ emit q->warnings(errors);
if (outputWarningsToMsgLog)
dumpwarning(errors);
}
@@ -1876,7 +1625,8 @@ void QQmlEnginePrivate::cleanupScarceResources()
The newly added \a path will be first in the importPathList().
- \sa setImportPathList(), {QML Modules}
+ \b {See also} \l setImportPathList(), \l {QML Modules},
+ and \l [QtQml] {QML Import Path}
*/
void QQmlEngine::addImportPath(const QString& path)
{
@@ -1894,9 +1644,8 @@ void QQmlEngine::addImportPath(const QString& path)
provided by that module. A \c qmldir file is required for defining the
type version mapping and possibly QML extensions plugins.
- By default, the list contains the directory of the application executable,
- paths specified in the \c QML_IMPORT_PATH environment variable,
- and the builtin \c QmlImportsPath from QLibraryInfo.
+ By default, this list contains the paths mentioned in
+ \l {QML Import Path}.
\sa addImportPath(), setImportPathList()
*/
@@ -1910,9 +1659,11 @@ QStringList QQmlEngine::importPathList() const
Sets \a paths as the list of directories where the engine searches for
installed modules in a URL-based directory structure.
- By default, the list contains the directory of the application executable,
- paths specified in the \c QML_IMPORT_PATH environment variable,
- and the builtin \c QmlImportsPath from QLibraryInfo.
+ By default, this list contains the paths mentioned in
+ \l {QML Import Path}.
+
+ \warning Calling setImportPathList does not preserve the default
+ import paths.
\sa importPathList(), addImportPath()
*/
@@ -1972,21 +1723,31 @@ void QQmlEngine::setPluginPathList(const QStringList &paths)
}
#if QT_CONFIG(library)
+#if QT_DEPRECATED_SINCE(6, 4)
/*!
+ \deprecated [6.4] Import the module from QML with an "import" statement instead.
+
Imports the plugin named \a filePath with the \a uri provided.
Returns true if the plugin was successfully imported; otherwise returns false.
On failure and if non-null, the \a errors list will have any errors which occurred prepended to it.
The plugin has to be a Qt plugin which implements the QQmlEngineExtensionPlugin interface.
+
+ \note Directly loading plugins like this can confuse the module import logic. In order to make
+ the import logic load plugins from a specific place, you can use \l addPluginPath(). Each
+ plugin should be part of a QML module that you can import using the "import" statement.
*/
bool QQmlEngine::importPlugin(const QString &filePath, const QString &uri, QList<QQmlError> *errors)
{
Q_D(QQmlEngine);
- return d->importDatabase.importDynamicPlugin(filePath, uri, QString(), QTypeRevision(), false,
- errors).isValid();
+ QQmlTypeLoaderQmldirContent qmldir;
+ QQmlPluginImporter importer(
+ uri, QTypeRevision(), &d->importDatabase, &qmldir, &d->typeLoader, errors);
+ return importer.importDynamicPlugin(filePath, uri, false).isValid();
}
#endif
+#endif
/*!
\property QQmlEngine::offlineStoragePath
@@ -1995,7 +1756,7 @@ bool QQmlEngine::importPlugin(const QString &filePath, const QString &uri, QList
Returns the directory where SQL and other offline
storage is placed.
- The SQL databases created with openDatabase() are stored here.
+ The SQL databases created with \c openDatabaseSync() are stored here.
The default is QML/OfflineStorage in the platform-standard
user application data directory.
@@ -2003,11 +1764,23 @@ bool QQmlEngine::importPlugin(const QString &filePath, const QString &uri, QList
Note that the path may not currently exist on the filesystem, so
callers wanting to \e create new files at this location should create
it first - see QDir::mkpath().
+
+ \sa {Qt Quick Local Storage QML Types}
+*/
+
+/*!
+ \fn void QQmlEngine::offlineStoragePathChanged()
+ This signal is emitted when \l offlineStoragePath changes.
+ \since 6.5
*/
+
void QQmlEngine::setOfflineStoragePath(const QString& dir)
{
Q_D(QQmlEngine);
+ if (dir == d->offlineStoragePath)
+ return;
d->offlineStoragePath = dir;
+ Q_EMIT offlineStoragePathChanged();
}
QString QQmlEngine::offlineStoragePath() const
@@ -2017,10 +1790,12 @@ QString QQmlEngine::offlineStoragePath() const
if (d->offlineStoragePath.isEmpty()) {
QString dataLocation = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation);
QQmlEnginePrivate *e = const_cast<QQmlEnginePrivate *>(d);
- if (!dataLocation.isEmpty())
+ if (!dataLocation.isEmpty()) {
e->offlineStoragePath = dataLocation.replace(QLatin1Char('/'), QDir::separator())
+ QDir::separator() + QLatin1String("QML")
+ QDir::separator() + QLatin1String("OfflineStorage");
+ Q_EMIT e->q_func()->offlineStoragePathChanged();
+ }
}
return d->offlineStoragePath;
@@ -2047,148 +1822,18 @@ QString QQmlEnginePrivate::offlineStorageDatabaseDirectory() const
return q->offlineStoragePath() + QDir::separator() + QLatin1String("Databases") + QDir::separator();
}
-static QQmlPropertyCache *propertyCacheForPotentialInlineComponentType(int t, const QHash<int, QV4::ExecutableCompilationUnit *>::const_iterator &iter) {
- if (t != (*iter)->typeIds.id.id()) {
- // this is an inline component, and what we have in the iterator is currently the parent compilation unit
- for (auto &&icDatum: (*iter)->inlineComponentData)
- if (icDatum.typeIds.id.id() == t)
- return (*iter)->propertyCaches.at(icDatum.objectIndex);
- }
- return (*iter)->rootPropertyCache().data();
-}
-
-/*!
- * \internal
- *
- * Look up by type's baseMetaObject.
- */
-QQmlMetaObject QQmlEnginePrivate::rawMetaObjectForType(int t) const
-{
- if (QQmlPropertyCache *composite = findPropertyCacheInCompositeTypes(t))
- return QQmlMetaObject(composite);
-
- QQmlType type = QQmlMetaType::qmlType(t);
- return QQmlMetaObject(type.baseMetaObject());
-}
-
-/*!
- * \internal
- *
- * Look up by type's metaObject.
- */
-QQmlMetaObject QQmlEnginePrivate::metaObjectForType(int t) const
-{
- if (QQmlPropertyCache *composite = findPropertyCacheInCompositeTypes(t))
- return QQmlMetaObject(composite);
-
- QQmlType type = QQmlMetaType::qmlType(t);
- return QQmlMetaObject(type.metaObject());
-}
-
-/*!
- * \internal
- *
- * Look up by type's metaObject and version.
- */
-QQmlPropertyCache *QQmlEnginePrivate::propertyCacheForType(int t)
-{
- if (QQmlPropertyCache *composite = findPropertyCacheInCompositeTypes(t))
- return composite;
-
- QQmlType type = QQmlMetaType::qmlType(t);
- return type.isValid() ? cache(type.metaObject(), type.version()) : nullptr;
-}
-
-/*!
- * \internal
- *
- * Look up by type's baseMetaObject and unspecified/any version.
- * TODO: Is this correct? Passing a plain QTypeRevision() rather than QTypeRevision::zero() or
- * the actual type's version seems strange. The behavior has been in place for a while.
- */
-QQmlPropertyCache *QQmlEnginePrivate::rawPropertyCacheForType(int t)
-{
- if (QQmlPropertyCache *composite = findPropertyCacheInCompositeTypes(t))
- return composite;
-
- QQmlType type = QQmlMetaType::qmlType(t);
- return type.isValid() ? cache(type.baseMetaObject(), QTypeRevision()) : nullptr;
-}
-
-/*!
- * \internal
- *
- * Look up by QQmlType and version. We only fall back to lookup by metaobject if the type
- * has no revisiononed attributes here. Unspecified versions are interpreted as "any".
- */
-QQmlPropertyCache *QQmlEnginePrivate::rawPropertyCacheForType(int t, QTypeRevision version)
-{
- if (QQmlPropertyCache *composite = findPropertyCacheInCompositeTypes(t))
- return composite;
-
- QQmlType type = QQmlMetaType::qmlType(t);
- if (!type.isValid())
- return nullptr;
-
- if (type.containsRevisionedAttributes())
- return QQmlMetaType::propertyCache(type, version);
-
- if (const QMetaObject *metaObject = type.metaObject())
- return cache(metaObject, version);
-
- return nullptr;
-}
-
-QQmlPropertyCache *QQmlEnginePrivate::findPropertyCacheInCompositeTypes(int t) const
-{
- Locker locker(this);
- auto iter = m_compositeTypes.constFind(t);
- return (iter == m_compositeTypes.constEnd())
- ? nullptr
- : propertyCacheForPotentialInlineComponentType(t, iter);
-}
-
-void QQmlEnginePrivate::registerInternalCompositeType(QV4::ExecutableCompilationUnit *compilationUnit)
-{
- compilationUnit->isRegisteredWithEngine = true;
-
- Locker locker(this);
- // The QQmlCompiledData is not referenced here, but it is removed from this
- // hash in the QQmlCompiledData destructor
- m_compositeTypes.insert(compilationUnit->typeIds.id.id(), compilationUnit);
- for (auto &&data: compilationUnit->inlineComponentData)
- m_compositeTypes.insert(data.typeIds.id.id(), compilationUnit);
-}
-
-void QQmlEnginePrivate::unregisterInternalCompositeType(QV4::ExecutableCompilationUnit *compilationUnit)
-{
- compilationUnit->isRegisteredWithEngine = false;
-
- Locker locker(this);
- m_compositeTypes.remove(compilationUnit->typeIds.id.id());
- for (auto&& icDatum: compilationUnit->inlineComponentData)
- m_compositeTypes.remove(icDatum.typeIds.id.id());
-}
-
-QV4::ExecutableCompilationUnit *QQmlEnginePrivate::obtainExecutableCompilationUnit(int typeId)
-{
- Locker locker(this);
- return m_compositeTypes.value(typeId, nullptr);
-}
-
template<>
QJSValue QQmlEnginePrivate::singletonInstance<QJSValue>(const QQmlType &type)
{
Q_Q(QQmlEngine);
- QJSValue value = singletonInstances.value(type);
- if (!value.isUndefined()) {
- return value;
- }
-
- QQmlType::SingletonInstanceInfo *siinfo = type.singletonInstanceInfo();
+ QQmlType::SingletonInstanceInfo::ConstPtr siinfo = type.singletonInstanceInfo();
Q_ASSERT(siinfo != nullptr);
+ QJSValue value = singletonInstances.value(siinfo);
+ if (!value.isUndefined())
+ return value;
+
if (siinfo->scriptCallback) {
value = siinfo->scriptCallback(q, q);
if (value.isQObject()) {
@@ -2197,7 +1842,7 @@ QJSValue QQmlEnginePrivate::singletonInstance<QJSValue>(const QQmlType &type)
// should behave identically to QML singleton types.
q->setContextForObject(o, new QQmlContext(q->rootContext(), q));
}
- singletonInstances.convertAndInsert(v4engine(), type, &value);
+ singletonInstances.convertAndInsert(v4engine(), siinfo, &value);
} else if (siinfo->qobjectCallback) {
QObject *o = siinfo->qobjectCallback(q, q);
@@ -2211,13 +1856,22 @@ QJSValue QQmlEnginePrivate::singletonInstance<QJSValue>(const QQmlType &type)
type.createProxy(o);
// if this object can use a property cache, create it now
- QQmlData::ensurePropertyCache(q, o);
+ QQmlData::ensurePropertyCache(o);
+
+ // even though the object is defined in C++, qmlContext(obj) and qmlEngine(obj)
+ // should behave identically to QML singleton types. You can, however, manually
+ // assign a context; and clearSingletons() retains the contexts, in which case
+ // we don't want to see warnings about the object already having a context.
+ QQmlData *data = QQmlData::get(o, true);
+ if (!data->context) {
+ auto contextData = QQmlContextData::get(new QQmlContext(q->rootContext(), q));
+ data->context = contextData.data();
+ contextData->addOwnedObject(data);
+ }
}
- // even though the object is defined in C++, qmlContext(obj) and qmlEngine(obj)
- // should behave identically to QML singleton types.
- q->setContextForObject(o, new QQmlContext(q->rootContext(), q));
+
value = q->newQObject(o);
- singletonInstances.convertAndInsert(v4engine(), type, &value);
+ singletonInstances.convertAndInsert(v4engine(), siinfo, &value);
} else if (!siinfo->url.isEmpty()) {
QQmlComponent component(q, siinfo->url, QQmlComponent::PreferSynchronous);
if (component.isError()) {
@@ -2228,26 +1882,13 @@ QJSValue QQmlEnginePrivate::singletonInstance<QJSValue>(const QQmlType &type)
}
QObject *o = component.beginCreate(q->rootContext());
value = q->newQObject(o);
- singletonInstances.convertAndInsert(v4engine(), type, &value);
+ singletonInstances.convertAndInsert(v4engine(), siinfo, &value);
component.completeCreate();
}
return value;
}
-void QQmlEnginePrivate::destroySingletonInstance(const QQmlType &type)
-{
- Q_ASSERT(type.isSingleton() || type.isCompositeSingleton());
-
- QObject* o = singletonInstances.take(type).toQObject();
- if (o) {
- QQmlData *ddata = QQmlData::get(o, false);
- if (type.singletonInstanceInfo()->url.isEmpty() && ddata && ddata->indestructible && ddata->explicitIndestructibleSet)
- return;
- delete o;
- }
-}
-
bool QQmlEnginePrivate::isTypeLoaded(const QUrl &url) const
{
return typeLoader.isTypeLoaded(url);
@@ -2258,28 +1899,111 @@ bool QQmlEnginePrivate::isScriptLoaded(const QUrl &url) const
return typeLoader.isScriptLoaded(url);
}
-QJSValue QQmlEnginePrivate::executeRuntimeFunction(const QUrl &url, qsizetype functionIndex,
- QObject *thisObject, int argc, void **args, QMetaType *types)
+void QQmlEnginePrivate::executeRuntimeFunction(const QUrl &url, qsizetype functionIndex,
+ QObject *thisObject, int argc, void **args,
+ QMetaType *types)
{
- Q_Q(QQmlEngine);
- if (const auto unit = typeLoader.getType(url)->compilationUnit()) {
- Q_ASSERT(functionIndex >= 0);
- Q_ASSERT(thisObject);
-
- if (!unit->engine)
- unit->linkToEngine(q->handle());
-
- if (unit->runtimeFunctions.length() <= functionIndex)
- return QJSValue();
-
- QQmlContext *ctx = q->contextForObject(thisObject);
- if (!ctx)
- ctx = q->rootContext();
- return QJSValuePrivate::fromReturnedValue(
- q->handle()->callInContext(unit->runtimeFunctions[functionIndex], thisObject,
- QQmlContextData::get(ctx), argc, args, types));
+ const auto unit = compilationUnitFromUrl(url);
+ if (!unit)
+ return;
+ executeRuntimeFunction(unit, functionIndex, thisObject, argc, args, types);
+}
+
+void QQmlEnginePrivate::executeRuntimeFunction(const QV4::ExecutableCompilationUnit *unit,
+ qsizetype functionIndex, QObject *thisObject,
+ int argc, void **args, QMetaType *types)
+{
+ Q_ASSERT(unit);
+ Q_ASSERT((functionIndex >= 0) && (functionIndex < unit->runtimeFunctions.size()));
+ Q_ASSERT(thisObject);
+
+ QQmlData *ddata = QQmlData::get(thisObject);
+ Q_ASSERT(ddata && ddata->outerContext);
+
+ QV4::Function *function = unit->runtimeFunctions[functionIndex];
+ Q_ASSERT(function);
+ Q_ASSERT(function->compiledFunction);
+
+ QV4::ExecutionEngine *v4 = v4engine();
+
+ // NB: always use scriptContext() by default as this method ignores whether
+ // there's already a stack frame (except when dealing with closures). the
+ // method is called from C++ (through QQmlEngine::executeRuntimeFunction())
+ // and thus the caller must ensure correct setup
+ QV4::Scope scope(v4);
+ QV4::ExecutionContext *ctx = v4->scriptContext();
+ QV4::Scoped<QV4::ExecutionContext> callContext(scope,
+ QV4::QmlContext::create(ctx, ddata->outerContext, thisObject));
+
+ if (auto nested = function->nestedFunction()) {
+ // if a nested function is already known, call the closure directly
+ function = nested;
+ } else if (function->isClosureWrapper()) {
+ // if there is a nested function, but we don't know it, we need to call
+ // an outer function first and then the inner function. we fetch the
+ // return value of a function call (that is a closure) by calling a
+ // different version of ExecutionEngine::callInContext() that returns a
+ // QV4::ReturnedValue with no arguments since they are not needed by the
+ // outer function anyhow
+ QV4::ScopedFunctionObject result(scope,
+ v4->callInContext(function, thisObject, callContext, 0, nullptr));
+ Q_ASSERT(result->function());
+ Q_ASSERT(result->function()->compilationUnit == function->compilationUnit);
+
+ // overwrite the function and its context
+ function = result->function();
+ callContext = QV4::Scoped<QV4::ExecutionContext>(scope, result->scope());
}
- return QJSValue();
+
+ v4->callInContext(function, thisObject, callContext, argc, args, types);
+}
+
+QV4::ExecutableCompilationUnit *QQmlEnginePrivate::compilationUnitFromUrl(const QUrl &url)
+{
+ QV4::ExecutionEngine *v4 = v4engine();
+ if (auto unit = v4->compilationUnitForUrl(url)) {
+ if (!unit->runtimeStrings)
+ unit->populate();
+ return unit.data();
+ }
+
+ auto unit = typeLoader.getType(url)->compilationUnit();
+ if (!unit)
+ return nullptr;
+
+ auto executable = v4->executableCompilationUnit(std::move(unit));
+ executable->populate();
+ return executable.data();
+}
+
+QQmlRefPointer<QQmlContextData>
+QQmlEnginePrivate::createInternalContext(const QQmlRefPointer<QV4::ExecutableCompilationUnit> &unit,
+ const QQmlRefPointer<QQmlContextData> &parentContext,
+ int subComponentIndex, bool isComponentRoot)
+{
+ Q_ASSERT(unit);
+
+ QQmlRefPointer<QQmlContextData> context;
+ context = QQmlContextData::createRefCounted(parentContext);
+ context->setInternal(true);
+ context->setImports(unit->typeNameCache());
+ context->initFromTypeCompilationUnit(unit, subComponentIndex);
+
+ const auto *dependentScripts = unit->dependentScriptsPtr();
+ const qsizetype dependentScriptsSize = dependentScripts->size();
+ if (isComponentRoot && dependentScriptsSize) {
+ QV4::ExecutionEngine *v4 = v4engine();
+ Q_ASSERT(v4);
+ QV4::Scope scope(v4);
+
+ QV4::ScopedObject scripts(scope, v4->newArrayObject(dependentScriptsSize));
+ context->setImportedScripts(QV4::PersistentValue(v4, scripts.asReturnedValue()));
+ QV4::ScopedValue v(scope);
+ for (qsizetype i = 0; i < dependentScriptsSize; ++i)
+ scripts->put(i, (v = dependentScripts->at(i)->scriptValueForContext(context)));
+ }
+
+ return context;
}
#if defined(Q_OS_WIN)
@@ -2389,6 +2113,53 @@ bool QQml_isFileCaseCorrect(const QString &fileName, int lengthIn /* = -1 */)
\sa {QQmlEngine::contextForObject()}{contextForObject()}, qmlEngine()
*/
+void hasJsOwnershipIndicator(QQmlGuardImpl *) {};
+
+LoadHelper::LoadHelper(QQmlTypeLoader *loader, QAnyStringView uri)
+ : QQmlTypeLoader::Blob({}, QQmlDataBlob::QmlFile, loader)
+ , m_uri(uri.toString())
+
+{
+ auto import = std::make_shared<PendingImport>();
+ import->uri = m_uri;
+ QList<QQmlError> errorList;
+ if (!Blob::addImport(import, &errorList)) {
+ qCDebug(lcQmlImport) << "LoadHelper: Errors loading " << m_uri << errorList;
+ m_uri.clear(); // reset m_uri to remember the failure
+ }
+}
+
+LoadHelper::ResolveTypeResult LoadHelper::resolveType(QAnyStringView typeName)
+{
+ QQmlType type;
+ if (!couldFindModule())
+ return {ResolveTypeResult::NoSuchModule, type};
+ QQmlTypeModule *module = QQmlMetaType::typeModule(m_uri, QTypeRevision{});
+ if (module) {
+ type = module->type(typeName.toString(), {});
+ if (type.isValid())
+ return {ResolveTypeResult::ModuleFound, type};
+ }
+ // The module exists (see check above), but there is no QQmlTypeModule
+ // ==> pure QML module, attempt resolveType
+ QTypeRevision versionReturn;
+ QList<QQmlError> errors;
+ QQmlImportNamespace *ns_return = nullptr;
+ m_importCache->resolveType(
+ typeLoader(), typeName.toString(), &type, &versionReturn, &ns_return, &errors);
+ return {ResolveTypeResult::ModuleFound, type};
+}
+
+bool LoadHelper::couldFindModule() const
+{
+ if (m_uri.isEmpty())
+ return false;
+ for (const auto &import: std::as_const(m_unresolvedImports))
+ if (import->priority == 0) // compare QQmlTypeData::allDependenciesDone
+ return false;
+ return true;
+}
+
QT_END_NAMESPACE
#include "moc_qqmlengine.cpp"
diff --git a/src/qml/qml/qqmlengine.h b/src/qml/qml/qqmlengine.h
index 37ca25779f..9c20090613 100644
--- a/src/qml/qml/qqmlengine.h
+++ b/src/qml/qml/qqmlengine.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLENGINE_H
#define QQMLENGINE_H
@@ -80,7 +44,6 @@ Q_DECLARE_OPERATORS_FOR_FLAGS(QQmlImageProviderBase::Flags)
class QQmlComponent;
class QQmlEnginePrivate;
-class QQmlImportsPrivate;
class QQmlExpression;
class QQmlContext;
class QQmlType;
@@ -92,7 +55,7 @@ class QQmlNetworkAccessManagerFactory;
class QQmlIncubationController;
class Q_QML_EXPORT QQmlEngine : public QJSEngine
{
- Q_PROPERTY(QString offlineStoragePath READ offlineStoragePath WRITE setOfflineStoragePath)
+ Q_PROPERTY(QString offlineStoragePath READ offlineStoragePath WRITE setOfflineStoragePath NOTIFY offlineStoragePathChanged)
Q_OBJECT
public:
explicit QQmlEngine(QObject *p = nullptr);
@@ -102,6 +65,7 @@ public:
void clearComponentCache();
void trimComponentCache();
+ void clearSingletons();
QStringList importPathList() const;
void setImportPathList(const QStringList &paths);
@@ -116,8 +80,11 @@ public:
#endif
#if QT_CONFIG(library)
+#if QT_DEPRECATED_SINCE(6, 4)
+ QT_DEPRECATED_VERSION_X_6_4("Import the module from QML instead")
bool importPlugin(const QString &filePath, const QString &uri, QList<QQmlError> *errors);
#endif
+#endif
#if QT_CONFIG(qml_network)
void setNetworkAccessManagerFactory(QQmlNetworkAccessManagerFactory *);
@@ -136,6 +103,7 @@ public:
void addUrlInterceptor(QQmlAbstractUrlInterceptor *urlInterceptor);
void removeUrlInterceptor(QQmlAbstractUrlInterceptor *urlInterceptor);
+ QList<QQmlAbstractUrlInterceptor *> urlInterceptors() const;
QUrl interceptUrl(const QUrl &url, QQmlAbstractUrlInterceptor::DataType type) const;
void addImageProvider(const QString &id, QQmlImageProviderBase *);
@@ -155,14 +123,22 @@ public:
bool outputWarningsToStandardError() const;
void setOutputWarningsToStandardError(bool);
+ void markCurrentFunctionAsTranslationBinding();
+
template<typename T>
T singletonInstance(int qmlTypeId);
+ template<typename T>
+ T singletonInstance(QAnyStringView moduleName, QAnyStringView typeName);
+
void captureProperty(QObject *object, const QMetaProperty &property) const;
public Q_SLOTS:
void retranslate();
+Q_SIGNALS:
+ void offlineStoragePathChanged();
+
public:
static QQmlContext *contextForObject(const QObject *);
static void setContextForObject(QObject *, QQmlContext *);
@@ -189,6 +165,15 @@ T QQmlEngine::singletonInstance(int qmlTypeId) {
return qobject_cast<T>(singletonInstance<QJSValue>(qmlTypeId).toQObject());
}
+template<>
+Q_QML_EXPORT QJSValue QQmlEngine::singletonInstance<QJSValue>(QAnyStringView uri, QAnyStringView typeName);
+
+template<typename T>
+T QQmlEngine::singletonInstance(QAnyStringView uri, QAnyStringView typeName)
+{
+ return qobject_cast<T>(singletonInstance<QJSValue>(uri, typeName).toQObject());
+}
+
QT_END_NAMESPACE
#endif // QQMLENGINE_H
diff --git a/src/qml/qml/qqmlengine_p.h b/src/qml/qml/qqmlengine_p.h
index 04ed50b2ee..7c820679ba 100644
--- a/src/qml/qml/qqmlengine_p.h
+++ b/src/qml/qml/qqmlengine_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLENGINE_P_H
#define QQMLENGINE_P_H
@@ -53,63 +17,46 @@
#include "qqmlengine.h"
-#include "qqmltypeloader_p.h"
-#include "qqmlimport_p.h"
-#include <private/qpodvector_p.h>
-#include "qqml.h"
-#include "qqmlvaluetype_p.h"
-#include "qqmlcontext.h"
-#include "qqmlcontextdata_p.h"
-#include "qqmlexpression.h"
-#include "qqmlproperty_p.h"
-#include "qqmlmetatype_p.h"
+#include <private/qfieldlist_p.h>
#include <private/qintrusivelist_p.h>
+#include <private/qjsengine_p.h>
+#include <private/qjsvalue_p.h>
+#include <private/qpodvector_p.h>
+#include <private/qqmldirparser_p.h>
+#include <private/qqmlimport_p.h>
+#include <private/qqmlmetatype_p.h>
+#include <private/qqmlnotifier_p.h>
+#include <private/qqmlproperty_p.h>
+#include <private/qqmltypeloader_p.h>
+#include <private/qqmlvaluetype_p.h>
#include <private/qrecyclepool_p.h>
-#include <private/qfieldlist_p.h>
#include <private/qv4engine_p.h>
-#include <private/qjsvalue_p.h>
+
+#include <QtQml/qqml.h>
+#include <QtQml/qqmlcontext.h>
#include <QtCore/qlist.h>
+#include <QtCore/qmetaobject.h>
+#include <QtCore/qmutex.h>
#include <QtCore/qpair.h>
+#include <QtCore/qpointer.h>
+#include <QtCore/qproperty.h>
#include <QtCore/qstack.h>
-#include <QtCore/qmutex.h>
#include <QtCore/qstring.h>
#include <QtCore/qthread.h>
-#include <private/qobject_p.h>
-
-#include <private/qjsengine_p.h>
-#include <private/qqmldirparser_p.h>
-
-#include <qproperty.h>
+#include <atomic>
QT_BEGIN_NAMESPACE
-class QQmlContext;
-class QQmlEngine;
-class QQmlContextPrivate;
-class QQmlExpression;
-class QQmlImportDatabase;
-class QNetworkReply;
class QNetworkAccessManager;
-class QQmlNetworkAccessManagerFactory;
-class QQmlTypeNameCache;
-class QQmlComponentAttached;
class QQmlDelayedError;
-class QQmlObjectCreator;
-class QDir;
class QQmlIncubator;
+class QQmlMetaObject;
+class QQmlNetworkAccessManagerFactory;
+class QQmlObjectCreator;
class QQmlProfiler;
class QQmlPropertyCapture;
-class QQmlMetaObject;
-
-struct QObjectForeign {
- Q_GADGET
- QML_FOREIGN(QObject)
- QML_NAMED_ELEMENT(QtObject)
- QML_ADDED_IN_VERSION(2, 0)
- Q_CLASSINFO("QML.Root", "QML")
-};
// This needs to be declared here so that the pool for it can live in QQmlEnginePrivate.
// The inline method definitions are in qqmljavascriptexpression_p.h
@@ -127,11 +74,20 @@ public:
};
struct QPropertyChangeTrigger : QPropertyObserver {
- QPropertyChangeTrigger(QQmlJavaScriptExpression *expression) : QPropertyObserver(&QPropertyChangeTrigger::trigger), m_expression(expression) {}
- QQmlJavaScriptExpression * m_expression;
- QObject *target = nullptr;
+ Q_DISABLE_COPY_MOVE(QPropertyChangeTrigger)
+
+ QPropertyChangeTrigger(QQmlJavaScriptExpression *expression)
+ : QPropertyObserver(&QPropertyChangeTrigger::trigger)
+ , m_expression(expression)
+ {
+ }
+
+ QPointer<QObject> target;
+ QQmlJavaScriptExpression *m_expression;
int propertyIndex = 0;
static void trigger(QPropertyObserver *, QUntypedPropertyData *);
+
+ QMetaProperty property() const;
};
struct TriggerList : QPropertyChangeTrigger {
@@ -141,11 +97,11 @@ struct TriggerList : QPropertyChangeTrigger {
TriggerList *next = nullptr;
};
-class Q_QML_PRIVATE_EXPORT QQmlEnginePrivate : public QJSEnginePrivate
+class Q_QML_EXPORT QQmlEnginePrivate : public QJSEnginePrivate
{
Q_DECLARE_PUBLIC(QQmlEngine)
public:
- QQmlEnginePrivate(QQmlEngine *);
+ explicit QQmlEnginePrivate(QQmlEngine *q) : importDatabase(q), typeLoader(q) {}
~QQmlEnginePrivate() override;
void init();
@@ -153,49 +109,48 @@ public:
// is just qmlClearTypeRegistrations (which can't be called while an engine exists)
static bool baseModulesUninitialized;
- QQmlPropertyCapture *propertyCapture;
+ QQmlPropertyCapture *propertyCapture = nullptr;
QRecyclePool<QQmlJavaScriptExpressionGuard> jsExpressionGuardPool;
QRecyclePool<TriggerList> qPropertyTriggerPool;
- QQmlContext *rootContext;
+ QQmlContext *rootContext = nullptr;
+ Q_OBJECT_BINDABLE_PROPERTY(QQmlEnginePrivate, QString, translationLanguage);
#if !QT_CONFIG(qml_debug)
static const quintptr profiler = 0;
#else
- QQmlProfiler *profiler;
+ QQmlProfiler *profiler = nullptr;
#endif
- bool outputWarningsToMsgLog;
+ bool outputWarningsToMsgLog = true;
// Bindings that have had errors during startup
- QQmlDelayedError *erroredBindings;
- int inProgressCreations;
+ QQmlDelayedError *erroredBindings = nullptr;
+ int inProgressCreations = 0;
QV4::ExecutionEngine *v4engine() const { return q_func()->handle(); }
#if QT_CONFIG(qml_worker_script)
- QThread *workerScriptEngine;
+ QThread *workerScriptEngine = nullptr;
#endif
QUrl baseUrl;
- typedef QPair<QPointer<QObject>,int> FinalizeCallback;
- void registerFinalizeCallback(QObject *obj, int index);
-
- QQmlObjectCreator *activeObjectCreator;
+ QQmlObjectCreator *activeObjectCreator = nullptr;
#if QT_CONFIG(qml_network)
QNetworkAccessManager *createNetworkAccessManager(QObject *parent) const;
QNetworkAccessManager *getNetworkAccessManager() const;
- mutable QNetworkAccessManager *networkAccessManager;
- mutable QQmlNetworkAccessManagerFactory *networkAccessManagerFactory;
+ mutable QNetworkAccessManager *networkAccessManager = nullptr;
+ mutable QQmlNetworkAccessManagerFactory *networkAccessManagerFactory = nullptr;
#endif
+ mutable QRecursiveMutex imageProviderMutex;
QHash<QString,QSharedPointer<QQmlImageProviderBase> > imageProviders;
QSharedPointer<QQmlImageProviderBase> imageProvider(const QString &providerId) const;
QList<QQmlAbstractUrlInterceptor *> urlInterceptors;
- int scarceResourcesRefCount;
+ int scarceResourcesRefCount = 0;
void referenceScarceResources();
void dereferenceScarceResources();
@@ -204,52 +159,24 @@ public:
QString offlineStoragePath;
- mutable quint32 uniqueId;
- inline quint32 getUniqueId() const {
- return uniqueId++;
- }
-
// Unfortunate workaround to avoid a circular dependency between
// qqmlengine_p.h and qqmlincubator_p.h
- struct Incubator : public QSharedData {
+ struct Incubator {
QIntrusiveListNode next;
- // Unfortunate workaround for MSVC
- QIntrusiveListNode nextWaitingFor;
};
QIntrusiveList<Incubator, &Incubator::next> incubatorList;
- unsigned int incubatorCount;
- QQmlIncubationController *incubationController;
+ unsigned int incubatorCount = 0;
+ QQmlIncubationController *incubationController = nullptr;
void incubate(QQmlIncubator &, const QQmlRefPointer<QQmlContextData> &);
// These methods may be called from any thread
- inline bool isEngineThread() const;
- inline static bool isEngineThread(const QQmlEngine *);
- template<typename T>
- inline void deleteInEngineThread(T *);
- template<typename T>
- inline static void deleteInEngineThread(QQmlEnginePrivate *, T *);
QString offlineStorageDatabaseDirectory() const;
- // These methods may be called from the loader thread
- inline QQmlPropertyCache *cache(const QQmlType &, QTypeRevision version);
- using QJSEnginePrivate::cache;
-
- // These methods may be called from the loader thread
- QQmlMetaObject rawMetaObjectForType(int) const;
- QQmlMetaObject metaObjectForType(int) const;
- QQmlPropertyCache *propertyCacheForType(int);
- QQmlPropertyCache *rawPropertyCacheForType(int);
- QQmlPropertyCache *rawPropertyCacheForType(int, QTypeRevision version);
- void registerInternalCompositeType(QV4::ExecutableCompilationUnit *compilationUnit);
- void unregisterInternalCompositeType(QV4::ExecutableCompilationUnit *compilationUnit);
- QV4::ExecutableCompilationUnit *obtainExecutableCompilationUnit(int typeId);
-
bool isTypeLoaded(const QUrl &url) const;
bool isScriptLoaded(const QUrl &url) const;
template <typename T>
T singletonInstance(const QQmlType &type);
- void destroySingletonInstance(const QQmlType &type);
void sendQuit();
void sendExit(int retCode = 0);
@@ -270,24 +197,22 @@ public:
static QList<QQmlError> qmlErrorFromDiagnostics(const QString &fileName, const QList<QQmlJS::DiagnosticMessage> &diagnosticMessages);
- static void defineModule();
-
static bool designerMode();
static void activateDesignerMode();
- static bool qml_debugging_enabled;
+ static std::atomic<bool> qml_debugging_enabled;
mutable QMutex networkAccessManagerMutex;
QQmlGadgetPtrWrapper *valueTypeInstance(QMetaType type)
{
int typeIndex = type.id();
- auto it = cachedValueTypeInstances.find(typeIndex);
- if (it != cachedValueTypeInstances.end())
+ auto it = cachedValueTypeInstances.constFind(typeIndex);
+ if (it != cachedValueTypeInstances.cend())
return *it;
if (QQmlValueType *valueType = QQmlMetaType::valueType(type)) {
- QQmlGadgetPtrWrapper *instance = new QQmlGadgetPtrWrapper(valueType, q_func());
+ QQmlGadgetPtrWrapper *instance = new QQmlGadgetPtrWrapper(valueType);
cachedValueTypeInstances.insert(typeIndex, instance);
return instance;
}
@@ -295,38 +220,81 @@ public:
return nullptr;
}
- QJSValue executeRuntimeFunction(const QUrl &url, qsizetype functionIndex, QObject *thisObject,
- int arcg=0, void **args = nullptr, QMetaType *types = nullptr);
+ void executeRuntimeFunction(const QUrl &url, qsizetype functionIndex, QObject *thisObject,
+ int argc = 0, void **args = nullptr, QMetaType *types = nullptr);
+ void executeRuntimeFunction(const QV4::ExecutableCompilationUnit *unit, qsizetype functionIndex,
+ QObject *thisObject, int argc = 0, void **args = nullptr,
+ QMetaType *types = nullptr);
+ QV4::ExecutableCompilationUnit *compilationUnitFromUrl(const QUrl &url);
+ QQmlRefPointer<QQmlContextData>
+ createInternalContext(const QQmlRefPointer<QV4::ExecutableCompilationUnit> &unit,
+ const QQmlRefPointer<QQmlContextData> &parentContext,
+ int subComponentIndex, bool isComponentRoot);
+ static void setInternalContext(QObject *This, const QQmlRefPointer<QQmlContextData> &context,
+ QQmlContextData::QmlObjectKind kind)
+ {
+ Q_ASSERT(This);
+ QQmlData *ddata = QQmlData::get(This, /*create*/ true);
+ // NB: copied from QQmlObjectCreator::createInstance()
+ //
+ // the if-statement logic to determine the kind is:
+ // if (static_cast<quint32>(index) == 0 || ddata->rootObjectInCreation || isInlineComponent)
+ // then QQmlContextData::DocumentRoot. here, we pass this through qmltc
+ context->installContext(ddata, kind);
+ Q_ASSERT(qmlEngine(This));
+ }
private:
- class SingletonInstances : private QHash<QQmlType, QJSValue>
+ class SingletonInstances : private QHash<QQmlType::SingletonInstanceInfo::ConstPtr, QJSValue>
{
public:
- void convertAndInsert(QV4::ExecutionEngine *engine, const QQmlType &type, QJSValue *value)
+ void convertAndInsert(
+ QV4::ExecutionEngine *engine, const QQmlType::SingletonInstanceInfo::ConstPtr &type,
+ QJSValue *value)
{
QJSValuePrivate::manageStringOnV4Heap(engine, value);
insert(type, *value);
}
- using QHash<QQmlType, QJSValue>::value;
- using QHash<QQmlType, QJSValue>::take;
+ void clear()
+ {
+ const auto canDelete = [](QObject *instance, const auto &siinfo) -> bool {
+ if (!instance)
+ return false;
+
+ if (!siinfo->url.isEmpty())
+ return true;
+
+ const auto *ddata = QQmlData::get(instance, false);
+ return !(ddata && ddata->indestructible && ddata->explicitIndestructibleSet);
+ };
+
+ for (auto it = constBegin(), end = constEnd(); it != end; ++it) {
+ auto *instance = it.value().toQObject();
+ if (canDelete(instance, it.key()))
+ QQmlData::markAsDeleted(instance);
+ }
+
+ for (auto it = constBegin(), end = constEnd(); it != end; ++it) {
+ QObject *instance = it.value().toQObject();
+
+ if (canDelete(instance, it.key()))
+ delete instance;
+ }
+
+ QHash<QQmlType::SingletonInstanceInfo::ConstPtr, QJSValue>::clear();
+ }
+
+ using QHash<QQmlType::SingletonInstanceInfo::ConstPtr, QJSValue>::value;
+ using QHash<QQmlType::SingletonInstanceInfo::ConstPtr, QJSValue>::take;
};
SingletonInstances singletonInstances;
QHash<int, QQmlGadgetPtrWrapper *> cachedValueTypeInstances;
- // These members must be protected by a QQmlEnginePrivate::Locker as they are required by
- // the threaded loader. Only access them through their respective accessor methods.
- QHash<int, QV4::ExecutableCompilationUnit *> m_compositeTypes;
static bool s_designerMode;
- // These members is protected by the full QQmlEnginePrivate::mutex mutex
- struct Deletable { Deletable():next(nullptr) {} virtual ~Deletable() {} Deletable *next; };
- QFieldList<Deletable, &Deletable::next> toDeleteInEngineThread;
- void doDeleteInEngineThread();
-
void cleanupScarceResources();
- QQmlPropertyCache *findPropertyCacheInCompositeTypes(int t) const;
};
/*
@@ -359,81 +327,6 @@ inline void QQmlEnginePrivate::dereferenceScarceResources()
}
}
-/*!
-Returns true if the calling thread is the QQmlEngine thread.
-*/
-bool QQmlEnginePrivate::isEngineThread() const
-{
-
- return QThread::currentThread() == q_ptr->thread();
-}
-
-/*!
-Returns true if the calling thread is the QQmlEngine \a engine thread.
-*/
-bool QQmlEnginePrivate::isEngineThread(const QQmlEngine *engine)
-{
- Q_ASSERT(engine);
- return QQmlEnginePrivate::get(engine)->isEngineThread();
-}
-
-/*!
-Delete \a value in the engine thread. If the calling thread is the engine
-thread, \a value will be deleted immediately.
-
-This method should be used for *any* type that has resources that need to
-be freed in the engine thread. This is generally types that use V8 handles.
-As there is some small overhead in checking the current thread, it is best
-practice to check if any V8 handles actually need to be freed and delete
-the instance directly if not.
-*/
-template<typename T>
-void QQmlEnginePrivate::deleteInEngineThread(T *value)
-{
- Q_ASSERT(value);
- if (isEngineThread()) {
- delete value;
- } else {
- struct I : public Deletable {
- I(T *value) : value(value) {}
- ~I() override { delete value; }
- T *value;
- };
- I *i = new I(value);
- mutex.lock();
- bool wasEmpty = toDeleteInEngineThread.isEmpty();
- toDeleteInEngineThread.append(i);
- mutex.unlock();
- if (wasEmpty)
- QCoreApplication::postEvent(q_ptr, new QEvent(QEvent::User));
- }
-}
-
-/*!
-Delete \a value in the \a engine thread. If the calling thread is the engine
-thread, \a value will be deleted immediately.
-*/
-template<typename T>
-void QQmlEnginePrivate::deleteInEngineThread(QQmlEnginePrivate *engine, T *value)
-{
- Q_ASSERT(engine);
- engine->deleteInEngineThread<T>(value);
-}
-
-/*!
-Returns a QQmlPropertyCache for \a type with \a minorVersion.
-
-The returned cache is not referenced, so if it is to be stored, call addref().
-*/
-QQmlPropertyCache *QQmlEnginePrivate::cache(const QQmlType &type, QTypeRevision version)
-{
- Q_ASSERT(type.isValid());
- Q_ASSERT(type.containsRevisionedAttributes());
-
- Locker locker(this);
- return QQmlMetaType::propertyCache(type, version);
-}
-
QV4::ExecutionEngine *QQmlEnginePrivate::getV4Engine(QQmlEngine *e)
{
Q_ASSERT(e);
@@ -491,13 +384,35 @@ QQmlEnginePrivate *QQmlEnginePrivate::get(QV4::ExecutionEngine *e)
}
template<>
-Q_QML_PRIVATE_EXPORT QJSValue QQmlEnginePrivate::singletonInstance<QJSValue>(const QQmlType &type);
+Q_QML_EXPORT QJSValue QQmlEnginePrivate::singletonInstance<QJSValue>(const QQmlType &type);
template<typename T>
T QQmlEnginePrivate::singletonInstance(const QQmlType &type) {
return qobject_cast<T>(singletonInstance<QJSValue>(type).toQObject());
}
+struct LoadHelper final : QQmlTypeLoader::Blob
+{
+ LoadHelper(QQmlTypeLoader *loader, QAnyStringView uri);
+
+ struct ResolveTypeResult
+ {
+ enum Status { NoSuchModule, ModuleFound } status;
+ QQmlType type;
+ };
+
+ ResolveTypeResult resolveType(QAnyStringView typeName);
+
+protected:
+ void dataReceived(const SourceCodeData &) final { Q_UNREACHABLE(); }
+ void initializeFromCachedUnit(const QQmlPrivate::CachedQmlUnit *) final { Q_UNREACHABLE(); }
+
+private:
+ bool couldFindModule() const;
+ QString m_uri;
+};
+
+
QT_END_NAMESPACE
#endif // QQMLENGINE_P_H
diff --git a/src/qml/qml/qqmlenumdata_p.h b/src/qml/qml/qqmlenumdata_p.h
index df99c2c1bc..be734acbee 100644
--- a/src/qml/qml/qqmlenumdata_p.h
+++ b/src/qml/qml/qqmlenumdata_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 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$
-**
-****************************************************************************/
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLENUMDATA_P_H
#define QQMLENUMDATA_P_H
diff --git a/src/qml/qml/qqmlenumvalue_p.h b/src/qml/qml/qqmlenumvalue_p.h
index ea0fc244cb..f5ea3c1a0e 100644
--- a/src/qml/qml/qqmlenumvalue_p.h
+++ b/src/qml/qml/qqmlenumvalue_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 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$
-**
-****************************************************************************/
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLENUMVALUE_P_H
#define QQMLENUMVALUE_P_H
@@ -52,6 +16,7 @@
//
#include <QtCore/qstring.h>
+#include <QtCore/private/qglobal_p.h>
QT_BEGIN_NAMESPACE
diff --git a/src/qml/qml/qqmlerror.cpp b/src/qml/qml/qqmlerror.cpp
index 099dccd5d0..415f8748f5 100644
--- a/src/qml/qml/qqmlerror.cpp
+++ b/src/qml/qml/qqmlerror.cpp
@@ -1,45 +1,8 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qqmlerror.h"
#include "qqmlfile.h"
-#include "qqmlsourcecoordinate_p.h"
#include <private/qqmljsdiagnosticmessage_p.h>
#include <QtCore/qdebug.h>
@@ -331,13 +294,13 @@ QDebug operator<<(QDebug debug, const QQmlError &error)
const QString code = stream.readAll();
const auto lines = QStringView{code}.split(QLatin1Char('\n'));
- if (lines.count() >= error.line()) {
+ if (lines.size() >= error.line()) {
const QStringView &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());
+ column = qMin(column, line.size());
QByteArray ind;
ind.reserve(column);
diff --git a/src/qml/qml/qqmlerror.h b/src/qml/qml/qqmlerror.h
index 53a28b244b..8ca57f1b99 100644
--- a/src/qml/qml/qqmlerror.h
+++ b/src/qml/qml/qqmlerror.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLERROR_H
#define QQMLERROR_H
@@ -47,7 +11,7 @@
QT_BEGIN_NAMESPACE
-// ### Qt 6: should this be called QQmlMessage, since it can have a message type?
+// ### Qt 7: should this be called QQmlMessage, since it can have a message type?
class QDebug;
class QQmlErrorPrivate;
class Q_QML_EXPORT QQmlError
@@ -55,9 +19,17 @@ class Q_QML_EXPORT QQmlError
public:
QQmlError();
QQmlError(const QQmlError &);
+ QQmlError(QQmlError &&other) noexcept
+ : d(std::exchange(other.d, nullptr))
+ {}
+
QQmlError &operator=(const QQmlError &);
+ QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_MOVE_AND_SWAP(QQmlError)
~QQmlError();
+ void swap(QQmlError &other)
+ { qt_ptr_swap(d, other.d); }
+
bool isValid() const;
QUrl url() const;
diff --git a/src/qml/qml/qqmlexpression.cpp b/src/qml/qml/qqmlexpression.cpp
index 5864c3245c..1cc734206e 100644
--- a/src/qml/qml/qqmlexpression.cpp
+++ b/src/qml/qml/qqmlexpression.cpp
@@ -1,48 +1,10 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qqmlexpression.h"
#include "qqmlexpression_p.h"
-#include "qqmlglobal_p.h"
#include "qqmlengine_p.h"
-#include "qqmlcontext_p.h"
#include "qqmlscriptstring_p.h"
#include "qqmlbinding_p.h"
#include <private/qqmlsourcecoordinate_p.h>
@@ -143,6 +105,14 @@ QQmlExpression::QQmlExpression(const QQmlScriptString &script, QQmlContext *ctxt
return;
const QQmlScriptStringPrivate *scriptPrivate = script.d.data();
+ if (!scriptPrivate) {
+ // A null QQmlScriptStringPrivate is an empty expression without context.
+ // We may still want the explicitly passed context, though.
+ if (ctxt)
+ d->init(QQmlContextData::get(ctxt), QString(), scope);
+ return;
+ }
+
if (!ctxt && (!scriptPrivate->context || !scriptPrivate->context->isValid()))
return;
@@ -206,7 +176,7 @@ QQmlExpression::~QQmlExpression()
}
/*!
- Returns the QQmlEngine this expression is associated with, or 0 if there
+ Returns the QQmlEngine this expression is associated with, or \nullptr if there
is no association or the QQmlEngine has been destroyed.
*/
QQmlEngine *QQmlExpression::engine() const
@@ -216,7 +186,7 @@ QQmlEngine *QQmlExpression::engine() const
}
/*!
- Returns the QQmlContext this expression is associated with, or 0 if there
+ Returns the QQmlContext this expression is associated with, or \nullptr if there
is no association or the QQmlContext has been destroyed.
*/
QQmlContext *QQmlExpression::context() const
@@ -281,7 +251,7 @@ QVariant QQmlExpressionPrivate::value(bool *isUndefined)
QV4::Scope scope(engine->handle());
QV4::ScopedValue result(scope, v4value(isUndefined));
if (!hasError())
- rv = scope.engine->toVariant(result, -1);
+ rv = QV4::ExecutionEngine::toVariant(result, QMetaType {});
}
ep->dereferenceScarceResources(); // "release" scarce resources if top-level expression evaluation is complete.
diff --git a/src/qml/qml/qqmlexpression.h b/src/qml/qml/qqmlexpression.h
index c9719aec52..c029c2069f 100644
--- a/src/qml/qml/qqmlexpression.h
+++ b/src/qml/qml/qqmlexpression.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLEXPRESSION_H
#define QQMLEXPRESSION_H
@@ -50,7 +14,6 @@ QT_BEGIN_NAMESPACE
class QString;
-class QQmlRefCount;
class QQmlEngine;
class QQmlContext;
class QQmlExpressionPrivate;
diff --git a/src/qml/qml/qqmlexpression_p.h b/src/qml/qml/qqmlexpression_p.h
index 3df839a6a2..740cb1b495 100644
--- a/src/qml/qml/qqmlexpression_p.h
+++ b/src/qml/qml/qqmlexpression_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLEXPRESSION_P_H
#define QQMLEXPRESSION_P_H
@@ -55,7 +19,6 @@
#include <private/qqmlengine_p.h>
#include <private/qfieldlist_p.h>
-#include <private/qflagpointer_p.h>
#include <private/qqmljavascriptexpression_p.h>
QT_BEGIN_NAMESPACE
@@ -76,6 +39,7 @@ public:
QVariant value(bool *isUndefined = nullptr);
QV4::ReturnedValue v4value(bool *isUndefined = nullptr);
+ bool mustCaptureBindableProperty() const final {return true;}
static inline QQmlExpressionPrivate *get(QQmlExpression *expr);
static inline QQmlExpression *get(QQmlExpressionPrivate *expr);
diff --git a/src/qml/qml/qqmlextensioninterface.cpp b/src/qml/qml/qqmlextensioninterface.cpp
new file mode 100644
index 0000000000..6cefcd3217
--- /dev/null
+++ b/src/qml/qml/qqmlextensioninterface.cpp
@@ -0,0 +1,17 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include <QtQml/qqmlextensioninterface.h>
+
+QT_BEGIN_NAMESPACE
+
+QQmlTypesExtensionInterface::~QQmlTypesExtensionInterface()
+ = default;
+
+QQmlExtensionInterface::~QQmlExtensionInterface()
+ = default;
+
+QQmlEngineExtensionInterface::~QQmlEngineExtensionInterface()
+ = default;
+
+QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlextensioninterface.h b/src/qml/qml/qqmlextensioninterface.h
index 1490bc512e..c7dfcae8bf 100644
--- a/src/qml/qml/qqmlextensioninterface.h
+++ b/src/qml/qml/qqmlextensioninterface.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLEXTENSIONINTERFACE_H
#define QQMLEXTENSIONINTERFACE_H
@@ -51,21 +15,21 @@ class QQmlEngine;
class Q_QML_EXPORT QQmlTypesExtensionInterface
{
public:
- virtual ~QQmlTypesExtensionInterface() = default;
+ virtual ~QQmlTypesExtensionInterface();
virtual void registerTypes(const char *uri) = 0;
};
class Q_QML_EXPORT QQmlExtensionInterface : public QQmlTypesExtensionInterface
{
public:
- ~QQmlExtensionInterface() override = default;
+ ~QQmlExtensionInterface() override;
virtual void initializeEngine(QQmlEngine *engine, const char *uri) = 0;
};
class Q_QML_EXPORT QQmlEngineExtensionInterface
{
public:
- virtual ~QQmlEngineExtensionInterface() = default;
+ virtual ~QQmlEngineExtensionInterface();
virtual void initializeEngine(QQmlEngine *engine, const char *uri) = 0;
};
diff --git a/src/qml/qml/qqmlextensionplugin.cpp b/src/qml/qml/qqmlextensionplugin.cpp
index f779199b74..5af51769ab 100644
--- a/src/qml/qml/qqmlextensionplugin.cpp
+++ b/src/qml/qml/qqmlextensionplugin.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qqmlextensionplugin.h"
#include "qqmlextensionplugin_p.h"
@@ -43,6 +7,21 @@
QT_BEGIN_NAMESPACE
/*!
+ \since 5.0
+ \inmodule QtQml
+ \class QQmlExtensionPlugin
+ \brief The QQmlExtensionPlugin class provides an abstract base for custom QML extension plugins
+ with custom type registration functions.
+
+ \ingroup plugins
+
+ \note If you need to write a plugin manually (which is rare) you should always use
+ \l{QQmlEngineExtensionPlugin}. QQmlExtensionPlugin only provides the registerTypes() and
+ unregisterTypes() functions in addition. You should not use them, but rather declare your
+ types with \l{QML_ELEMENT} and friends and have the build system take care of the registration.
+*/
+
+/*!
\since 5.14
\inmodule QtQml
\class QQmlEngineExtensionPlugin
@@ -61,11 +40,10 @@ QT_BEGIN_NAMESPACE
/*!
\fn void QQmlExtensionPlugin::registerTypes(const char *uri)
- \internal
Registers the QML types in the given \a uri. Subclasses should implement
- this to call qmlRegisterType() for all types which are provided by the extension
- plugin.
+ this to call \l {QQmlEngine::}{qmlRegisterType()} for all types which are
+ provided by the extension plugin.
The \a uri is an identifier for the plugin generated by the QML engine
based on the name and path of the extension's plugin library.
@@ -75,7 +53,11 @@ QT_BEGIN_NAMESPACE
\internal
*/
QQmlExtensionPlugin::QQmlExtensionPlugin(QObject *parent)
+#if QT_DEPRECATED_SINCE(6, 3)
: QObject(*(new QQmlExtensionPluginPrivate), parent)
+#else
+ : QObject(parent)
+#endif
{
}
@@ -102,19 +84,31 @@ QQmlExtensionPlugin::~QQmlExtensionPlugin() = default;
*/
QQmlEngineExtensionPlugin::~QQmlEngineExtensionPlugin() = default;
+#if QT_DEPRECATED_SINCE(6, 3)
/*!
\since 5.1
\internal
+ \deprecated [6.3] This is unnecessary and doesn't work for optional plugins
\brief Returns the URL of the directory from which the extension is loaded.
This is useful when the plugin also needs to load QML files or other
assets from the same directory.
+
+ \note You should not need this function. Other files that are part of the
+ module's public interface should be specified accordingly in the build
+ system and qmldir file. The build system makes sure that they end up
+ both in the final module directory, and in the resource file system.
+ You can use the copy from the resource file system in the plugin.
+ Non-QML/JS files private to the plugin can be added to the resource
+ file system manually. However, consider moving all such functionality
+ out of the plugin and making the plugin optional.
*/
QUrl QQmlExtensionPlugin::baseUrl() const
{
Q_D(const QQmlExtensionPlugin);
return d->baseUrl;
}
+#endif
/*!
\since 6.0
@@ -127,9 +121,10 @@ void QQmlExtensionPlugin::unregisterTypes()
}
/*!
- \internal
-*/
-
+ Initializes the extension from the \a uri using the \a engine. Here an application
+ plugin might, for example, expose some data or objects to QML,
+ as context properties on the engine's root context.
+ */
void QQmlExtensionPlugin::initializeEngine(QQmlEngine *engine, const char *uri)
{
Q_UNUSED(engine);
@@ -165,6 +160,30 @@ void QQmlEngineExtensionPlugin::initializeEngine(QQmlEngine *engine, const char
\inmodule QtQml
*/
+
+/*!
+ \macro Q_IMPORT_QML_PLUGIN(PluginName)
+ \since 6.2
+ \relates QQmlEngineExtensionPlugin
+
+ Ensures the plugin whose metadata-declaring plugin extension class is named
+ \a PluginName is linked into static builds. For the modules created using
+ \l qt_add_qml_module, the default plugin extension class name is computed
+ from the QML module URI by replacing dots with underscores, unless the
+ \c CLASS_NAME argument is specified.
+
+ For example:
+ \badcode
+ qt_add_qml_module(myplugin
+ # The plugin extension class name in this case is my_Company_QmlComponents.
+ URI my.Company.QmlComponents
+ ...
+ )
+ \endcode
+
+ \sa Q_IMPORT_PLUGIN
+*/
+
QT_END_NAMESPACE
#include "moc_qqmlextensionplugin.cpp"
diff --git a/src/qml/qml/qqmlextensionplugin.h b/src/qml/qml/qqmlextensionplugin.h
index 78371106bd..3d4494ba20 100644
--- a/src/qml/qml/qqmlextensionplugin.h
+++ b/src/qml/qml/qqmlextensionplugin.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLEXTENSIONPLUGIN_H
#define QQMLEXTENSIONPLUGIN_H
@@ -44,6 +8,15 @@
#include <QtCore/QUrl>
#include <QtQml/qqmlextensioninterface.h>
+#if defined(Q_CC_GHS)
+# define Q_GHS_KEEP_REFERENCE(S) QT_DO_PRAGMA(ghs reference S ##__Fv)
+#else
+# define Q_GHS_KEEP_REFERENCE(S)
+#endif
+
+#define Q_IMPORT_QML_PLUGIN(PLUGIN) \
+ Q_IMPORT_PLUGIN(PLUGIN)
+
QT_BEGIN_NAMESPACE
class QQmlEngine;
@@ -61,7 +34,10 @@ public:
explicit QQmlExtensionPlugin(QObject *parent = nullptr);
~QQmlExtensionPlugin() override;
+#if QT_DEPRECATED_SINCE(6, 3)
+ QT_DEPRECATED_VERSION_X_6_3("Provide a qmldir file to remove the need for calling baseUrl")
QUrl baseUrl() const;
+#endif
void registerTypes(const char *uri) override = 0;
virtual void unregisterTypes();
diff --git a/src/qml/qml/qqmlextensionplugin_p.h b/src/qml/qml/qqmlextensionplugin_p.h
index 2abb5547aa..468fa9e8f4 100644
--- a/src/qml/qml/qqmlextensionplugin_p.h
+++ b/src/qml/qml/qqmlextensionplugin_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLEXTENSIONPLUGIN_P_H
#define QQMLEXTENSIONPLUGIN_P_H
@@ -56,6 +20,7 @@
QT_BEGIN_NAMESPACE
+#if QT_DEPRECATED_SINCE(6, 3)
class QQmlExtensionPluginPrivate : public QObjectPrivate
{
Q_DECLARE_PUBLIC(QQmlExtensionPlugin)
@@ -66,6 +31,7 @@ public:
QUrl baseUrl;
};
+#endif
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlfile.cpp b/src/qml/qml/qqmlfile.cpp
index 4db8981975..bac70e69bb 100644
--- a/src/qml/qml/qqmlfile.cpp
+++ b/src/qml/qml/qqmlfile.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qqmlfile.h"
@@ -46,18 +10,27 @@
#include <private/qqmlengine_p.h>
#include <private/qqmlglobal_p.h>
-/*!
-\class QQmlFile
-\brief The QQmlFile class gives access to local and remote files.
+QT_BEGIN_NAMESPACE
-\internal
+/*!
+ \class QQmlFile
+ \inmodule QtQml
+ \since 5.0
+ \brief The QQmlFile class provides static utility methods to categorize URLs.
-Supports file:// and qrc:/ uris and whatever QNetworkAccessManager supports.
+ QQmlFile provides some static utility methods to categorize URLs
+ and file names the way \l{QQmlEngine} does when loading content from them.
*/
-#define QQMLFILE_MAX_REDIRECT_RECURSION 16
+/*!
+ \internal
-QT_BEGIN_NAMESPACE
+ \enum QQmlFile::Status
+ \value Null
+ \value Ready
+ \value Error
+ \value Loading
+ */
static char qrc_string[] = "qrc";
static char file_string[] = "file";
@@ -65,6 +38,9 @@ static char file_string[] = "file";
#if defined(Q_OS_ANDROID)
static char assets_string[] = "assets";
static char content_string[] = "content";
+static char authority_externalstorage[] = "com.android.externalstorage.documents";
+static char authority_downloads_documents[] = "com.android.providers.downloads.documents";
+static char authority_media_documents[] = "com.android.providers.media.documents";
#endif
class QQmlFilePrivate;
@@ -97,7 +73,6 @@ private:
QQmlEngine *m_engine;
QQmlFilePrivate *m_p;
- int m_redirectCount;
QNetworkReply *m_reply;
};
#endif
@@ -132,7 +107,7 @@ int QQmlFileNetworkReply::replyFinishedIndex = -1;
int QQmlFileNetworkReply::replyDownloadProgressIndex = -1;
QQmlFileNetworkReply::QQmlFileNetworkReply(QQmlEngine *e, QQmlFilePrivate *p, const QUrl &url)
-: m_engine(e), m_p(p), m_redirectCount(0), m_reply(nullptr)
+: m_engine(e), m_p(p), m_reply(nullptr)
{
if (finishedIndex == -1) {
finishedIndex = QMetaMethod::fromSignal(&QQmlFileNetworkReply::finished).methodIndex();
@@ -166,27 +141,6 @@ QQmlFileNetworkReply::~QQmlFileNetworkReply()
void QQmlFileNetworkReply::networkFinished()
{
- ++m_redirectCount;
- if (m_redirectCount < QQMLFILE_MAX_REDIRECT_RECURSION) {
- QVariant redirect = m_reply->attribute(QNetworkRequest::RedirectionTargetAttribute);
- if (redirect.isValid()) {
- QUrl url = m_reply->url().resolved(redirect.toUrl());
-
- QNetworkRequest req(url);
- req.setAttribute(QNetworkRequest::HttpPipeliningAllowedAttribute, true);
-
- m_reply->deleteLater();
- m_reply = m_engine->networkAccessManager()->get(req);
-
- QMetaObject::connect(m_reply, replyFinishedIndex,
- this, networkFinishedIndex);
- QMetaObject::connect(m_reply, replyDownloadProgressIndex,
- this, networkDownloadProgressIndex);
-
- return;
- }
- }
-
if (m_reply->error()) {
m_p->errorString = m_reply->errorString();
m_p->error = QQmlFilePrivate::Network;
@@ -216,22 +170,36 @@ QQmlFilePrivate::QQmlFilePrivate()
{
}
+/*!
+ \internal
+ */
QQmlFile::QQmlFile()
: d(new QQmlFilePrivate)
{
}
-QQmlFile::QQmlFile(QQmlEngine *e, const QUrl &url)
+/*!
+ \internal
+ Constructs a QQmlFile for content at \a url, using \a engine to retrieve it.
+ */
+QQmlFile::QQmlFile(QQmlEngine *engine, const QUrl &url)
: d(new QQmlFilePrivate)
{
- load(e, url);
+ load(engine, url);
}
-QQmlFile::QQmlFile(QQmlEngine *e, const QString &url)
- : QQmlFile(e, QUrl(url))
+/*!
+ \internal
+ Constructs a QQmlFile for content at \a url, using \a engine to retrieve it.
+ */
+QQmlFile::QQmlFile(QQmlEngine *engine, const QString &url)
+ : QQmlFile(engine, QUrl(url))
{
}
+/*!
+ \internal
+ */
QQmlFile::~QQmlFile()
{
#if QT_CONFIG(qml_network)
@@ -241,26 +209,41 @@ QQmlFile::~QQmlFile()
d = nullptr;
}
+/*!
+ \internal
+ */
bool QQmlFile::isNull() const
{
return status() == Null;
}
+/*!
+ \internal
+ */
bool QQmlFile::isReady() const
{
return status() == Ready;
}
+/*!
+ \internal
+ */
bool QQmlFile::isError() const
{
return status() == Error;
}
+/*!
+ \internal
+ */
bool QQmlFile::isLoading() const
{
return status() == Loading;
}
+/*!
+ \internal
+ */
QUrl QQmlFile::url() const
{
if (!d->urlString.isEmpty()) {
@@ -270,6 +253,9 @@ QUrl QQmlFile::url() const
return d->url;
}
+/*!
+ \internal
+ */
QQmlFile::Status QQmlFile::status() const
{
if (d->url.isEmpty() && d->urlString.isEmpty())
@@ -284,6 +270,9 @@ QQmlFile::Status QQmlFile::status() const
return Ready;
}
+/*!
+ \internal
+ */
QString QQmlFile::error() const
{
switch (d->error) {
@@ -297,21 +286,34 @@ QString QQmlFile::error() const
}
}
+/*!
+ \internal
+ */
qint64 QQmlFile::size() const
{
return d->data.size();
}
+/*!
+ \internal
+ */
const char *QQmlFile::data() const
{
return d->data.constData();
}
+/*!
+ \internal
+ */
QByteArray QQmlFile::dataByteArray() const
{
return d->data;
}
+/*!
+ \internal
+ Loads content at \a url using \a engine.
+ */
void QQmlFile::load(QQmlEngine *engine, const QUrl &url)
{
Q_ASSERT(engine);
@@ -342,6 +344,10 @@ void QQmlFile::load(QQmlEngine *engine, const QUrl &url)
}
}
+/*!
+ \internal
+ Loads content at \a url using \a engine.
+ */
void QQmlFile::load(QQmlEngine *engine, const QString &url)
{
Q_ASSERT(engine);
@@ -376,6 +382,9 @@ void QQmlFile::load(QQmlEngine *engine, const QString &url)
}
}
+/*!
+ \internal
+ */
void QQmlFile::clear()
{
d->url = QUrl();
@@ -384,12 +393,22 @@ void QQmlFile::clear()
d->error = QQmlFilePrivate::None;
}
-void QQmlFile::clear(QObject *)
+/*!
+ \internal
+ Redirects to the other clear() overload, ignoring \a object.
+ */
+void QQmlFile::clear(QObject *object)
{
+ Q_UNUSED(object);
clear();
}
#if QT_CONFIG(qml_network)
+
+/*!
+ \internal
+ Connects \a method of \a object to the internal \c{finished} signal.
+ */
bool QQmlFile::connectFinished(QObject *object, const char *method)
{
if (!d || !d->reply) {
@@ -397,10 +416,13 @@ bool QQmlFile::connectFinished(QObject *object, const char *method)
return false;
}
- return QObject::connect(d->reply, SIGNAL(finished()),
- object, method);
+ return QObject::connect(d->reply, SIGNAL(finished()), object, method);
}
+/*!
+ \internal
+ Connects \a method of \a object to the internal \c{finished} signal.
+ */
bool QQmlFile::connectFinished(QObject *object, int method)
{
if (!d || !d->reply) {
@@ -412,6 +434,10 @@ bool QQmlFile::connectFinished(QObject *object, int method)
object, method);
}
+/*!
+ \internal
+ Connects \a method of \a object to the internal \c{downloadProgress} signal.
+ */
bool QQmlFile::connectDownloadProgress(QObject *object, const char *method)
{
if (!d || !d->reply) {
@@ -423,6 +449,10 @@ bool QQmlFile::connectDownloadProgress(QObject *object, const char *method)
object, method);
}
+/*!
+ \internal
+ Connects \a method of \a object to the internal \c{downloadProgress} signal.
+ */
bool QQmlFile::connectDownloadProgress(QObject *object, int method)
{
if (!d || !d->reply) {
@@ -436,18 +466,21 @@ bool QQmlFile::connectDownloadProgress(QObject *object, int method)
#endif
/*!
-Returns true if QQmlFile will open \a url synchronously.
+ \internal
-Synchronous urls have a qrc:/ or file:// scheme.
+ Returns \c true if QQmlFile will open \a url synchronously.
+ Otherwise returns \c false. Synchronous urls have a \c{qrc:} or \c{file:}
+ scheme.
-\note On Android, urls with assets:/ scheme are also considered synchronous.
+ \note On Android, urls with \c{assets:} or \c{content:} scheme are also
+ considered synchronous.
*/
bool QQmlFile::isSynchronous(const QUrl &url)
{
QString scheme = url.scheme();
- if ((scheme.length() == 4 && 0 == scheme.compare(QLatin1String(file_string), Qt::CaseInsensitive)) ||
- (scheme.length() == 3 && 0 == scheme.compare(QLatin1String(qrc_string), Qt::CaseInsensitive))) {
+ if ((scheme.size() == 4 && 0 == scheme.compare(QLatin1String(file_string), Qt::CaseInsensitive)) ||
+ (scheme.size() == 3 && 0 == scheme.compare(QLatin1String(qrc_string), Qt::CaseInsensitive))) {
return true;
#if defined(Q_OS_ANDROID)
@@ -463,28 +496,31 @@ bool QQmlFile::isSynchronous(const QUrl &url)
}
/*!
-Returns true if QQmlFile will open \a url synchronously.
+ \internal
-Synchronous urls have a qrc:/ or file:// scheme.
+ Returns \c true if QQmlFile will open \a url synchronously.
+ Otherwise returns \c false. Synchronous urls have a \c{qrc:} or \c{file:}
+ scheme.
-\note On Android, urls with assets:/ scheme are also considered synchronous.
+ \note On Android, urls with \c{assets:} or \c{content:} scheme are also
+ considered synchronous.
*/
bool QQmlFile::isSynchronous(const QString &url)
{
- if (url.length() < 5 /* qrc:/ */)
+ if (url.size() < 5 /* qrc:/ */)
return false;
QChar f = url[0];
if (f == QLatin1Char('f') || f == QLatin1Char('F')) {
- return url.length() >= 7 /* file:// */ &&
+ return url.size() >= 7 /* file:// */ &&
url.startsWith(QLatin1String(file_string), Qt::CaseInsensitive) &&
url[4] == QLatin1Char(':') && url[5] == QLatin1Char('/') && url[6] == QLatin1Char('/');
} else if (f == QLatin1Char('q') || f == QLatin1Char('Q')) {
- return url.length() >= 5 /* qrc:/ */ &&
+ return url.size() >= 5 /* qrc:/ */ &&
url.startsWith(QLatin1String(qrc_string), Qt::CaseInsensitive) &&
url[3] == QLatin1Char(':') && url[4] == QLatin1Char('/');
@@ -505,76 +541,149 @@ bool QQmlFile::isSynchronous(const QString &url)
return false;
}
-/*!
-Returns true if \a url is a local file that can be opened with QFile.
+#if defined(Q_OS_ANDROID)
+static bool hasLocalContentAuthority(const QUrl &url)
+{
+ const QString authority = url.authority();
+ return authority.isEmpty()
+ || authority == QLatin1String(authority_externalstorage)
+ || authority == QLatin1String(authority_downloads_documents)
+ || authority == QLatin1String(authority_media_documents);
+}
+#endif
-Local file urls have either a qrc:/ or file:// scheme.
+/*!
+ Returns \c true if \a url is a local file that can be opened with \l{QFile}.
+ Otherwise returns \c false. Local file urls have either a \c{qrc:} or
+ \c{file:} scheme.
-\note On Android, urls with assets:/ scheme are also considered local files.
+ \note On Android, urls with \c{assets:} or \c{content:} scheme are also
+ considered local files.
*/
bool QQmlFile::isLocalFile(const QUrl &url)
{
QString scheme = url.scheme();
- if ((scheme.length() == 4 && 0 == scheme.compare(QLatin1String(file_string), Qt::CaseInsensitive)) ||
- (scheme.length() == 3 && 0 == scheme.compare(QLatin1String(qrc_string), Qt::CaseInsensitive))) {
+ // file: URLs with two slashes following the scheme can be interpreted as local files
+ // where the slashes are part of the path. Therefore, disregard the authority.
+ // See QUrl::toLocalFile().
+ if (scheme.size() == 4 && scheme.startsWith(QLatin1String(file_string), Qt::CaseInsensitive))
return true;
+ if (scheme.size() == 3 && scheme.startsWith(QLatin1String(qrc_string), Qt::CaseInsensitive))
+ return url.authority().isEmpty();
+
#if defined(Q_OS_ANDROID)
- } else if (scheme.length() == 6 && 0 == scheme.compare(QLatin1String(assets_string), Qt::CaseInsensitive)) {
- return true;
+ if (scheme.length() == 6
+ && scheme.startsWith(QLatin1String(assets_string), Qt::CaseInsensitive))
+ return url.authority().isEmpty();
+ if (scheme.length() == 7
+ && scheme.startsWith(QLatin1String(content_string), Qt::CaseInsensitive))
+ return hasLocalContentAuthority(url);
#endif
- } else {
- return false;
- }
+ return false;
}
-/*!
-Returns true if \a url is a local file that can be opened with QFile.
-
-Local file urls have either a qrc:/ or file:// scheme.
-
-\note On Android, urls with assets:/ scheme are also considered local files.
-*/
-bool QQmlFile::isLocalFile(const QString &url)
+static bool hasScheme(const QString &url, const char *scheme, qsizetype schemeLength)
{
- if (url.length() < 5 /* qrc:/ */)
+ const qsizetype urlLength = url.size();
+
+ if (urlLength < schemeLength + 1)
return false;
- QChar f = url[0];
+ if (!url.startsWith(QLatin1String(scheme, scheme + schemeLength), Qt::CaseInsensitive))
+ return false;
- if (f == QLatin1Char('f') || f == QLatin1Char('F')) {
+ if (url[schemeLength] != QLatin1Char(':'))
+ return false;
- return url.length() >= 7 /* file:// */ &&
- url.startsWith(QLatin1String(file_string), Qt::CaseInsensitive) &&
- url[4] == QLatin1Char(':') && url[5] == QLatin1Char('/') && url[6] == QLatin1Char('/');
+ return true;
+}
- } else if (f == QLatin1Char('q') || f == QLatin1Char('Q')) {
+static qsizetype authorityOffset(const QString &url, qsizetype schemeLength)
+{
+ const qsizetype urlLength = url.size();
- return url.length() >= 5 /* qrc:/ */ &&
- url.startsWith(QLatin1String(qrc_string), Qt::CaseInsensitive) &&
- url[3] == QLatin1Char(':') && url[4] == QLatin1Char('/');
+ if (urlLength < schemeLength + 3)
+ return -1;
+ const QLatin1Char slash('/');
+ if (url[schemeLength + 1] == slash && url[schemeLength + 2] == slash) {
+ // Exactly two slashes denote an authority.
+ if (urlLength < schemeLength + 4 || url[schemeLength + 3] != slash)
+ return schemeLength + 3;
}
+
+ return -1;
+}
+
#if defined(Q_OS_ANDROID)
- else if (f == QLatin1Char('a') || f == QLatin1Char('A')) {
- return url.length() >= 8 /* assets:/ */ &&
- url.startsWith(QLatin1String(assets_string), Qt::CaseInsensitive) &&
- url[6] == QLatin1Char(':') && url[7] == QLatin1Char('/');
- } else if (f == QLatin1Char('c') || f == QLatin1Char('C')) {
- return url.length() >= 9 /* content:/ */ &&
- url.startsWith(QLatin1String(content_string), Qt::CaseInsensitive) &&
- url[7] == QLatin1Char(':') && url[8] == QLatin1Char('/');
+static bool hasLocalContentAuthority(const QString &url, qsizetype schemeLength)
+{
+ const qsizetype offset = authorityOffset(url, schemeLength);
+ if (offset == -1)
+ return true; // no authority is a local authority.
+
+ const QString authorityAndPath = url.sliced(offset);
+ return authorityAndPath.startsWith(QLatin1String(authority_externalstorage))
+ || authorityAndPath.startsWith(QLatin1String(authority_downloads_documents))
+ || authorityAndPath.startsWith(QLatin1String(authority_media_documents));
+}
+
+#endif
+
+/*!
+ Returns \c true if \a url is a local file that can be opened with \l{QFile}.
+ Otherwise returns \c false. Local file urls have either a \c{qrc:} or
+ \c{file:} scheme.
+
+ \note On Android, urls with \c{assets:} or \c{content:} scheme are also considered
+ local files.
+*/
+bool QQmlFile::isLocalFile(const QString &url)
+{
+ if (url.size() < 4 /* qrc: */)
+ return false;
+
+ switch (url[0].toLatin1()) {
+ case 'f':
+ case 'F': {
+ // file: URLs with two slashes following the scheme can be interpreted as local files
+ // where the slashes are part of the path. Therefore, disregard the authority.
+ // See QUrl::toLocalFile().
+ const qsizetype fileLength = strlen(file_string);
+ return url.startsWith(QLatin1String(file_string, file_string + fileLength),
+ Qt::CaseInsensitive)
+ && url.size() > fileLength
+ && url[fileLength] == QLatin1Char(':');
}
+ case 'q':
+ case 'Q':
+ return hasScheme(url, qrc_string, strlen(qrc_string))
+ && authorityOffset(url, strlen(qrc_string)) == -1;
+#if defined(Q_OS_ANDROID)
+ case 'a':
+ case 'A':
+ return hasScheme(url, assets_string, strlen(assets_string))
+ && authorityOffset(url, strlen(assets_string)) == -1;
+ case 'c':
+ case 'C':
+ return hasScheme(url, content_string, strlen(content_string))
+ && hasLocalContentAuthority(url, strlen(content_string));
#endif
+ default:
+ break;
+ }
return false;
}
/*!
-If \a url is a local file returns a path suitable for passing to QFile. Otherwise returns an
-empty string.
+ If \a url is a local file returns a path suitable for passing to \l{QFile}.
+ Otherwise returns an empty string.
+
+ \sa isLocalFile
*/
QString QQmlFile::urlToLocalFileOrQrc(const QUrl& url)
{
@@ -585,15 +694,14 @@ QString QQmlFile::urlToLocalFileOrQrc(const QUrl& url)
}
#if defined(Q_OS_ANDROID)
- else if (url.scheme().compare(QLatin1String("assets"), Qt::CaseInsensitive) == 0) {
- if (url.authority().isEmpty())
+ if (url.scheme().compare(QLatin1String("assets"), Qt::CaseInsensitive) == 0)
+ return url.authority().isEmpty() ? url.toString() : QString();
+ if (url.scheme().compare(QLatin1String("content"), Qt::CaseInsensitive) == 0) {
+ if (hasLocalContentAuthority(url))
return url.toString();
return QString();
- } else if (url.scheme().compare(QLatin1String("content"), Qt::CaseInsensitive) == 0) {
- return url.toString();
}
#endif
-
return url.toLocalFile();
}
@@ -603,35 +711,59 @@ static QString toLocalFile(const QString &url)
if (!file.isLocalFile())
return QString();
- //XXX TODO: handle windows hostnames: "//servername/path/to/file.txt"
+ // QUrl::toLocalFile() interprets two slashes as part of the path.
+ // Therefore windows hostnames like "//servername/path/to/file.txt" are preserved.
return file.toLocalFile();
}
+static bool isDoubleSlashed(const QString &url, qsizetype offset)
+{
+ const qsizetype urlLength = url.size();
+ if (urlLength < offset + 2)
+ return false;
+
+ const QLatin1Char slash('/');
+ if (url[offset] != slash || url[offset + 1] != slash)
+ return false;
+
+ if (urlLength < offset + 3)
+ return true;
+
+ return url[offset + 2] != slash;
+}
+
/*!
-If \a url is a local file returns a path suitable for passing to QFile. Otherwise returns an
-empty string.
+ If \a url is a local file returns a path suitable for passing to \l{QFile}.
+ Otherwise returns an empty string.
+
+ \sa isLocalFile
*/
QString QQmlFile::urlToLocalFileOrQrc(const QString& url)
{
if (url.startsWith(QLatin1String("qrc://"), Qt::CaseInsensitive)) {
- if (url.length() > 6)
- return QLatin1Char(':') + QStringView{url}.mid(6);
- return QString();
+ // Exactly two slashes are bad because that's a URL authority.
+ // One slash is fine and >= 3 slashes are file.
+ if (url.size() == 6 || url[6] != QLatin1Char('/')) {
+ Q_ASSERT(isDoubleSlashed(url, strlen("qrc:")));
+ return QString();
+ }
+ Q_ASSERT(!isDoubleSlashed(url, strlen("qrc:")));
+ return QLatin1Char(':') + QStringView{url}.mid(6);
}
if (url.startsWith(QLatin1String("qrc:"), Qt::CaseInsensitive)) {
- if (url.length() > 4)
+ Q_ASSERT(!isDoubleSlashed(url, strlen("qrc:")));
+ if (url.size() > 4)
return QLatin1Char(':') + QStringView{url}.mid(4);
- return QString();
+ return QStringLiteral(":");
}
#if defined(Q_OS_ANDROID)
- else if (url.startsWith(QLatin1String("assets:"), Qt::CaseInsensitive)) {
- return url;
- } else if (url.startsWith(QLatin1String("content:"), Qt::CaseInsensitive)) {
- return url;
- }
+ if (url.startsWith(QLatin1String("assets:"), Qt::CaseInsensitive))
+ return isDoubleSlashed(url, strlen("assets:")) ? QString() : url;
+ if (hasScheme(url, content_string, strlen(content_string)))
+ return hasLocalContentAuthority(url, strlen(content_string)) ? url : QString();
#endif
return toLocalFile(url);
diff --git a/src/qml/qml/qqmlfile.h b/src/qml/qml/qqmlfile.h
index aec0981a95..af90e671a9 100644
--- a/src/qml/qml/qqmlfile.h
+++ b/src/qml/qml/qqmlfile.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLFILE_H
#define QQMLFILE_H
@@ -54,8 +18,8 @@ class Q_QML_EXPORT QQmlFile
{
public:
QQmlFile();
- QQmlFile(QQmlEngine *, const QUrl &);
- QQmlFile(QQmlEngine *, const QString &);
+ QQmlFile(QQmlEngine *engine, const QUrl &url);
+ QQmlFile(QQmlEngine *engine, const QString &url);
~QQmlFile();
enum Status { Null, Ready, Error, Loading };
@@ -78,7 +42,7 @@ public:
void load(QQmlEngine *, const QString &);
void clear();
- void clear(QObject *);
+ void clear(QObject *object);
#if QT_CONFIG(qml_network)
bool connectFinished(QObject *, const char *);
diff --git a/src/qml/qml/qqmlfileselector.cpp b/src/qml/qml/qqmlfileselector.cpp
index 4b773adc3e..1704e2d994 100644
--- a/src/qml/qml/qqmlfileselector.cpp
+++ b/src/qml/qml/qqmlfileselector.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 BlackBerry Limited. All rights reserved.
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 BlackBerry Limited. All rights reserved.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <QtCore/QFileSelector>
#include <QtQml/QQmlAbstractUrlInterceptor>
@@ -90,8 +54,7 @@ QT_BEGIN_NAMESPACE
directories used for selection must start with a '+' character, so you will not accidentally
trigger this feature unless you have directories with such names inside your project.
- If a new QQmlFileSelector is set on the engine, the old one will be replaced. Use
- \l QQmlFileSelector::get() to query or use the existing instance.
+ If a new QQmlFileSelector is set on the engine, the old one will be replaced.
*/
/*!
@@ -147,7 +110,7 @@ QQmlFileSelectorPrivate::~QQmlFileSelectorPrivate()
/*!
Sets the QFileSelector instance for use by the QQmlFileSelector to \a selector.
QQmlFileSelector does not take ownership of the new QFileSelector. To reset QQmlFileSelector
- to use its internal QFileSelector instance, call setSelector(0).
+ to use its internal QFileSelector instance, call setSelector(\nullptr).
*/
void QQmlFileSelector::setSelector(QFileSelector *selector)
@@ -180,7 +143,9 @@ void QQmlFileSelector::setExtraSelectors(const QStringList &strings)
#if QT_DEPRECATED_SINCE(6, 0)
/*!
- \deprecated
+ \deprecated [6.0] The file selector should not be accessed after it
+ is set. It may be in use. See below for further details.
+
Gets the QQmlFileSelector currently active on the target \a engine.
This method is deprecated. You should not retrieve the files selector from an
@@ -198,10 +163,7 @@ QQmlFileSelector* QQmlFileSelector::get(QQmlEngine* engine)
if (qobject_cast<QQmlApplicationEngine *>(engine)) {
auto *appEnginePrivate = static_cast<QQmlApplicationEnginePrivate *>(enginePrivate);
- if (!appEnginePrivate->isInitialized) {
- appEnginePrivate->init();
- appEnginePrivate->isInitialized = true;
- }
+ appEnginePrivate->ensureInitialized();
}
const QUrl nonEmptyInvalid(QLatin1String(":"));
diff --git a/src/qml/qml/qqmlfileselector.h b/src/qml/qml/qqmlfileselector.h
index 8ad565e49d..0509aa565a 100644
--- a/src/qml/qml/qqmlfileselector.h
+++ b/src/qml/qml/qqmlfileselector.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 BlackBerry Limited. All rights reserved.
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 BlackBerry Limited. All rights reserved.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLFILESELECTOR_H
#define QQMLFILESELECTOR_H
diff --git a/src/qml/qml/qqmlfileselector_p.h b/src/qml/qml/qqmlfileselector_p.h
index a7360f83d9..58696acef7 100644
--- a/src/qml/qml/qqmlfileselector_p.h
+++ b/src/qml/qml/qqmlfileselector_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 BlackBerry Limited. All rights reserved.
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 BlackBerry Limited. All rights reserved.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLFILESELECTOR_P_H
#define QQMLFILESELECTOR_P_H
@@ -57,11 +21,13 @@
#include <private/qobject_p.h>
#include <private/qtqmlglobal_p.h>
+#include <QtCore/qpointer.h>
+
QT_BEGIN_NAMESPACE
class QFileSelector;
class QQmlFileSelectorInterceptor;
-class Q_QML_PRIVATE_EXPORT QQmlFileSelectorPrivate : public QObjectPrivate
+class Q_QML_EXPORT QQmlFileSelectorPrivate : public QObjectPrivate
{
Q_DECLARE_PUBLIC(QQmlFileSelector)
public:
@@ -74,7 +40,7 @@ public:
QScopedPointer<QQmlFileSelectorInterceptor> myInstance;
};
-class Q_QML_PRIVATE_EXPORT QQmlFileSelectorInterceptor : public QQmlAbstractUrlInterceptor
+class Q_QML_EXPORT QQmlFileSelectorInterceptor : public QQmlAbstractUrlInterceptor
{
public:
QQmlFileSelectorInterceptor(QQmlFileSelectorPrivate* pd);
diff --git a/src/qml/qml/qqmlfinalizer.cpp b/src/qml/qml/qqmlfinalizer.cpp
new file mode 100644
index 0000000000..8b87b8955d
--- /dev/null
+++ b/src/qml/qml/qqmlfinalizer.cpp
@@ -0,0 +1,59 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include <private/qqmlfinalizer_p.h>
+
+QT_BEGIN_NAMESPACE
+
+QQmlFinalizerHook::~QQmlFinalizerHook() = default;
+
+/*!
+ \class QQmlFinalizerHook
+ \internal
+
+ QQmlFinalizerHook is an internal interface to run code after the current toplevel
+ component has been completed.
+ At first, this might look like QQmlParserStaus' componentComplete functionality
+ by another name - however there is a difference. To understand it, consider the
+ following QML file:
+
+ \qml
+ import QtQuick
+ Item {
+ id: root
+ Rectangle {
+ id: rect
+ Rectangle { id: innerRect }
+ }
+ property Item it: Item {id: myItem }
+ }
+ \endqml
+
+ This file will instantiate 4 (sub-)components: One for each of root, rect, innerRect
+ and myItem. If the component gets loaded in a synchronous way, each of their
+ componentComplete (if existent) would run directly one after another (in a non-specified
+ order).
+
+ However, in the case of an asynchronous instantiation, e.g. via a loader, we might interrupt
+ the (sub-)component construction partway: There can be a delay between the various
+ componentComplete calls, and not all sub-components might have been constructed yet.
+ QQmlFinalizerHook::componentFinalized is instead called after all asynchronously instantiated
+ (sub-)components have been constructed. Notably, all bindings of those components have also
+ been set up.
+
+ \note While the engine does not use qobject_cast, tooling still relies on the interface
+ being marked as such. Thus you should always use the Q_INTERFACES macro in classes deriving
+ from QQmlFinalizerHook.
+*/
+
+/*!
+ \fn void QQmlFinalizerHook::componentFinalized()
+
+ The customization point provided by this interface. See the class description for
+ why it is useful and how it compares to componentComplete.
+
+ \sa QQmlParserStatus::componentComplete
+
+ */
+
+QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlfinalizer_p.h b/src/qml/qml/qqmlfinalizer_p.h
new file mode 100644
index 0000000000..66fd85ddad
--- /dev/null
+++ b/src/qml/qml/qqmlfinalizer_p.h
@@ -0,0 +1,34 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QQMLFINALIZER_P_H
+#define QQMLFINALIZER_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 <QtQml/private/qtqmlglobal_p.h>
+#include <qobject.h>
+
+QT_BEGIN_NAMESPACE
+
+class Q_QML_EXPORT QQmlFinalizerHook
+{
+public:
+ virtual ~QQmlFinalizerHook();
+ virtual void componentFinalized() = 0;
+};
+#define QQmlFinalizerHook_iid "org.qt-project.Qt.QQmlFinalizerHook"
+Q_DECLARE_INTERFACE(QQmlFinalizerHook, QQmlFinalizerHook_iid)
+
+QT_END_NAMESPACE
+
+#endif // QQMLFINALIZER_P_H
diff --git a/src/qml/qml/qqmlglobal.cpp b/src/qml/qml/qqmlglobal.cpp
index d4473b7020..1273067187 100644
--- a/src/qml/qml/qqmlglobal.cpp
+++ b/src/qml/qml/qqmlglobal.cpp
@@ -1,69 +1,147 @@
-/****************************************************************************
-**
-** 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 <private/qqmlglobal_p.h>
-#include <QtQml/private/qqmlmetatype_p.h>
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+#include <QtQml/private/qjsvalue_p.h>
+#include <QtQml/private/qqmlglobal_p.h>
+#include <QtQml/private/qqmlmetatype_p.h>
#include <QtQml/qqmlengine.h>
-#include <QtCore/qvariant.h>
-#include <QtCore/qstringlist.h>
+
+#include <QtCore/private/qvariant_p.h>
+#include <QtCore/qcoreapplication.h>
#include <QtCore/qdebug.h>
-#include <QtCore/QCoreApplication>
+#include <QtCore/qstringlist.h>
QT_BEGIN_NAMESPACE
-bool QQmlValueTypeProvider::initValueType(int type, QVariant& dst)
+// Pre-filter the metatype before poking QQmlMetaType::qmlType() and locking its mutex.
+static bool isConstructibleMetaType(const QMetaType metaType)
{
- const QMetaType metaType(type);
- if (!metaType.isValid())
+ switch (metaType.id()) {
+ // The builtins are not constructible this way.
+ case QMetaType::Void:
+ case QMetaType::Nullptr:
+ case QMetaType::QVariant:
+ case QMetaType::Int:
+ case QMetaType::UInt:
+ case QMetaType::LongLong:
+ case QMetaType::ULongLong:
+ case QMetaType::Float:
+ case QMetaType::Double:
+ case QMetaType::Long:
+ case QMetaType::ULong:
+ case QMetaType::Short:
+ case QMetaType::UShort:
+ case QMetaType::Char:
+ case QMetaType::SChar:
+ case QMetaType::UChar:
+ case QMetaType::QChar:
+ case QMetaType::QString:
+ case QMetaType::Bool:
+ case QMetaType::QDateTime:
+ case QMetaType::QDate:
+ case QMetaType::QTime:
+ case QMetaType::QUrl:
+ case QMetaType::QRegularExpression:
+ case QMetaType::QByteArray:
+ case QMetaType::QLocale:
return false;
- dst = QVariant(QMetaType(type));
+ default:
+ break;
+ }
+
+ // QJSValue is also builtin
+ if (metaType == QMetaType::fromType<QJSValue>())
+ return false;
+
+ // We also don't want to construct pointers of any kind, or lists, or enums.
+ if (metaType.flags() &
+ (QMetaType::PointerToQObject
+ | QMetaType::IsEnumeration
+ | QMetaType::SharedPointerToQObject
+ | QMetaType::WeakPointerToQObject
+ | QMetaType::TrackingPointerToQObject
+ | QMetaType::IsUnsignedEnumeration
+ | QMetaType::PointerToGadget
+ | QMetaType::IsPointer
+ | QMetaType::IsQmlList)) {
+ return false;
+ }
+
return true;
}
-bool QQmlValueTypeProvider::createValueType(int type, const QJSValue &s, QVariant &data)
+static void *createVariantData(QMetaType type, QVariant *variant)
{
- const QQmlType qmlType = QQmlMetaType::qmlType(type, QQmlMetaType::TypeIdCategory::MetaType);
- if (auto valueTypeFunction = qmlType.createValueTypeFunction()) {
- QVariant result = valueTypeFunction(s);
- if (result.userType() == type) {
- data = std::move(result);
+ const QtPrivate::QMetaTypeInterface *iface = type.iface();
+ QVariant::Private *d = &variant->data_ptr();
+ Q_ASSERT(d->is_null && !d->is_shared);
+ *d = QVariant::Private(iface);
+ if (QVariant::Private::canUseInternalSpace(iface))
+ return d->data.data;
+
+ // This is not exception safe.
+ // If your value type throws an exception from its ctor bad things will happen anyway.
+ d->data.shared = QVariant::PrivateShared::create(iface->size, iface->alignment);
+ d->is_shared = true;
+ return d->data.shared->data();
+}
+
+static void callConstructor(
+ const QMetaObject *targetMetaObject, int i, void *source, void *target)
+{
+ void *p[] = { target, source };
+ targetMetaObject->static_metacall(QMetaObject::ConstructInPlace, i, p);
+}
+
+template<typename Allocate>
+static void fromVerifiedType(
+ const QMetaObject *targetMetaObject, int ctorIndex, void *source, Allocate &&allocate)
+{
+ const QMetaMethod ctor = targetMetaObject->constructor(ctorIndex);
+ Q_ASSERT_X(ctor.parameterCount() == 1, "fromVerifiedType",
+ "Value type constructor must take exactly one argument");
+ callConstructor(targetMetaObject, ctorIndex, source, allocate());
+}
+
+
+template<typename Allocate, typename Retrieve>
+static bool fromMatchingType(
+ const QMetaObject *targetMetaObject, Allocate &&allocate, Retrieve &&retrieve)
+{
+ for (int i = 0, end = targetMetaObject->constructorCount(); i < end; ++i) {
+ const QMetaMethod ctor = targetMetaObject->constructor(i);
+ if (ctor.parameterCount() != 1)
+ continue;
+
+ const QMetaType parameterType = ctor.parameterMetaType(0);
+
+ if (retrieve(parameterType, [&](QMetaType sourceMetaType, void *sourceData) {
+ if (sourceMetaType == parameterType) {
+ callConstructor(targetMetaObject, i, sourceData, allocate());
+ return true;
+ }
+
+ if (const QMetaObject *parameterMetaObject = parameterType.metaObject()) {
+ if (const QMetaObject *sourceMetaObject = sourceMetaType.metaObject();
+ sourceMetaObject && sourceMetaObject->inherits(parameterMetaObject)) {
+ // Allow construction from derived types.
+ callConstructor(targetMetaObject, i, sourceData, allocate());
+ return true;
+ }
+ }
+
+ // Do not recursively try to create parameters here. This may end up in infinite recursion.
+
+ // At this point, s should be a builtin type. For builtin types
+ // the QMetaType converters are good enough.
+ QVariant converted(parameterType);
+ if (QMetaType::convert(sourceMetaType, sourceData, parameterType, converted.data())) {
+ callConstructor(targetMetaObject, i, converted.data(), allocate());
+ return true;
+ }
+
+ return false;
+ })) {
return true;
}
}
@@ -71,40 +149,598 @@ bool QQmlValueTypeProvider::createValueType(int type, const QJSValue &s, QVarian
return false;
}
-bool QQmlValueTypeProvider::equalValueType(int type, const void *lhs, const QVariant& rhs)
+template<typename Allocate>
+static bool fromMatchingType(
+ const QMetaObject *targetMetaObject, const QV4::Value &source, Allocate &&allocate)
+{
+ return fromMatchingType(
+ targetMetaObject, std::forward<Allocate>(allocate),
+ [&](QMetaType parameterType, auto callback) {
+ QVariant variant = QV4::ExecutionEngine::toVariant(source, parameterType);
+ return callback(variant.metaType(), variant.data());
+ });
+}
+
+template<typename Allocate>
+static bool fromMatchingType(
+ const QMetaObject *targetMetaObject, QVariant source, Allocate &&allocate)
+{
+ return fromMatchingType(targetMetaObject, std::forward<Allocate>(allocate),
+ [&](QMetaType, auto callback) {
+ return callback(source.metaType(), source.data());
+ });
+}
+
+template<typename Allocate>
+static bool fromString(const QMetaObject *mo, QString s, Allocate &&allocate)
+{
+ for (int i = 0, end = mo->constructorCount(); i < end; ++i) {
+ const QMetaMethod ctor = mo->constructor(i);
+ if (ctor.parameterCount() != 1)
+ continue;
+
+ if (ctor.parameterMetaType(0) == QMetaType::fromType<QString>()) {
+ callConstructor(mo, i, &s, allocate());
+ return true;
+ }
+ }
+
+ return false;
+}
+
+template<typename Get, typename Convert>
+static bool doWriteProperty(const QMetaProperty &metaProperty, void *target,
+ Get &&get, Convert &&convert)
+{
+ const QMetaType propertyType = metaProperty.metaType();
+ QVariant property = get(propertyType);
+ if (property.metaType() == propertyType) {
+ metaProperty.writeOnGadget(target, std::move(property));
+ return true;
+ }
+
+ QVariant converted = convert(propertyType);
+ if (converted.isValid()) {
+ metaProperty.writeOnGadget(target, std::move(converted));
+ return true;
+ }
+
+ converted = QVariant(propertyType);
+ if (QMetaType::convert(property.metaType(), property.constData(),
+ propertyType, converted.data())) {
+ metaProperty.writeOnGadget(target, std::move(converted));
+ return true;
+ }
+
+ return false;
+}
+
+static void doWriteProperties(
+ const QMetaObject *targetMetaObject, void *target, const QV4::Value &source)
+{
+ const QV4::Object *o = static_cast<const QV4::Object *>(&source);
+ QV4::Scope scope(o->engine());
+ QV4::ScopedObject object(scope, o);
+
+ for (int i = 0; i < targetMetaObject->propertyCount(); ++i) {
+ const QMetaProperty metaProperty = targetMetaObject->property(i);
+ const QString propertyName = QString::fromUtf8(metaProperty.name());
+
+ QV4::ScopedString v4PropName(scope, scope.engine->newString(propertyName));
+ QV4::ScopedValue v4PropValue(scope, object->get(v4PropName));
+
+ // We assume that data is freshly constructed.
+ // There is no point in reset()'ing properties of a freshly created object.
+ if (v4PropValue->isUndefined())
+ continue;
+
+ if (doWriteProperty(metaProperty, target, [&](const QMetaType &propertyType) {
+ return QV4::ExecutionEngine::toVariant(v4PropValue, propertyType);
+ }, [&](const QMetaType &propertyType) {
+ return QQmlValueTypeProvider::createValueType(v4PropValue, propertyType);
+ })) {
+ continue;
+ }
+
+ const QMetaType propertyType = metaProperty.metaType();
+ QVariant property = QV4::ExecutionEngine::toVariant(v4PropValue, propertyType);
+ if (property.metaType() == propertyType) {
+ metaProperty.writeOnGadget(target, std::move(property));
+ continue;
+ }
+
+ QVariant converted = QQmlValueTypeProvider::createValueType(v4PropValue, propertyType);
+ if (converted.isValid()) {
+ metaProperty.writeOnGadget(target, std::move(converted));
+ continue;
+ }
+
+ converted = QVariant(propertyType);
+ if (QMetaType::convert(property.metaType(), property.constData(),
+ propertyType, converted.data())) {
+ metaProperty.writeOnGadget(target, std::move(converted));
+ continue;
+ }
+
+ qWarning().noquote()
+ << QLatin1String("Could not convert %1 to %2 for property %3")
+ .arg(v4PropValue->toQStringNoThrow(), QString::fromUtf8(propertyType.name()),
+ propertyName);
+ }
+}
+
+static QVariant byProperties(
+ const QMetaObject *targetMetaObject, QMetaType metaType, const QV4::Value &source)
{
- Q_ASSERT(lhs);
- return QMetaType(type).equals(lhs, rhs.constData());
+ if (!source.isObject() || !targetMetaObject)
+ return QVariant();
+
+ QVariant result(metaType);
+ doWriteProperties(targetMetaObject, result.data(), source);
+ return result;
}
-bool QQmlValueTypeProvider::readValueType(const QVariant& src, void *dst, int type)
+template<typename Read>
+static void doWriteProperties(
+ const QMetaObject *targetMetaObject, void *target,
+ const QMetaObject *sourceMetaObject, Read &&read)
+{
+ for (int i = 0; i < targetMetaObject->propertyCount(); ++i) {
+ const QMetaProperty metaProperty = targetMetaObject->property(i);
+
+ const int sourceProperty = sourceMetaObject->indexOfProperty(metaProperty.name());
+
+ // We assume that data is freshly constructed.
+ // There is no point in reset()'ing properties of a freshly created object.
+ if (sourceProperty == -1)
+ continue;
+
+ const QMetaType propertyType = metaProperty.metaType();
+ QVariant property = read(sourceMetaObject, sourceProperty);
+ if (property.metaType() == propertyType) {
+ metaProperty.writeOnGadget(target, std::move(property));
+ continue;
+ }
+
+ QVariant converted = QQmlValueTypeProvider::createValueType(property, propertyType);
+ if (converted.isValid()) {
+ metaProperty.writeOnGadget(target, std::move(converted));
+ continue;
+ }
+
+ converted = QVariant(propertyType);
+ if (QMetaType::convert(property.metaType(), property.constData(),
+ propertyType, converted.data())) {
+ metaProperty.writeOnGadget(target, std::move(converted));
+ continue;
+ }
+
+ qWarning().noquote()
+ << QLatin1String("Could not convert %1 to %2 for property %3")
+ .arg(property.toString(), QString::fromUtf8(propertyType.name()),
+ QString::fromUtf8(metaProperty.name()));
+ }
+}
+
+
+static void doWriteProperties(const QMetaObject *targetMeta, void *target, QObject *source)
{
- Q_ASSERT(dst);
- const QMetaType dstType(type);
- if (!dstType.isValid() || (src.metaType() == dstType && dstType.equals(src.constData(), dst)))
+ doWriteProperties(
+ targetMeta, target, source->metaObject(),
+ [source](const QMetaObject *sourceMetaObject, int sourceProperty) {
+ return sourceMetaObject->property(sourceProperty).read(source);
+ });
+}
+
+static QVariant byProperties(
+ const QMetaObject *targetMetaObject, QMetaType targetMetaType, QObject *source)
+{
+ if (!source || !targetMetaObject)
+ return QVariant();
+
+ QVariant result(targetMetaType);
+ doWriteProperties(targetMetaObject, result.data(), source);
+ return result;
+}
+
+static QVariant byProperties(
+ const QMetaObject *targetMetaObject, QMetaType targetMetaType,
+ const QMetaObject *sourceMetaObject, const void *source)
+{
+ if (!source || !sourceMetaObject || !targetMetaObject)
+ return QVariant();
+
+ QVariant result(targetMetaType);
+ doWriteProperties(
+ targetMetaObject, result.data(), sourceMetaObject,
+ [source](const QMetaObject *sourceMetaObject, int sourceProperty) {
+ return sourceMetaObject->property(sourceProperty).readOnGadget(source);
+ });
+ return result;
+}
+
+template<typename Map>
+void doWriteProperties(const QMetaObject *targetMetaObject, void *target, const Map &source)
+{
+ for (int i = 0; i < targetMetaObject->propertyCount(); ++i) {
+ const QMetaProperty metaProperty = targetMetaObject->property(i);
+
+ // We assume that data is freshly constructed.
+ // There is no point in reset()'ing properties of a freshly created object.
+ const auto it = source.constFind(QString::fromUtf8(metaProperty.name()));
+ if (it == source.constEnd())
+ continue;
+
+ const QMetaType propertyType = metaProperty.metaType();
+ QVariant property = *it;
+ if (property.metaType() == propertyType) {
+ metaProperty.writeOnGadget(target, std::move(property));
+ continue;
+ }
+
+ QVariant converted = QQmlValueTypeProvider::createValueType(property, propertyType);
+ if (converted.isValid()) {
+ metaProperty.writeOnGadget(target, std::move(converted));
+ continue;
+ }
+
+ converted = QVariant(propertyType);
+ if (QMetaType::convert(property.metaType(), property.constData(),
+ propertyType, converted.data())) {
+ metaProperty.writeOnGadget(target, std::move(converted));
+ continue;
+ }
+
+ qWarning().noquote()
+ << QLatin1String("Could not convert %1 to %2 for property %3")
+ .arg(property.toString(), QString::fromUtf8(propertyType.name()),
+ QString::fromUtf8(metaProperty.name()));
+ }
+}
+
+template<typename Map>
+QVariant byProperties(
+ const QMetaObject *targetMetaObject, QMetaType targetMetaType, const Map &source)
+{
+ QVariant result(targetMetaType);
+ doWriteProperties(targetMetaObject, result.data(), source);
+ return result;
+}
+
+static QVariant byProperties(
+ const QMetaObject *targetMetaObject, QMetaType targetMetaType, const QVariant &source)
+{
+ if (!targetMetaObject)
+ return QVariant();
+
+ if (source.metaType() == QMetaType::fromType<QJSValue>()) {
+ QJSValue val = source.value<QJSValue>();
+ return byProperties(
+ targetMetaObject, targetMetaType, QV4::Value(QJSValuePrivate::asReturnedValue(&val)));
+ }
+
+ if (source.metaType() == QMetaType::fromType<QVariantMap>()) {
+ return byProperties(
+ targetMetaObject, targetMetaType,
+ *static_cast<const QVariantMap *>(source.constData()));
+ }
+
+ if (source.metaType() == QMetaType::fromType<QVariantHash>()) {
+ return byProperties(
+ targetMetaObject, targetMetaType,
+ *static_cast<const QVariantHash *>(source.constData()));
+ }
+
+ if (source.metaType().flags() & QMetaType::PointerToQObject)
+ return byProperties(targetMetaObject, targetMetaType, source.value<QObject *>());
+
+ if (const QMetaObject *sourceMeta = QQmlMetaType::metaObjectForValueType(source.metaType()))
+ return byProperties(targetMetaObject, targetMetaType, sourceMeta, source.constData());
+
+ return QVariant();
+}
+
+template<typename Allocate, typename DefaultConstruct>
+bool createOrConstructValueType(
+ const QQmlType &targetType, const QV4::Value &source,
+ Allocate &&allocate, DefaultConstruct &&defaultConstruct)
+{
+ const auto warn = [&](const QMetaObject *targetMetaObject) {
+ qWarning().noquote()
+ << "Could not find any constructor for value type"
+ << targetMetaObject->className() << "to call with value"
+ << source.toQStringNoThrow();
+ };
+
+ if (targetType.canPopulateValueType()) {
+ if (const QMetaObject *targetMetaObject = targetType.metaObjectForValueType()) {
+ if (source.isObject()) {
+ doWriteProperties(targetMetaObject, defaultConstruct(), source);
+ return true;
+ }
+ if (targetType.canConstructValueType()) {
+ if (fromMatchingType(targetMetaObject, source, allocate))
+ return true;
+ warn(targetMetaObject);
+ }
+ }
+ } else if (targetType.canConstructValueType()) {
+ if (const QMetaObject *targetMetaObject = targetType.metaObjectForValueType()) {
+ if (fromMatchingType(targetMetaObject, source, allocate))
+ return true;
+ warn(targetMetaObject);
+ }
+ }
+
+ if (const auto valueTypeFunction = targetType.createValueTypeFunction()) {
+ const QVariant result
+ = valueTypeFunction(QJSValuePrivate::fromReturnedValue(source.asReturnedValue()));
+ const QMetaType resultType = result.metaType();
+ if (resultType == targetType.typeId()) {
+ resultType.construct(allocate(), result.constData());
+ return true;
+ }
+ }
+
+ return false;
+}
+
+template<typename Allocate, typename DefaultConstruct>
+bool createOrConstructValueType(
+ const QQmlType &targetType, QMetaType sourceMetaType, void *source,
+ Allocate &&allocate, DefaultConstruct &&defaultConstruct)
+{
+
+ const auto warn = [&](const QMetaObject *targetMetaObject) {
+ qWarning().noquote()
+ << "Could not find any constructor for value type"
+ << targetMetaObject->className() << "to call with value" << source;
+ };
+
+ if (targetType.canPopulateValueType()) {
+ if (const QMetaObject *targetMetaObject = targetType.metaObjectForValueType()) {
+ if (const QMetaObject *sourceMetaObject
+ = QQmlMetaType::metaObjectForValueType(sourceMetaType)) {
+ doWriteProperties(
+ targetMetaObject, defaultConstruct(), sourceMetaObject,
+ [&source](const QMetaObject *sourceMetaObject, int sourceProperty) {
+ return sourceMetaObject->property(sourceProperty).readOnGadget(source);
+ });
+ return true;
+ }
+
+ if (sourceMetaType == QMetaType::fromType<QVariantMap>()) {
+ doWriteProperties(
+ targetMetaObject, defaultConstruct(),
+ *static_cast<const QVariantMap *>(source));
+ return true;
+ }
+
+ if (sourceMetaType == QMetaType::fromType<QVariantHash>()) {
+ doWriteProperties(
+ targetMetaObject, defaultConstruct(),
+ *static_cast<const QVariantHash *>(source));
+ return true;
+ }
+
+ if (sourceMetaType.flags() & QMetaType::PointerToQObject) {
+ doWriteProperties(
+ targetMetaObject, defaultConstruct(),
+ *static_cast<QObject *const *>(source));
+ return true;
+ }
+ }
+ }
+
+ if (targetType.canConstructValueType()) {
+ if (const QMetaObject *targetMetaObject = targetType.metaObjectForValueType()) {
+ if (fromMatchingType(targetMetaObject, std::forward<Allocate>(allocate),
+ [&](QMetaType, auto callback) {
+ return callback(sourceMetaType, source);
+ })) {
+ return true;
+ }
+ warn(targetMetaObject);
+ }
+ }
+
+ return false;
+}
+
+/*!
+ * \internal
+ * Populate the value type in place at \a target, which is expected to be
+ * allocated and default-constructed, for example the result of a QVariant(QMetaType).
+ * This is efficient if we can do byProperties() since it can use the pre-constructed object.
+ * It also avoids the creation of a QVariant in most cases. It is not
+ * efficient if you're going to create a QVariant anyway.
+ */
+bool QQmlValueTypeProvider::populateValueType(
+ QMetaType targetMetaType, void *target, QMetaType sourceMetaType, void *source)
+{
+ if (sourceMetaType == QMetaType::fromType<QJSValue>()) {
+ const QJSValue *val = static_cast<const QJSValue *>(source);
+ return populateValueType(
+ targetMetaType, target, QV4::Value(QJSValuePrivate::asReturnedValue(val)));
+ }
+
+ if (!isConstructibleMetaType(targetMetaType))
return false;
- dstType.destruct(dst);
- dstType.construct(dst, src.metaType() == dstType ? src.constData() : nullptr);
- return true;
+ return createOrConstructValueType(
+ QQmlMetaType::qmlType(targetMetaType), sourceMetaType, source,
+ [targetMetaType, target]() {
+ targetMetaType.destruct(target);
+ return target;
+ }, [target]() {
+ return target;
+ });
}
-bool QQmlValueTypeProvider::writeValueType(int type, const void *src, QVariant& dst)
+/*!
+ * \internal
+ * Populate the value type in place at \a target, which is expected to be
+ * allocated and default-constructed, for example the result of a QVariant(QMetaType).
+ * This is efficient if we can do byProperties() since it can use the pre-constructed object.
+ * It also avoids the creation of a QVariant in most cases. It is not
+ * efficient if you're going to create a QVariant anyway.
+ */
+bool QQmlValueTypeProvider::populateValueType(
+ QMetaType targetMetaType, void *target, const QV4::Value &source)
{
- Q_ASSERT(src);
- const QMetaType srcType(type);
- if (!srcType.isValid() || (dst.metaType() == srcType && srcType.equals(src, dst.constData())))
+ if (!isConstructibleMetaType(targetMetaType))
return false;
- dst = QVariant(srcType, src);
- return true;
+ return createOrConstructValueType(
+ QQmlMetaType::qmlType(targetMetaType), source, [targetMetaType, target]() {
+ targetMetaType.destruct(target);
+ return target;
+ }, [target]() {
+ return target;
+ });
+}
+
+/*!
+ * \internal
+ * Specialization that constructs the value type on the heap using new and returns a pointer to it.
+ */
+void *QQmlValueTypeProvider::heapCreateValueType(
+ const QQmlType &targetType, const QV4::Value &source)
+{
+ void *target = nullptr;
+ if (createOrConstructValueType(
+ targetType, source, [&]() {
+ const QMetaType metaType = targetType.typeId();
+ const ushort align = metaType.alignOf();
+ target = align > __STDCPP_DEFAULT_NEW_ALIGNMENT__
+ ? operator new(metaType.sizeOf(), std::align_val_t(align))
+ : operator new(metaType.sizeOf());
+ return target;
+ }, [&]() {
+ target = targetType.typeId().create();
+ return target;
+ })) {
+ Q_ASSERT(target != nullptr);
+ }
+
+ return target;
}
-Q_GLOBAL_STATIC(QQmlValueTypeProvider, valueTypeProvider)
+QVariant QQmlValueTypeProvider::constructValueType(
+ QMetaType targetMetaType, const QMetaObject *targetMetaObject,
+ int ctorIndex, void *ctorArg)
+{
+ QVariant result;
+ fromVerifiedType(targetMetaObject, ctorIndex, ctorArg,
+ [&]() { return createVariantData(targetMetaType, &result); });
+ return result;
+}
-Q_AUTOTEST_EXPORT QQmlValueTypeProvider *QQml_valueTypeProvider()
+static QVariant fromJSValue(const QQmlType &type, const QJSValue &s, QMetaType metaType)
{
- return valueTypeProvider();
+ if (const auto valueTypeFunction = type.createValueTypeFunction()) {
+ const QVariant result = valueTypeFunction(s);
+ if (result.metaType() == metaType)
+ return result;
+ }
+
+ return QVariant();
+}
+
+QVariant QQmlValueTypeProvider::createValueType(const QJSValue &s, QMetaType metaType)
+{
+ if (!isConstructibleMetaType(metaType))
+ return QVariant();
+ return fromJSValue(QQmlMetaType::qmlType(metaType), s, metaType);
+}
+
+QVariant QQmlValueTypeProvider::createValueType(const QString &s, QMetaType metaType)
+{
+ if (!isConstructibleMetaType(metaType))
+ return QVariant();
+ const QQmlType type = QQmlMetaType::qmlType(metaType);
+ if (type.canConstructValueType()) {
+ if (const QMetaObject *mo = type.metaObjectForValueType()) {
+ QVariant result;
+ if (fromString(mo, s, [&]() { return createVariantData(metaType, &result); }))
+ return result;
+ }
+ }
+
+ return fromJSValue(type, s, metaType);
+}
+
+QVariant QQmlValueTypeProvider::createValueType(const QV4::Value &s, QMetaType metaType)
+{
+ if (!isConstructibleMetaType(metaType))
+ return QVariant();
+ const QQmlType type = QQmlMetaType::qmlType(metaType);
+ const auto warn = [&](const QMetaObject *mo) {
+ qWarning().noquote()
+ << "Could not find any constructor for value type"
+ << mo->className() << "to call with value" << s.toQStringNoThrow();
+ };
+
+ if (type.canPopulateValueType()) {
+ if (const QMetaObject *mo = type.metaObject()) {
+ QVariant result = byProperties(mo, metaType, s);
+ if (result.isValid())
+ return result;
+ if (type.canConstructValueType()) {
+ if (fromMatchingType(mo, s, [&]() { return createVariantData(metaType, &result); }))
+ return result;
+ warn(mo);
+ }
+ }
+ } else if (type.canConstructValueType()) {
+ if (const QMetaObject *mo = type.metaObject()) {
+ QVariant result;
+ if (fromMatchingType(mo, s, [&]() { return createVariantData(metaType, &result); }))
+ return result;
+ warn(mo);
+ }
+ }
+
+ return fromJSValue(type, QJSValuePrivate::fromReturnedValue(s.asReturnedValue()), metaType);
+
+}
+
+/*!
+ * \internal
+ * This should only be called with either builtin types or wrapped QJSValues as source.
+ */
+QVariant QQmlValueTypeProvider::createValueType(const QVariant &s, QMetaType metaType)
+{
+ if (!isConstructibleMetaType(metaType))
+ return QVariant();
+ const QQmlType type = QQmlMetaType::qmlType(metaType);
+ const auto warn = [&](const QMetaObject *mo) {
+ qWarning().noquote()
+ << "Could not find any constructor for value type"
+ << mo->className() << "to call with value" << s;
+ };
+
+ if (type.canPopulateValueType()) {
+ if (const QMetaObject *mo = type.metaObjectForValueType()) {
+ QVariant result = byProperties(mo, metaType, s);
+ if (result.isValid())
+ return result;
+ if (type.canConstructValueType()) {
+ if (fromMatchingType(mo, s, [&]() { return createVariantData(metaType, &result); }))
+ return result;
+ warn(mo);
+ }
+ }
+ } else if (type.canConstructValueType()) {
+ if (const QMetaObject *mo = type.metaObjectForValueType()) {
+ QVariant result;
+ if (fromMatchingType(mo, s, [&]() { return createVariantData(metaType, &result); }))
+ return result;
+ warn(mo);
+ }
+ }
+
+ return QVariant();
}
QQmlColorProvider::~QQmlColorProvider() {}
@@ -123,7 +759,7 @@ QVariant QQmlColorProvider::tint(const QVariant &, const QVariant &) { return QV
static QQmlColorProvider *colorProvider = nullptr;
-Q_QML_PRIVATE_EXPORT QQmlColorProvider *QQml_setColorProvider(QQmlColorProvider *newProvider)
+Q_QML_EXPORT QQmlColorProvider *QQml_setColorProvider(QQmlColorProvider *newProvider)
{
QQmlColorProvider *old = colorProvider;
colorProvider = newProvider;
@@ -177,7 +813,7 @@ QString QQmlGuiProvider::pluginName() const { return QString(); }
static QQmlGuiProvider *guiProvider = nullptr;
-Q_QML_PRIVATE_EXPORT QQmlGuiProvider *QQml_setGuiProvider(QQmlGuiProvider *newProvider)
+Q_QML_EXPORT QQmlGuiProvider *QQml_setGuiProvider(QQmlGuiProvider *newProvider)
{
QQmlGuiProvider *old = guiProvider;
guiProvider = newProvider;
@@ -202,18 +838,8 @@ Q_AUTOTEST_EXPORT QQmlGuiProvider *QQml_guiProvider(void)
//Docs in qqmlengine.cpp
QQmlApplication::QQmlApplication(QObject *parent)
- : QObject(*(new QQmlApplicationPrivate),parent)
+ : QQmlApplication(*(new QQmlApplicationPrivate), parent)
{
- connect(QCoreApplication::instance(), SIGNAL(aboutToQuit()),
- this, SIGNAL(aboutToQuit()));
- connect(QCoreApplication::instance(), SIGNAL(applicationNameChanged()),
- this, SIGNAL(nameChanged()));
- connect(QCoreApplication::instance(), SIGNAL(applicationVersionChanged()),
- this, SIGNAL(versionChanged()));
- connect(QCoreApplication::instance(), SIGNAL(organizationNameChanged()),
- this, SIGNAL(organizationChanged()));
- connect(QCoreApplication::instance(), SIGNAL(organizationDomainChanged()),
- this, SIGNAL(domainChanged()));
}
QQmlApplication::QQmlApplication(QQmlApplicationPrivate &dd, QObject *parent)
@@ -281,6 +907,62 @@ void QQmlApplication::setDomain(const QString &arg)
QCoreApplication::instance()->setOrganizationDomain(arg);
}
+static const QQmlData *ddata_for_cast(QObject *object)
+{
+ Q_ASSERT(object);
+ auto ddata = QQmlData::get(object, false);
+ return (ddata && ddata->propertyCache) ? ddata : nullptr;
+}
+
+bool qmlobject_can_cpp_cast(QObject *object, const QMetaObject *mo)
+{
+ Q_ASSERT(mo);
+ if (const QQmlData *ddata = ddata_for_cast(object))
+ return ddata->propertyCache->firstCppMetaObject()->inherits(mo);
+ return object->metaObject()->inherits(mo);
+}
+
+bool qmlobject_can_qml_cast(QObject *object, const QQmlType &type)
+{
+ Q_ASSERT(type.isValid());
+
+ // A non-composite type will always have a metaobject.
+ const QMetaObject *typeMetaObject = type.metaObject();
+ const QQmlPropertyCache::ConstPtr typePropertyCache = typeMetaObject
+ ? QQmlPropertyCache::ConstPtr()
+ : QQmlMetaType::findPropertyCacheInCompositeTypes(type.typeId());
+
+ if (const QQmlData *ddata = ddata_for_cast(object)) {
+ for (const QQmlPropertyCache *propertyCache = ddata->propertyCache.data(); propertyCache;
+ propertyCache = propertyCache->parent().data()) {
+
+ if (typeMetaObject) {
+ // Prefer the metaobject inheritance mechanism, since it is more accurate.
+ //
+ // Assume the object can be casted to the type. Then, if we have a type metaobject,
+ // the object's property cache inheritance has to contain it. Otherwise we would
+ // end up with diverging metaobject hierarchies if we created the object's
+ // metaobject. This would be a disaster.
+ if (const QMetaObject *objectMetaObject = propertyCache->metaObject())
+ return objectMetaObject->inherits(typeMetaObject);
+ } else {
+ // This is a best effort attempt. There are a number of ways for the
+ // property caches to be unrelated but the types still convertible.
+ // Multiple property caches can hold the same metaobject, for example for
+ // versions of non-composite types.
+ if (propertyCache == typePropertyCache.data())
+ return true;
+ }
+ }
+ }
+
+ // If nothing else works, we have to create the metaobjects.
+
+ return object->metaObject()->inherits(typeMetaObject
+ ? typeMetaObject
+ : (typePropertyCache ? typePropertyCache->createMetaObject() : nullptr));
+}
+
QT_END_NAMESPACE
#include "moc_qqmlglobal_p.cpp"
diff --git a/src/qml/qml/qqmlglobal_p.h b/src/qml/qml/qqmlglobal_p.h
index d32641c10c..98fe2e6a79 100644
--- a/src/qml/qml/qqmlglobal_p.h
+++ b/src/qml/qml/qqmlglobal_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLGLOBAL_H
#define QQMLGLOBAL_H
@@ -51,35 +15,41 @@
// We mean it.
//
-#include <private/qtqmlglobal_p.h>
-#include <QtCore/QObject>
-#include <private/qqmlmetaobject_p.h>
#include <private/qmetaobject_p.h>
+#include <private/qqmlmetaobject_p.h>
+#include <private/qqmltype_p.h>
+#include <private/qtqmlglobal_p.h>
+
#include <QtQml/qqml.h>
+#include <QtCore/qobject.h>
QT_BEGIN_NAMESPACE
+inline bool qmlConvertBoolConfigOption(const char *v)
+{
+ return v != nullptr && qstrcmp(v, "0") != 0 && qstrcmp(v, "false") != 0;
+}
+
+template<typename T, T(*Convert)(const char *)>
+T qmlGetConfigOption(const char *var)
+{
+ if (Q_UNLIKELY(!qEnvironmentVariableIsEmpty(var)))
+ return Convert(qgetenv(var));
+ return Convert(nullptr);
+}
#define DEFINE_BOOL_CONFIG_OPTION(name, var) \
static bool name() \
{ \
- static enum { Yes, No, Unknown } status = Unknown; \
- if (status == Unknown) { \
- status = No; \
- if (Q_UNLIKELY(!qEnvironmentVariableIsEmpty(#var))) { \
- const QByteArray v = qgetenv(#var); \
- if (v != "0" && v != "false") \
- status = Yes; \
- } \
- } \
- return status == Yes; \
+ static const bool result = qmlGetConfigOption<bool, qmlConvertBoolConfigOption>(#var); \
+ return result; \
}
/*!
Connect \a Signal of \a Sender to \a Method of \a Receiver. \a Signal must be
of type \a SenderType and \a Receiver of type \a ReceiverType.
- Unlike QObject::connect(), this method caches the lookup of the signal and method
+ Unlike QObject::connect(), this macro caches the lookup of the signal and method
indexes. It also does not require lazy QMetaObjects to be built so should be
preferred in all QML code that might interact with QML built objects.
@@ -118,7 +88,7 @@ do { \
Disconnect \a Signal of \a Sender from \a Method of \a Receiver. \a Signal must be
of type \a SenderType and \a Receiver of type \a ReceiverType.
- Unlike QObject::disconnect(), this method caches the lookup of the signal and method
+ Unlike QObject::disconnect(), this macro caches the lookup of the signal and method
indexes. It also does not require lazy QMetaObjects to be built so should be
preferred in all QML code that might interact with QML built objects.
@@ -153,6 +123,9 @@ do { \
QMetaObject::disconnect(sender, signalIdx, receiver, methodIdx); \
} while (0)
+Q_QML_EXPORT bool qmlobject_can_cpp_cast(QObject *object, const QMetaObject *mo);
+Q_QML_EXPORT bool qmlobject_can_qml_cast(QObject *object, const QQmlType &type);
+
/*!
This method is identical to qobject_cast<T>() except that it does not require lazy
QMetaObjects to be built, so should be preferred in all QML code that might interact
@@ -168,10 +141,23 @@ do { \
template<class T>
T qmlobject_cast(QObject *object)
{
- if (object && QQmlMetaObject::canConvert(object, &reinterpret_cast<T>(object)->staticMetaObject))
+ if (!object)
+ return nullptr;
+ if (qmlobject_can_cpp_cast(object, &(std::remove_pointer_t<T>::staticMetaObject)))
return static_cast<T>(object);
else
- return 0;
+ return nullptr;
+}
+
+class QQuickItem;
+template<>
+inline QQuickItem *qmlobject_cast<QQuickItem *>(QObject *object)
+{
+ if (!object || !object->isQuickItemType())
+ return nullptr;
+ // QQuickItem is incomplete here -> can't use static_cast
+ // but we don't need any pointer adjustment, so reinterpret is safe
+ return reinterpret_cast<QQuickItem *>(object);
}
#define IS_SIGNAL_CONNECTED(Sender, SenderType, Name, Arguments) \
@@ -217,19 +203,27 @@ inline void QQml_setParent_noEvent(QObject *object, QObject *parent)
d_ptr->sendChildEvents = sce;
}
-class Q_QML_PRIVATE_EXPORT QQmlValueTypeProvider
+class QQmlValueTypeProvider
{
public:
- bool initValueType(int, QVariant&);
- bool createValueType(int, const QJSValue &, QVariant &);
- bool equalValueType(int, const void *, const QVariant&);
- bool readValueType(const QVariant&, void *, int);
- bool writeValueType(int, const void *, QVariant&);
+ static bool populateValueType(
+ QMetaType targetMetaType, void *target, const QV4::Value &source);
+ static bool populateValueType(
+ QMetaType targetMetaType, void *target, QMetaType sourceMetaType, void *source);
+
+ static Q_QML_EXPORT void *heapCreateValueType(
+ const QQmlType &targetType, const QV4::Value &source);
+ static QVariant constructValueType(
+ QMetaType targetMetaType, const QMetaObject *targetMetaObject,
+ int ctorIndex, void *ctorArg);
+
+ static QVariant createValueType(const QJSValue &, QMetaType);
+ static QVariant createValueType(const QString &, QMetaType);
+ static QVariant createValueType(const QV4::Value &, QMetaType);
+ static QVariant createValueType(const QVariant &, QMetaType);
};
-Q_AUTOTEST_EXPORT QQmlValueTypeProvider *QQml_valueTypeProvider();
-
-class Q_QML_PRIVATE_EXPORT QQmlColorProvider
+class Q_QML_EXPORT QQmlColorProvider
{
public:
virtual ~QQmlColorProvider();
@@ -245,11 +239,11 @@ public:
virtual QVariant tint(const QVariant &, const QVariant &);
};
-Q_QML_PRIVATE_EXPORT QQmlColorProvider *QQml_setColorProvider(QQmlColorProvider *);
-Q_QML_PRIVATE_EXPORT QQmlColorProvider *QQml_colorProvider();
+Q_QML_EXPORT QQmlColorProvider *QQml_setColorProvider(QQmlColorProvider *);
+Q_QML_EXPORT QQmlColorProvider *QQml_colorProvider();
class QQmlApplication;
-class Q_QML_PRIVATE_EXPORT QQmlGuiProvider
+class Q_QML_EXPORT QQmlGuiProvider
{
public:
virtual ~QQmlGuiProvider();
@@ -261,12 +255,12 @@ public:
virtual QString pluginName() const;
};
-Q_QML_PRIVATE_EXPORT QQmlGuiProvider *QQml_setGuiProvider(QQmlGuiProvider *);
+Q_QML_EXPORT QQmlGuiProvider *QQml_setGuiProvider(QQmlGuiProvider *);
Q_AUTOTEST_EXPORT QQmlGuiProvider *QQml_guiProvider();
class QQmlApplicationPrivate;
-class Q_QML_PRIVATE_EXPORT QQmlApplication : public QObject
+class Q_QML_EXPORT QQmlApplication : public QObject
{
//Application level logic, subclassed by Qt Quick if available via QQmlGuiProvider
Q_OBJECT
diff --git a/src/qml/qml/qqmlguard_p.h b/src/qml/qml/qqmlguard_p.h
index 3ac63926a0..685293868e 100644
--- a/src/qml/qml/qqmlguard_p.h
+++ b/src/qml/qml/qqmlguard_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLGUARD_P_H
#define QQMLGUARD_P_H
@@ -51,87 +15,106 @@
// We mean it.
//
-#include <QtCore/qglobal.h>
-#include <QtCore/qvariant.h>
#include <private/qqmldata_p.h>
+#include <private/qqmlglobal_p.h>
QT_BEGIN_NAMESPACE
class QQmlGuardImpl
{
public:
+ using ObjectDestroyedFn = void(*)(QQmlGuardImpl *);
+
inline QQmlGuardImpl();
inline QQmlGuardImpl(QObject *);
inline QQmlGuardImpl(const QQmlGuardImpl &);
+protected:
inline ~QQmlGuardImpl();
+public: // ### make so it can be private
QObject *o = nullptr;
QQmlGuardImpl *next = nullptr;
QQmlGuardImpl **prev = nullptr;
+ ObjectDestroyedFn objectDestroyed = nullptr;
inline void addGuard();
inline void remGuard();
+
+ inline void setObject(QObject *g);
+ bool isNull() const noexcept { return !o; }
};
class QObject;
template<class T>
-class QQmlGuard : private QQmlGuardImpl
+class QQmlGuard : protected QQmlGuardImpl
{
friend class QQmlData;
public:
- inline QQmlGuard();
- inline QQmlGuard(T *);
- inline QQmlGuard(const QQmlGuard<T> &);
- inline virtual ~QQmlGuard();
+ Q_NODISCARD_CTOR inline QQmlGuard();
+ Q_NODISCARD_CTOR inline QQmlGuard(ObjectDestroyedFn objectDestroyed, T *);
+ Q_NODISCARD_CTOR inline QQmlGuard(T *);
+ Q_NODISCARD_CTOR inline QQmlGuard(const QQmlGuard<T> &);
inline QQmlGuard<T> &operator=(const QQmlGuard<T> &o);
inline QQmlGuard<T> &operator=(T *);
- inline T *object() const;
- inline void setObject(T *g);
+ T *object() const noexcept { return static_cast<T *>(o); }
+ void setObject(T *g) { QQmlGuardImpl::setObject(g); }
- inline bool isNull() const
- { return !o; }
+ using QQmlGuardImpl::isNull;
- inline T* operator->() const
- { return static_cast<T*>(const_cast<QObject*>(o)); }
- inline T& operator*() const
- { return *static_cast<T*>(const_cast<QObject*>(o)); }
- inline operator T*() const
- { return static_cast<T*>(const_cast<QObject*>(o)); }
- inline T* data() const
- { return static_cast<T*>(const_cast<QObject*>(o)); }
-
-protected:
- virtual void objectDestroyed(T *) {}
+ T *operator->() const noexcept { return object(); }
+ T &operator*() const { return *object(); }
+ operator T *() const noexcept { return object(); }
+ T *data() const noexcept { return object(); }
};
+/* used in QQmlStrongJSQObjectReference to indicate that the
+ * object has JS ownership
+ * We save it in objectDestroyFn to save space
+ * (implemented in qqmlengine.cpp)
+ */
+void Q_QML_EXPORT hasJsOwnershipIndicator(QQmlGuardImpl *);
+
template <typename T>
-class QQmlStrongJSQObjectReference : public QQmlGuard<T>
+class QQmlStrongJSQObjectReference final : protected QQmlGuardImpl
{
public:
- void setObject(T *o, QObject *parent) {
- T *old = this->object();
- if (o == old)
+ T *object() const noexcept { return static_cast<T *>(o); }
+
+ using QQmlGuardImpl::isNull;
+
+ T *operator->() const noexcept { return object(); }
+ T &operator*() const { return *object(); }
+ operator T *() const noexcept { return object(); }
+ T *data() const noexcept { return object(); }
+
+ void setObject(T *obj, QObject *parent) {
+ T *old = object();
+ if (obj == old)
return;
- if (m_jsOwnership && old && old->parent() == parent)
+ if (hasJsOwnership() && old && old->parent() == parent)
QQml_setParent_noEvent(old, nullptr);
- this->QQmlGuard<T>::operator=(o);
+ QQmlGuardImpl::setObject(obj);
- if (o && !o->parent() && !QQmlData::keepAliveDuringGarbageCollection(o)) {
- m_jsOwnership = true;
- QQml_setParent_noEvent(o, parent);
+ if (obj && !obj->parent() && !QQmlData::keepAliveDuringGarbageCollection(obj)) {
+ setJsOwnership(true);
+ QQml_setParent_noEvent(obj, parent);
} else {
- m_jsOwnership = false;
+ setJsOwnership(false);
}
}
private:
- using QQmlGuard<T>::setObject;
- using QQmlGuard<T>::operator=;
- bool m_jsOwnership = false;
+ bool hasJsOwnership() {
+ return objectDestroyed == hasJsOwnershipIndicator;
+ }
+
+ void setJsOwnership(bool itHasOwnership) {
+ objectDestroyed = itHasOwnership ? hasJsOwnershipIndicator : nullptr;
+ }
};
QT_END_NAMESPACE
@@ -150,8 +133,15 @@ QQmlGuardImpl::QQmlGuardImpl(QObject *g)
if (o) addGuard();
}
+/*
+ \internal
+ Copying a QQmlGuardImpl leaves the old one in the intrinsic linked list of guards.
+ The fresh copy does not contain the list pointer of the existing guard; instead
+ only the object and objectDestroyed pointers are copied, and if there is an object
+ we add the new guard to the object's list of guards.
+ */
QQmlGuardImpl::QQmlGuardImpl(const QQmlGuardImpl &g)
-: o(g.o)
+: o(g.o), objectDestroyed(g.objectDestroyed)
{
if (o) addGuard();
}
@@ -192,25 +182,28 @@ QQmlGuard<T>::QQmlGuard()
}
template<class T>
-QQmlGuard<T>::QQmlGuard(T *g)
-: QQmlGuardImpl(g)
+QQmlGuard<T>::QQmlGuard(ObjectDestroyedFn objDestroyed, T *obj)
+ : QQmlGuardImpl(obj)
{
+ objectDestroyed = objDestroyed;
}
template<class T>
-QQmlGuard<T>::QQmlGuard(const QQmlGuard<T> &g)
+QQmlGuard<T>::QQmlGuard(T *g)
: QQmlGuardImpl(g)
{
}
template<class T>
-QQmlGuard<T>::~QQmlGuard()
+QQmlGuard<T>::QQmlGuard(const QQmlGuard<T> &g)
+: QQmlGuardImpl(g)
{
}
template<class T>
QQmlGuard<T> &QQmlGuard<T>::operator=(const QQmlGuard<T> &g)
{
+ objectDestroyed = g.objectDestroyed;
setObject(g.object());
return *this;
}
@@ -218,18 +211,15 @@ QQmlGuard<T> &QQmlGuard<T>::operator=(const QQmlGuard<T> &g)
template<class T>
QQmlGuard<T> &QQmlGuard<T>::operator=(T *g)
{
+ /* this does not touch objectDestroyed, as operator= is only a convenience
+ * for setObject. All logic involving objectDestroyed is (sub-)class specific
+ * and remains unaffected.
+ */
setObject(g);
return *this;
}
-template<class T>
-T *QQmlGuard<T>::object() const
-{
- return static_cast<T *>(o);
-}
-
-template<class T>
-void QQmlGuard<T>::setObject(T *g)
+void QQmlGuardImpl::setObject(QObject *g)
{
if (g != o) {
if (prev) remGuard();
diff --git a/src/qml/qml/qqmlguardedcontextdata_p.h b/src/qml/qml/qqmlguardedcontextdata_p.h
index 0b24c04305..048f809f48 100644
--- a/src/qml/qml/qqmlguardedcontextdata_p.h
+++ b/src/qml/qml/qqmlguardedcontextdata_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2020 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$
-**
-****************************************************************************/
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLGUARDEDCONTEXTDATA_P_H
#define QQMLGUARDEDCONTEXTDATA_P_H
@@ -51,7 +15,7 @@
// We mean it.
//
-#include <QtQml/private/qqmlglobal_p.h>
+#include <QtQml/private/qtqmlglobal_p.h>
#include <QtQml/private/qqmlcontextdata_p.h>
QT_BEGIN_NAMESPACE
@@ -103,14 +67,14 @@ public:
QQmlGuardedContextData *next() const { return m_next; }
+private:
void reset()
{
- m_contextData = nullptr;
+ m_contextData.reset();
m_next = nullptr;
m_prev = nullptr;
}
-private:
void unlink()
{
if (m_prev) {
diff --git a/src/qml/qml/qqmlimport.cpp b/src/qml/qml/qqmlimport.cpp
index 0016d4bcc4..86380294ba 100644
--- a/src/qml/qml/qqmlimport.cpp
+++ b/src/qml/qml/qqmlimport.cpp
@@ -1,42 +1,6 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 Crimson AS <info@crimson.no>
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2017 Crimson AS <info@crimson.no>
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qqmlimport_p.h"
@@ -46,28 +10,62 @@
#include <QtCore/qfileinfo.h>
#include <QtCore/qpluginloader.h>
#include <QtCore/qlibraryinfo.h>
-#include <QtCore/qreadwritelock.h>
+#include <QtCore/qloggingcategory.h>
#include <QtQml/qqmlextensioninterface.h>
#include <QtQml/qqmlextensionplugin.h>
#include <private/qqmlextensionplugin_p.h>
#include <private/qqmlglobal_p.h>
#include <private/qqmltypenamecache_p.h>
#include <private/qqmlengine_p.h>
-#include <private/qfieldlist_p.h>
#include <private/qqmltypemodule_p.h>
#include <private/qqmltypeloaderqmldircontent_p.h>
+#include <private/qqmlpluginimporter_p.h>
#include <QtCore/qjsonobject.h>
#include <QtCore/qjsonarray.h>
#include <QtQml/private/qqmltype_p_p.h>
#include <QtQml/private/qqmlimportresolver_p.h>
+#ifdef Q_OS_MACOS
+#include "private/qcore_mac_p.h"
+#endif
+
#include <algorithm>
#include <functional>
-#include <unordered_map>
+
+using namespace Qt::Literals::StringLiterals;
QT_BEGIN_NAMESPACE
DEFINE_BOOL_CONFIG_OPTION(qmlImportTrace, QML_IMPORT_TRACE)
+
+class QmlImportCategoryHolder
+{
+ Q_DISABLE_COPY_MOVE(QmlImportCategoryHolder);
+public:
+
+ QmlImportCategoryHolder() : m_category("qt.qml.import")
+ {
+ // We have to explicitly setEnabled() here because for categories that start with
+ // "qt." it won't accept QtDebugMsg as argument. Debug messages are off by default
+ // for all Qt logging categories.
+ if (qmlImportTrace())
+ m_category.setEnabled(QtDebugMsg, true);
+ }
+
+ ~QmlImportCategoryHolder() = default;
+
+ const QLoggingCategory &category() const { return m_category; }
+
+private:
+ QLoggingCategory m_category;
+};
+
+const QLoggingCategory &lcQmlImport()
+{
+ static const QmlImportCategoryHolder holder;
+ return holder.category();
+}
+
DEFINE_BOOL_CONFIG_OPTION(qmlCheckTypes, QML_CHECK_TYPES)
static const QLatin1Char Dot('.');
@@ -87,12 +85,6 @@ QTypeRevision relevantVersion(const QString &uri, QTypeRevision version)
return QQmlMetaType::latestModuleVersion(uri).isValid() ? version : QTypeRevision();
}
-QTypeRevision validVersion(QTypeRevision version = QTypeRevision())
-{
- // If the given version is invalid, return a valid but useless version to signal "It's OK".
- return version.isValid() ? version : QTypeRevision::fromMinorVersion(0);
-}
-
QQmlError moduleNotFoundError(const QString &uri, QTypeRevision version)
{
QQmlError error;
@@ -127,7 +119,7 @@ QString resolveLocalUrl(const QString &url, const QString &relative)
QString base = baseRef + relative;
// Remove any relative directory elements in the path
- int length = base.length();
+ int length = base.size();
int index = 0;
while ((index = base.indexOf(QLatin1String("/."), index)) != -1) {
if ((length > (index + 2)) && (base.at(index + 2) == Dot) &&
@@ -166,72 +158,6 @@ bool isPathAbsolute(const QString &path)
} // namespace
-struct QmlPlugin {
- std::unique_ptr<QPluginLoader> loader;
-};
-
-class PathPluginMap
-{
- Q_DISABLE_COPY_MOVE(PathPluginMap)
-public:
- PathPluginMap() = default;
- using Container = std::unordered_map<QString, QmlPlugin>;
-
-private:
- QBasicMutex mutex;
- Container plugins;
- friend class PathPluginMapPtr;
-};
-
-class PathPluginMapPtr
-{
- Q_DISABLE_COPY_MOVE(PathPluginMapPtr)
-public:
- PathPluginMapPtr(PathPluginMap *map) : map(map), locker(&map->mutex) {}
-
- PathPluginMap::Container &operator*() { return map->plugins; }
- const PathPluginMap::Container &operator*() const { return map->plugins; }
-
- PathPluginMap::Container *operator->() { return &map->plugins; }
- const PathPluginMap::Container *operator->() const { return &map->plugins; }
-
-private:
- PathPluginMap *map;
- QMutexLocker<QBasicMutex> locker;
-};
-
-Q_GLOBAL_STATIC(PathPluginMap, qmlPluginsByPath); // stores the uri and the PluginLoaders
-
-static bool unloadPlugin(const std::pair<const QString, QmlPlugin> &plugin)
-{
- const auto &loader = plugin.second.loader;
- if (!loader)
- return false;
-
- if (auto extensionPlugin = qobject_cast<QQmlExtensionPlugin *>(loader->instance()))
- extensionPlugin->unregisterTypes();
-
-#if QT_CONFIG(library) && !defined(Q_OS_MACOS)
- if (!loader->unload()) {
- qWarning("Unloading %s failed: %s", qPrintable(plugin.first),
- qPrintable(loader->errorString()));
- return false;
- }
-#endif
-
- return true;
-}
-
-void qmlClearEnginePlugins()
-{
- PathPluginMapPtr plugins(qmlPluginsByPath());
- for (const auto &plugin : qAsConst(*plugins))
- unloadPlugin(plugin);
- plugins->clear();
-}
-
-typedef QPair<QStaticPlugin, QJsonArray> StaticPluginPair;
-
/*!
\internal
\class QQmlImportInstance
@@ -265,103 +191,16 @@ typedef QPair<QStaticPlugin, QJsonArray> StaticPluginPair;
import MyFoo 1.0 as Foo
*/
-class QQmlImportsPrivate
-{
-public:
- QQmlImportsPrivate(QQmlTypeLoader *loader);
- ~QQmlImportsPrivate();
-
- QQmlImportNamespace *importNamespace(const QString &prefix) const;
-
- QTypeRevision addLibraryImport(
- const QString& uri, const QString &prefix, QTypeRevision version,
- const QString &qmldirIdentifier, const QString &qmldirUrl, uint flags,
- QQmlImportDatabase *database, QList<QQmlError> *errors);
-
- QTypeRevision addFileImport(
- const QString &uri, const QString &prefix, QTypeRevision version, uint flags,
- QQmlImportDatabase *database, QList<QQmlError> *errors);
-
- QTypeRevision updateQmldirContent(const QString &uri, const QString &prefix,
- const QString &qmldirIdentifier, const QString& qmldirUrl,
- QQmlImportDatabase *database,
- QList<QQmlError> *errors);
-
- bool resolveType(const QHashedStringRef &type, QTypeRevision *version_return,
- QQmlType *type_return, QList<QQmlError> *errors,
- QQmlType::RegistrationType registrationType,
- bool *typeRecursionDetected = nullptr);
-
- QUrl baseUrl;
- QString base;
- int ref;
-
- // storage of data related to imports without a namespace
- mutable QQmlImportNamespace unqualifiedset;
-
- QQmlImportNamespace *findQualifiedNamespace(const QHashedStringRef &) const;
-
- // storage of data related to imports with a namespace
- mutable QFieldList<QQmlImportNamespace, &QQmlImportNamespace::nextNamespace> qualifiedSets;
-
- QQmlTypeLoader *typeLoader;
-
- static QQmlImports::LocalQmldirResult locateLocalQmldir(
- const QString &uri, QTypeRevision version, QQmlImportDatabase *database,
- QString *outQmldirFilePath, QString *outUrl);
-
- static QTypeRevision matchingQmldirVersion(
- const QQmlTypeLoaderQmldirContent &qmldir, const QString &uri,
- QTypeRevision version, QList<QQmlError> *errors);
-
- QTypeRevision importExtension(
- const QString &uri, QTypeRevision version, QQmlImportDatabase *database,
- const QQmlTypeLoaderQmldirContent &qmldir, QList<QQmlError> *errors);
-
- bool getQmldirContent(const QString &qmldirIdentifier, const QString &uri,
- QQmlTypeLoaderQmldirContent *qmldir, QList<QQmlError> *errors);
-
- QString resolvedUri(const QString &dir_arg, QQmlImportDatabase *database);
-
- QQmlImportInstance *addImportToNamespace(QQmlImportNamespace *nameSpace, const QString &uri,
- const QString &url, QTypeRevision version,
- QV4::CompiledData::Import::ImportType type,
- QList<QQmlError> *errors, uint flags);
-
- bool populatePluginPairVector(QVector<StaticPluginPair> &result, const QString &uri, const QStringList &versionUris,
- const QString &qmldirPath, QList<QQmlError> *errors);
-};
-
/*!
\class QQmlImports
\brief The QQmlImports class encapsulates one QML document's import statements.
\internal
*/
-QQmlImports::QQmlImports(const QQmlImports &copy)
-: d(copy.d)
-{
- ++d->ref;
-}
-
-QQmlImports &
-QQmlImports::operator =(const QQmlImports &copy)
-{
- ++copy.d->ref;
- if (--d->ref == 0)
- delete d;
- d = copy.d;
- return *this;
-}
-QQmlImports::QQmlImports(QQmlTypeLoader *typeLoader)
- : d(new QQmlImportsPrivate(typeLoader))
+QTypeRevision QQmlImports::validVersion(QTypeRevision version)
{
-}
-
-QQmlImports::~QQmlImports()
-{
- if (--d->ref == 0)
- delete d;
+ // If the given version is invalid, return a valid but useless version to signal "It's OK".
+ return version.isValid() ? version : QTypeRevision::fromMinorVersion(0);
}
/*!
@@ -369,23 +208,20 @@ QQmlImports::~QQmlImports()
*/
void QQmlImports::setBaseUrl(const QUrl& url, const QString &urlString)
{
- d->baseUrl = url;
+ m_baseUrl = url;
- if (urlString.isEmpty()) {
- d->base = url.toString();
- } else {
- //Q_ASSERT(url.toString() == urlString);
- d->base = urlString;
- }
+ if (urlString.isEmpty())
+ m_base = url.toString();
+ else
+ m_base = urlString;
}
/*!
+ \fn QQmlImports::baseUrl()
+ \internal
+
Returns the base URL to be used for all relative file imports added.
*/
-QUrl QQmlImports::baseUrl() const
-{
- return d->baseUrl;
-}
/*
\internal
@@ -399,9 +235,9 @@ QUrl QQmlImports::baseUrl() const
*/
void QQmlImports::populateCache(QQmlTypeNameCache *cache) const
{
- const QQmlImportNamespace &set = d->unqualifiedset;
+ const QQmlImportNamespace &set = m_unqualifiedset;
- for (int ii = set.imports.count() - 1; ii >= 0; --ii) {
+ for (int ii = set.imports.size() - 1; ii >= 0; --ii) {
const QQmlImportInstance *import = set.imports.at(ii);
QQmlTypeModule *module = QQmlMetaType::typeModule(import->uri, import->version);
if (module) {
@@ -409,7 +245,7 @@ void QQmlImports::populateCache(QQmlTypeNameCache *cache) const
}
}
- for (QQmlImportNamespace *ns = d->qualifiedSets.first(); ns; ns = d->qualifiedSets.next(ns)) {
+ for (QQmlImportNamespace *ns = m_qualifiedSets.first(); ns; ns = m_qualifiedSets.next(ns)) {
const QQmlImportNamespace &set = *ns;
@@ -417,7 +253,7 @@ void QQmlImports::populateCache(QQmlTypeNameCache *cache) const
QQmlImportRef &typeimport = cache->m_namedImports[set.prefix];
typeimport.m_qualifier = set.prefix;
- for (int ii = set.imports.count() - 1; ii >= 0; --ii) {
+ for (int ii = set.imports.size() - 1; ii >= 0; --ii) {
const QQmlImportInstance *import = set.imports.at(ii);
QQmlTypeModule *module = QQmlMetaType::typeModule(import->uri, import->version);
if (module) {
@@ -449,7 +285,7 @@ void findCompositeSingletons(const QQmlImportNamespace &set, QList<QQmlImports::
{
typedef QQmlDirComponents::const_iterator ConstIterator;
- for (int ii = set.imports.count() - 1; ii >= 0; --ii) {
+ for (int ii = set.imports.size() - 1; ii >= 0; --ii) {
const QQmlImportInstance *import = set.imports.at(ii);
const QQmlDirComponents &components = import->qmlDirComponents;
@@ -502,10 +338,10 @@ QList<QQmlImports::CompositeSingletonReference> QQmlImports::resolvedCompositeSi
{
QList<QQmlImports::CompositeSingletonReference> compositeSingletons;
- const QQmlImportNamespace &set = d->unqualifiedset;
+ const QQmlImportNamespace &set = m_unqualifiedset;
findCompositeSingletons(set, compositeSingletons, baseUrl());
- for (QQmlImportNamespace *ns = d->qualifiedSets.first(); ns; ns = d->qualifiedSets.next(ns)) {
+ for (QQmlImportNamespace *ns = m_qualifiedSets.first(); ns; ns = m_qualifiedSets.next(ns)) {
const QQmlImportNamespace &set = *ns;
findCompositeSingletons(set, compositeSingletons, baseUrl());
}
@@ -537,9 +373,9 @@ QList<QQmlImports::ScriptReference> QQmlImports::resolvedScripts() const
{
QList<QQmlImports::ScriptReference> scripts;
- const QQmlImportNamespace &set = d->unqualifiedset;
+ const QQmlImportNamespace &set = m_unqualifiedset;
- for (int ii = set.imports.count() - 1; ii >= 0; --ii) {
+ for (int ii = set.imports.size() - 1; ii >= 0; --ii) {
const QQmlImportInstance *import = set.imports.at(ii);
for (const QQmlDirParser::Script &script : import->qmlDirScripts) {
@@ -550,10 +386,10 @@ QList<QQmlImports::ScriptReference> QQmlImports::resolvedScripts() const
}
}
- for (QQmlImportNamespace *ns = d->qualifiedSets.first(); ns; ns = d->qualifiedSets.next(ns)) {
+ for (QQmlImportNamespace *ns = m_qualifiedSets.first(); ns; ns = m_qualifiedSets.next(ns)) {
const QQmlImportNamespace &set = *ns;
- for (int ii = set.imports.count() - 1; ii >= 0; --ii) {
+ for (int ii = set.imports.size() - 1; ii >= 0; --ii) {
const QQmlImportInstance *import = set.imports.at(ii);
for (const QQmlDirParser::Script &script : import->qmlDirScripts) {
@@ -613,24 +449,23 @@ QString QQmlImports::versionString(QTypeRevision version, ImportVersion versionM
\sa addFileImport(), addLibraryImport
*/
-bool QQmlImports::resolveType(const QHashedStringRef &type,
- QQmlType *type_return, QTypeRevision *version_return,
- QQmlImportNamespace** ns_return, QList<QQmlError> *errors,
- QQmlType::RegistrationType registrationType,
- bool *typeRecursionDetected) const
+bool QQmlImports::resolveType(
+ QQmlTypeLoader *typeLoader, const QHashedStringRef &type, QQmlType *type_return,
+ QTypeRevision *version_return, QQmlImportNamespace **ns_return, QList<QQmlError> *errors,
+ QQmlType::RegistrationType registrationType, bool *typeRecursionDetected) const
{
- QQmlImportNamespace* ns = d->findQualifiedNamespace(type);
+ QQmlImportNamespace *ns = findQualifiedNamespace(type);
if (ns) {
if (ns_return)
*ns_return = ns;
return true;
}
if (type_return) {
- if (d->resolveType(type, version_return, type_return, errors, registrationType,
- typeRecursionDetected)) {
- if (qmlImportTrace()) {
-#define RESOLVE_TYPE_DEBUG qDebug().nospace() << "QQmlImports(" << qPrintable(baseUrl().toString()) \
- << ')' << "::resolveType: " << type.toString() << " => "
+ if (resolveType(typeLoader, type, version_return, type_return, errors, registrationType,
+ typeRecursionDetected)) {
+ if (lcQmlImport().isDebugEnabled()) {
+#define RESOLVE_TYPE_DEBUG qCDebug(lcQmlImport) \
+ << "resolveType:" << qPrintable(baseUrl().toString()) << type.toString() << " => "
if (type_return && type_return->isValid()) {
if (type_return->isCompositeSingleton())
@@ -654,18 +489,8 @@ bool QQmlImportInstance::setQmldirContent(const QString &resolvedUrl,
const QQmlTypeLoaderQmldirContent &qmldir,
QQmlImportNamespace *nameSpace, QList<QQmlError> *errors)
{
-
- const QString preferredPath = qmldir.preferredPath();
- if (preferredPath.isEmpty()) {
- Q_ASSERT(resolvedUrl.endsWith(Slash));
- url = resolvedUrl;
- } else {
- Q_ASSERT(preferredPath.endsWith(Slash));
- if (preferredPath.startsWith(u':'))
- url = QStringLiteral("qrc") + preferredPath;
- else
- url = QUrl::fromLocalFile(preferredPath).toString();
- }
+ Q_ASSERT(resolvedUrl.endsWith(Slash));
+ url = resolvedUrl;
qmlDirComponents = qmldir.components();
@@ -676,7 +501,9 @@ bool QQmlImportInstance::setQmldirContent(const QString &resolvedUrl,
it != nameSpace->imports.constEnd(); ++it) {
if ((*it != this) && ((*it)->uri == uri)) {
QQmlError error;
- error.setDescription(QQmlImportDatabase::tr("\"%1\" is ambiguous. Found in %2 and in %3").arg(uri).arg(url).arg((*it)->url));
+ error.setDescription(
+ QQmlImportDatabase::tr("\"%1\" is ambiguous. Found in %2 and in %3")
+ .arg(uri, url, (*it)->url));
errors->prepend(error);
return false;
}
@@ -700,8 +527,8 @@ QQmlDirScripts QQmlImportInstance::getVersionedScripts(const QQmlDirScripts &qml
&& (!version.hasMinorVersion()
|| (sit->version.minorVersion() <= version.minorVersion()))) {
// Load the highest version that matches
- QMap<QString, QQmlDirParser::Script>::iterator vit = versioned.find(sit->nameSpace);
- if (vit == versioned.end()
+ const auto vit = versioned.constFind(sit->nameSpace);
+ if (vit == versioned.cend()
|| (vit->version.minorVersion() < sit->version.minorVersion())) {
versioned.insert(sit->nameSpace, *sit);
}
@@ -712,6 +539,7 @@ QQmlDirScripts QQmlImportInstance::getVersionedScripts(const QQmlDirScripts &qml
}
/*!
+ \fn QQmlImports::resolveType(QQmlImportNamespace *ns, const QHashedStringRef &type, QQmlType *type_return, QTypeRevision *version_return, QQmlType::RegistrationType registrationType = QQmlType::AnyRegistrationType) const
\internal
Searching \e only in the namespace \a ns (previously returned in a call to
@@ -721,17 +549,10 @@ QQmlDirScripts QQmlImportInstance::getVersionedScripts(const QQmlDirScripts &qml
If the return pointer is 0, the corresponding search is not done.
*/
-bool QQmlImports::resolveType(QQmlImportNamespace *ns, const QHashedStringRef &type,
- QQmlType *type_return, QTypeRevision *version_return,
- QQmlType::RegistrationType registrationType) const
-{
- return ns->resolveType(d->typeLoader, type, version_return, type_return, nullptr, nullptr,
- registrationType);
-}
bool QQmlImportInstance::resolveType(QQmlTypeLoader *typeLoader, const QHashedStringRef& type,
QTypeRevision *version_return, QQmlType *type_return,
- QString *base, bool *typeRecursionDetected,
+ const QString *base, bool *typeRecursionDetected,
QQmlType::RegistrationType registrationType,
QQmlImport::RecursionRestriction recursionRestriction,
QList<QQmlError> *errors) const
@@ -751,37 +572,14 @@ bool QQmlImportInstance::resolveType(QQmlTypeLoader *typeLoader, const QHashedSt
bool ret = uri == typeStr;
if (ret) {
Q_ASSERT(!type_return->isValid());
- auto createICType = [&]() {
- auto typePriv = new QQmlTypePrivate {QQmlType::RegistrationType::InlineComponentType};
- bool ok = false;
- typePriv->extraData.id->objectId = QUrl(this->url).fragment().toInt(&ok);
- Q_ASSERT(ok);
- typePriv->extraData.id->url = QUrl(this->url);
- auto icType = QQmlType(typePriv);
- typePriv->release();
- return icType;
- };
- if (containingType.isValid()) {
- // we currently cannot reference a Singleton inside itself
- // in that case, containingType is still invalid
- if (int icID = containingType.lookupInlineComponentIdByName(typeStr); icID != -1) {
- *type_return = containingType.lookupInlineComponentById(icID);
- } else {
- auto icType = createICType();
- int placeholderId = containingType.generatePlaceHolderICId();
- const_cast<QQmlImportInstance*>(this)->containingType.associateInlineComponent(typeStr, placeholderId, CompositeMetaTypeIds {}, icType);
- *type_return = QQmlType(icType);
- }
- } else {
- *type_return = createICType();
- }
+ *type_return = QQmlMetaType::fetchOrCreateInlineComponentTypeForUrl(QUrl(url));
}
return ret;
}
QQmlDirComponents::ConstIterator it = qmlDirComponents.find(typeStr), end = qmlDirComponents.end();
if (it != end) {
QString componentUrl;
- bool isCompositeSingleton = false;
+ QQmlMetaType::CompositeTypeLookupMode lookupMode = QQmlMetaType::NonSingleton;
QQmlDirComponents::ConstIterator candidate = end;
for ( ; it != end && it.key() == typeStr; ++it) {
const QQmlDirParser::Component &c = *it;
@@ -826,7 +624,7 @@ bool QQmlImportInstance::resolveType(QQmlTypeLoader *typeLoader, const QHashedSt
// This is our best candidate so far
candidate = it;
- isCompositeSingleton = c.singleton;
+ lookupMode = c.singleton ? QQmlMetaType::Singleton : QQmlMetaType::NonSingleton;
}
}
}
@@ -834,7 +632,7 @@ bool QQmlImportInstance::resolveType(QQmlTypeLoader *typeLoader, const QHashedSt
if (candidate != end) {
if (!base) // ensure we have a componentUrl
componentUrl = resolveLocalUrl(QString(url + candidate->typeName + dotqml_string), candidate->fileName);
- QQmlType returnType = QQmlMetaType::typeForUrl(componentUrl, type, isCompositeSingleton,
+ QQmlType returnType = QQmlMetaType::typeForUrl(componentUrl, type, lookupMode,
nullptr, candidate->version);
if (version_return)
*version_return = candidate->version;
@@ -883,7 +681,10 @@ bool QQmlImportInstance::resolveType(QQmlTypeLoader *typeLoader, const QHashedSt
*typeRecursionDetected = recursion;
if (recursionRestriction == QQmlImport::AllowRecursion || !recursion) {
QQmlType returnType = QQmlMetaType::typeForUrl(
- qmlUrl, type, registrationType == QQmlType::CompositeSingletonType, errors);
+ qmlUrl, type, registrationType == QQmlType::CompositeSingletonType
+ ? QQmlMetaType::Singleton
+ : QQmlMetaType::NonSingleton,
+ errors);
if (type_return)
*type_return = returnType;
return returnType.isValid();
@@ -894,22 +695,28 @@ bool QQmlImportInstance::resolveType(QQmlTypeLoader *typeLoader, const QHashedSt
return false;
}
-bool QQmlImportsPrivate::resolveType(const QHashedStringRef& type, QTypeRevision *version_return,
- QQmlType *type_return, QList<QQmlError> *errors,
- QQmlType::RegistrationType registrationType,
- bool *typeRecursionDetected)
+bool QQmlImports::resolveType(
+ QQmlTypeLoader *typeLoader, const QHashedStringRef &type, QTypeRevision *version_return,
+ QQmlType *type_return, QList<QQmlError> *errors,
+ QQmlType::RegistrationType registrationType, bool *typeRecursionDetected) const
{
const QVector<QHashedStringRef> splitName = type.split(Dot);
- auto resolveTypeInNamespace = [&](QHashedStringRef unqualifiedtype, QQmlImportNamespace *nameSpace, QList<QQmlError> *errors) -> bool {
- if (nameSpace->resolveType(typeLoader, unqualifiedtype, version_return, type_return, &base, errors,
- registrationType, typeRecursionDetected))
+ auto resolveTypeInNamespace = [&](
+ QHashedStringRef unqualifiedtype, QQmlImportNamespace *nameSpace,
+ QList<QQmlError> *errors) -> bool {
+ if (nameSpace->resolveType(
+ typeLoader, unqualifiedtype, version_return, type_return, &m_base, errors,
+ registrationType, typeRecursionDetected))
return true;
- if (nameSpace->imports.count() == 1 && !nameSpace->imports.at(0)->isLibrary && type_return && nameSpace != &unqualifiedset) {
+ if (nameSpace->imports.size() == 1
+ && !nameSpace->imports.at(0)->isLibrary
+ && type_return
+ && nameSpace != &m_unqualifiedset) {
// qualified, and only 1 url
*type_return = QQmlMetaType::typeForUrl(
resolveLocalUrl(nameSpace->imports.at(0)->url,
unqualifiedtype.toString() + QLatin1String(".qml")),
- type, false, errors);
+ type, QQmlMetaType::NonSingleton, errors);
return type_return->isValid();
}
return false;
@@ -917,7 +724,7 @@ bool QQmlImportsPrivate::resolveType(const QHashedStringRef& type, QTypeRevision
switch (splitName.size()) {
case 1: {
// must be a simple type
- return resolveTypeInNamespace(type, &unqualifiedset, errors);
+ return resolveTypeInNamespace(type, &m_unqualifiedset, errors);
}
case 2: {
// either namespace + simple type OR simple type + inline component
@@ -926,25 +733,10 @@ bool QQmlImportsPrivate::resolveType(const QHashedStringRef& type, QTypeRevision
// namespace + simple type
return resolveTypeInNamespace(splitName.at(1), s, errors);
} else {
- if (resolveTypeInNamespace(splitName.at(0), &unqualifiedset, nullptr)) {
+ if (resolveTypeInNamespace(splitName.at(0), &m_unqualifiedset, nullptr)) {
// either simple type + inline component
- auto const icName = splitName.at(1).toString();
- auto objectIndex = type_return->lookupInlineComponentIdByName(icName);
- if (objectIndex != -1) {
- *type_return = type_return->lookupInlineComponentById(objectIndex);
- } else {
- auto icTypePriv = new QQmlTypePrivate(QQmlType::RegistrationType::InlineComponentType);
- icTypePriv->setContainingType(type_return);
- icTypePriv->extraData.id->url = type_return->sourceUrl();
- int placeholderId = type_return->generatePlaceHolderICId();
- icTypePriv->extraData.id->url.setFragment(QString::number(placeholderId));
- auto icType = QQmlType(icTypePriv);
- icTypePriv->release();
- type_return->associateInlineComponent(icName, placeholderId, CompositeMetaTypeIds {}, icType);
- *type_return = icType;
- }
- Q_ASSERT(type_return->containingType().isValid());
- type_return->setPendingResolutionName(icName);
+ *type_return = QQmlMetaType::inlineComponentType(
+ *type_return, splitName.at(1).toString());
return true;
} else {
// or a failure
@@ -965,22 +757,8 @@ bool QQmlImportsPrivate::resolveType(const QHashedStringRef& type, QTypeRevision
error.setDescription(QQmlImportDatabase::tr("- %1 is not a namespace").arg(splitName.at(0).toString()));
} else {
if (resolveTypeInNamespace(splitName.at(1), s, nullptr)) {
- auto const icName = splitName.at(2).toString();
- auto objectIndex = type_return->lookupInlineComponentIdByName(icName);
- if (objectIndex != -1)
- *type_return = type_return->lookupInlineComponentById(objectIndex);
- else {
- auto icTypePriv = new QQmlTypePrivate(QQmlType::RegistrationType::InlineComponentType);
- icTypePriv->setContainingType(type_return);
- icTypePriv->extraData.id->url = type_return->sourceUrl();
- int placeholderId = type_return->generatePlaceHolderICId();
- icTypePriv->extraData.id->url.setFragment(QString::number(placeholderId));
- auto icType = QQmlType(icTypePriv);
- icTypePriv->release();
- type_return->associateInlineComponent(icName, placeholderId, CompositeMetaTypeIds {}, icType);
- *type_return = icType;
- }
- type_return->setPendingResolutionName(icName);
+ *type_return = QQmlMetaType::inlineComponentType(
+ *type_return, splitName.at(2).toString());
return true;
} else {
error.setDescription(QQmlImportDatabase::tr("- %1 is not a type").arg(splitName.at(1).toString()));
@@ -1015,7 +793,7 @@ QQmlImportInstance *QQmlImportNamespace::findImport(const QString &uri) const
bool QQmlImportNamespace::resolveType(QQmlTypeLoader *typeLoader, const QHashedStringRef &type,
QTypeRevision *version_return, QQmlType *type_return,
- QString *base, QList<QQmlError> *errors,
+ const QString *base, QList<QQmlError> *errors,
QQmlType::RegistrationType registrationType,
bool *typeRecursionDetected)
{
@@ -1026,19 +804,20 @@ bool QQmlImportNamespace::resolveType(QQmlTypeLoader *typeLoader, const QHashedS
if (!typeRecursionDetected)
typeRecursionDetected = &localTypeRecursionDetected;
+ // TODO: move the sorting somewhere else and make resolveType() const.
if (needsSorting()) {
std::stable_partition(imports.begin(), imports.end(), [](QQmlImportInstance *import) {
return import->isInlineComponent;
});
setNeedsSorting(false);
}
- for (int i=0; i<imports.count(); ++i) {
+ for (int i=0; i<imports.size(); ++i) {
const QQmlImportInstance *import = imports.at(i);
if (import->resolveType(typeLoader, type, version_return, type_return, base,
typeRecursionDetected, registrationType, recursionRestriction, errors)) {
if (qmlCheckTypes()) {
// check for type clashes
- for (int j = i+1; j<imports.count(); ++j) {
+ for (int j = i+1; j<imports.size(); ++j) {
const QQmlImportInstance *import2 = imports.at(j);
if (import2->resolveType(typeLoader, type, version_return, nullptr, base,
nullptr, registrationType)) {
@@ -1064,14 +843,20 @@ bool QQmlImportNamespace::resolveType(QQmlTypeLoader *typeLoader, const QHashedS
QQmlError error;
if (u1 != u2) {
- error.setDescription(QQmlImportDatabase::tr("is ambiguous. Found in %1 and in %2").arg(u1).arg(u2));
+ error.setDescription(
+ QQmlImportDatabase::tr(
+ "is ambiguous. Found in %1 and in %2")
+ .arg(u1, u2));
} else {
- error.setDescription(QQmlImportDatabase::tr("is ambiguous. Found in %1 in version %2.%3 and %4.%5")
- .arg(u1)
- .arg(import->version.majorVersion())
- .arg(import->version.minorVersion())
- .arg(import2->version.majorVersion())
- .arg(import2->version.minorVersion()));
+ error.setDescription(
+ QQmlImportDatabase::tr(
+ "is ambiguous. Found in %1 in version "
+ "%2.%3 and %4.%5")
+ .arg(u1)
+ .arg(import->version.majorVersion())
+ .arg(import->version.minorVersion())
+ .arg(import2->version.majorVersion())
+ .arg(import2->version.minorVersion()));
}
errors->prepend(error);
}
@@ -1093,30 +878,9 @@ bool QQmlImportNamespace::resolveType(QQmlTypeLoader *typeLoader, const QHashedS
return false;
}
-bool QQmlImportNamespace::needsSorting() const
-{
- return nextNamespace == this;
-}
-
-void QQmlImportNamespace::setNeedsSorting(bool needsSorting)
+QQmlImportNamespace *QQmlImports::findQualifiedNamespace(const QHashedStringRef &prefix) const
{
- Q_ASSERT(nextNamespace == this || nextNamespace == nullptr);
- nextNamespace = needsSorting ? this : nullptr;
-}
-
-QQmlImportsPrivate::QQmlImportsPrivate(QQmlTypeLoader *loader)
-: ref(1), typeLoader(loader) {
-}
-
-QQmlImportsPrivate::~QQmlImportsPrivate()
-{
- while (QQmlImportNamespace *ns = qualifiedSets.takeFirst())
- delete ns;
-}
-
-QQmlImportNamespace *QQmlImportsPrivate::findQualifiedNamespace(const QHashedStringRef &prefix) const
-{
- for (QQmlImportNamespace *ns = qualifiedSets.first(); ns; ns = qualifiedSets.next(ns)) {
+ for (QQmlImportNamespace *ns = m_qualifiedSets.first(); ns; ns = m_qualifiedSets.next(ns)) {
if (prefix == ns->prefix)
return ns;
}
@@ -1124,229 +888,75 @@ QQmlImportNamespace *QQmlImportsPrivate::findQualifiedNamespace(const QHashedStr
}
/*
- Returns the list of possible versioned URI combinations. For example, if \a uri is
- QtQml.Models, \a vmaj is 2, and \a vmin is 0, this method returns the following:
- [QtQml.Models.2.0, QtQml.2.0.Models, QtQml.Models.2, QtQml.2.Models, QtQml.Models]
- */
-static QStringList versionUriList(const QString &uri, QTypeRevision version)
-{
- QStringList result;
- for (int mode = QQmlImports::FullyVersioned; mode <= QQmlImports::Unversioned; ++mode) {
- int index = uri.length();
- do {
- QString versionUri = uri;
- versionUri.insert(index, QQmlImports::versionString(
- version, QQmlImports::ImportVersion(mode)));
- result += versionUri;
-
- index = uri.lastIndexOf(Dot, index - 1);
- } while (index > 0 && mode != QQmlImports::Unversioned);
- }
- return result;
-}
-
-static QVector<QStaticPlugin> makePlugins()
-{
- QVector<QStaticPlugin> plugins;
- // To avoid traversing all static plugins for all imports, we cut down
- // the list the first time called to only contain QML plugins:
- const auto staticPlugins = QPluginLoader::staticPlugins();
- for (const QStaticPlugin &plugin : staticPlugins) {
- const QString iid = plugin.metaData().value(QLatin1String("IID")).toString();
- if (iid == QLatin1String(QQmlEngineExtensionInterface_iid)
- || iid == QLatin1String(QQmlExtensionInterface_iid)
- || iid == QLatin1String(QQmlExtensionInterface_iid_old)) {
- plugins.append(plugin);
- }
- }
- return plugins;
-}
-
-/*
- Get all static plugins that are QML plugins and has a meta data URI that matches with one of
- \a versionUris, which is a list of all possible versioned URI combinations - see versionUriList()
- above.
- */
-bool QQmlImportsPrivate::populatePluginPairVector(QVector<StaticPluginPair> &result, const QString &uri, const QStringList &versionUris,
- const QString &qmldirPath, QList<QQmlError> *errors)
-{
- static const QVector<QStaticPlugin> plugins = makePlugins();
- for (const QStaticPlugin &plugin : plugins) {
- // Since a module can list more than one plugin, we keep iterating even after we found a match.
- QObject *instance = plugin.instance();
- if (qobject_cast<QQmlEngineExtensionPlugin *>(instance)
- || qobject_cast<QQmlExtensionPlugin *>(instance)) {
- const QJsonArray metaTagsUriList = plugin.metaData().value(QLatin1String("uri")).toArray();
- if (metaTagsUriList.isEmpty()) {
- if (errors) {
- QQmlError error;
- error.setDescription(QQmlImportDatabase::tr("static plugin for module \"%1\" with name \"%2\" has no metadata URI")
- .arg(uri).arg(QString::fromUtf8(instance->metaObject()->className())));
- error.setUrl(QUrl::fromLocalFile(qmldirPath));
- errors->prepend(error);
- }
- return false;
- }
- // A plugin can be set up to handle multiple URIs, so go through the list:
- for (const QJsonValue metaTagUri : metaTagsUriList) {
- if (versionUris.contains(metaTagUri.toString())) {
- result.append(qMakePair(plugin, metaTagsUriList));
- break;
- }
- }
- }
- }
- return true;
-}
-
-/*
Import an extension defined by a qmldir file.
*/
-QTypeRevision QQmlImportsPrivate::importExtension(
- const QString &uri, QTypeRevision version, QQmlImportDatabase *database,
- const QQmlTypeLoaderQmldirContent &qmldir, QList<QQmlError> *errors)
+QTypeRevision QQmlImports::importExtension(
+ QQmlTypeLoader *typeLoader, const QString &uri, QTypeRevision version,
+ const QQmlTypeLoaderQmldirContent *qmldir, QList<QQmlError> *errors)
{
- Q_ASSERT(qmldir.hasContent());
+ Q_ASSERT(qmldir->hasContent());
- const QString qmldirFilePath = qmldir.qmldirLocation();
- if (qmlImportTrace())
- qDebug().nospace() << "QQmlImports(" << qPrintable(base) << ")::importExtension: "
- << "loaded " << qmldirFilePath;
+ qCDebug(lcQmlImport)
+ << "importExtension:" << qPrintable(m_base) << "loaded" << qmldir->qmldirLocation();
- if (designerSupportRequired && !qmldir.designerSupported()) {
+ if (designerSupportRequired && !qmldir->designerSupported()) {
if (errors) {
QQmlError error;
- error.setDescription(QQmlImportDatabase::tr("module does not support the designer \"%1\"").arg(qmldir.typeNamespace()));
- error.setUrl(QUrl::fromLocalFile(qmldirFilePath));
+ error.setDescription(
+ QQmlImportDatabase::tr("module does not support the designer \"%1\"")
+ .arg(qmldir->typeNamespace()));
+ error.setUrl(QUrl::fromLocalFile(qmldir->qmldirLocation()));
errors->prepend(error);
}
return QTypeRevision();
}
- int qmldirPluginCount = qmldir.plugins().count();
- if (qmldirPluginCount == 0)
+ if (qmldir->plugins().isEmpty()) {
+ // If the qmldir does not register a plugin, we might still have declaratively
+ // registered types (if we are dealing with an application instead of a library)
+ if (!QQmlMetaType::typeModule(uri, version))
+ QQmlMetaType::qmlRegisterModuleTypes(uri);
return validVersion(version);
+ }
- if (!database->qmlDirFilesForWhichPluginsHaveBeenLoaded.contains(qmldirFilePath)) {
- // First search for listed qmldir plugins dynamically. If we cannot resolve them all, we continue
- // searching static plugins that has correct metadata uri. Note that since we only know the uri
- // for a static plugin, and not the filename, we cannot know which static plugin belongs to which
- // listed plugin inside qmldir. And for this reason, mixing dynamic and static plugins inside a
- // single module is not recommended.
-
- QString typeNamespace = qmldir.typeNamespace();
- QString qmldirPath = qmldirFilePath;
- int slash = qmldirPath.lastIndexOf(Slash);
- if (slash > 0)
- qmldirPath.truncate(slash);
-
- int dynamicPluginsFound = 0;
- int staticPluginsFound = 0;
-
- const auto qmldirPlugins = qmldir.plugins();
- for (const QQmlDirParser::Plugin &plugin : qmldirPlugins) {
- const QString resolvedFilePath = database->resolvePlugin(
- typeLoader, qmldirPath, plugin.path, plugin.name);
-
- if (resolvedFilePath.isEmpty())
- continue;
-
- ++dynamicPluginsFound;
- version = database->importDynamicPlugin(
- resolvedFilePath, uri, typeNamespace, version, plugin.optional, errors);
- if (!version.isValid())
- return QTypeRevision();
- }
-
- if (dynamicPluginsFound < qmldirPluginCount) {
- // Check if the missing plugins can be resolved statically. We do this by looking at
- // the URIs embedded in a plugins meta data. Since those URIs can be anything from fully
- // versioned to unversioned, we need to compare with differnt version strings. If a module
- // has several plugins, they must all have the same version. Start by populating pluginPairs
- // with relevant plugins to cut the list short early on:
- const QStringList versionUris = versionUriList(uri, version);
- QVector<StaticPluginPair> pluginPairs;
- if (!populatePluginPairVector(pluginPairs, uri, versionUris, qmldirFilePath, errors))
- return QTypeRevision();
-
- const QString basePath = QFileInfo(qmldirPath).absoluteFilePath();
- for (const QString &versionUri : versionUris) {
- for (const StaticPluginPair &pair : qAsConst(pluginPairs)) {
- for (const QJsonValue metaTagUri : pair.second) {
- if (versionUri == metaTagUri.toString()) {
- staticPluginsFound++;
- QObject *instance = pair.first.instance();
- version = database->importStaticPlugin(
- instance, basePath, uri, typeNamespace, version, errors);
- if (!version.isValid()){
- if (errors) {
- Q_ASSERT(!errors->isEmpty());
- QQmlError poppedError = errors->takeFirst();
- QQmlError error;
- error.setDescription(QQmlImportDatabase::tr("static plugin for module \"%1\" with name \"%2\" cannot be loaded: %3")
- .arg(uri).arg(QString::fromUtf8(instance->metaObject()->className())).arg(poppedError.description()));
- error.setUrl(QUrl::fromLocalFile(qmldirFilePath));
- errors->prepend(error);
- }
- return QTypeRevision();
- }
-
- if (qmlImportTrace())
- qDebug().nospace() << "QQmlImports(" << qPrintable(base) << ")::importExtension: "
- << "loaded static plugin " << versionUri;
+ QQmlPluginImporter importer(
+ uri, version, typeLoader->importDatabase(), qmldir, typeLoader, errors);
+ return importer.importPlugins();
+}
- break;
- }
- }
- }
- if (staticPluginsFound > 0)
- break;
- }
- }
+QString QQmlImports::redirectQmldirContent(
+ QQmlTypeLoader *typeLoader, QQmlTypeLoaderQmldirContent *qmldir)
+{
+ const QString preferredPath = qmldir->preferredPath();
+ const QString url = preferredPath.startsWith(u':')
+ ? QStringLiteral("qrc") + preferredPath
+ : QUrl::fromLocalFile(preferredPath).toString();
- if ((dynamicPluginsFound + staticPluginsFound) < qmldirPluginCount) {
- if (errors) {
- QQmlError error;
- if (qmldirPluginCount > 1 && staticPluginsFound > 0)
- error.setDescription(QQmlImportDatabase::tr("could not resolve all plugins for module \"%1\"").arg(uri));
- else
- error.setDescription(QQmlImportDatabase::tr("module \"%1\" plugin \"%2\" not found").arg(uri).arg(qmldir.plugins()[dynamicPluginsFound].name));
- error.setUrl(QUrl::fromLocalFile(qmldirFilePath));
- errors->prepend(error);
- }
- return QTypeRevision();
- }
+ QQmlTypeLoaderQmldirContent redirected
+ = typeLoader->qmldirContent(url + QLatin1String("qmldir"));
- database->qmlDirFilesForWhichPluginsHaveBeenLoaded.insert(qmldirFilePath);
- }
- return validVersion(version);
+ // Ignore errors: If the qmldir doesn't exist, stick to the old one.
+ if (redirected.hasContent() && !redirected.hasError())
+ *qmldir = std::move(redirected);
+ return url;
}
-bool QQmlImportsPrivate::getQmldirContent(const QString &qmldirIdentifier, const QString &uri,
- QQmlTypeLoaderQmldirContent *qmldir, QList<QQmlError> *errors)
+bool QQmlImports::getQmldirContent(
+ QQmlTypeLoader *typeLoader, const QString &qmldirIdentifier, const QString &uri,
+ QQmlTypeLoaderQmldirContent *qmldir, QList<QQmlError> *errors)
{
Q_ASSERT(errors);
Q_ASSERT(qmldir);
*qmldir = typeLoader->qmldirContent(qmldirIdentifier);
- if ((*qmldir).hasContent()) {
- // Ensure that parsing was successful
- if ((*qmldir).hasError()) {
- QUrl url = QUrl::fromLocalFile(qmldirIdentifier);
- const QList<QQmlError> qmldirErrors = (*qmldir).errors(uri);
- for (int i = 0; i < qmldirErrors.size(); ++i) {
- QQmlError error = qmldirErrors.at(i);
- error.setUrl(url);
- errors->append(error);
- }
- return false;
- }
- }
+ if (!qmldir->hasContent() || !qmldir->hasError())
+ return true;
- return true;
+ errors->append(qmldir->errors(uri, QUrl::fromLocalFile(qmldirIdentifier)));
+ return false;
}
-QString QQmlImportsPrivate::resolvedUri(const QString &dir_arg, QQmlImportDatabase *database)
+QString QQmlImports::resolvedUri(const QString &dir_arg, QQmlImportDatabase *database)
{
QString dir = dir_arg;
if (dir.endsWith(Slash) || dir.endsWith(Backslash))
@@ -1357,9 +967,9 @@ QString QQmlImportsPrivate::resolvedUri(const QString &dir_arg, QQmlImportDataba
std::sort(paths.begin(), paths.end(), std::greater<QString>()); // Ensure subdirs preceed their parents.
QString stableRelativePath = dir;
- for (const QString &path : qAsConst(paths)) {
+ for (const QString &path : std::as_const(paths)) {
if (dir.startsWith(path)) {
- stableRelativePath = dir.mid(path.length()+1);
+ stableRelativePath = dir.mid(path.size()+1);
break;
}
}
@@ -1381,89 +991,24 @@ QString QQmlImportsPrivate::resolvedUri(const QString &dir_arg, QQmlImportDataba
return stableRelativePath;
}
-/*
-Locates the qmldir file for \a uri version \a vmaj.vmin. Returns true if found,
-and fills in outQmldirFilePath and outQmldirUrl appropriately. Otherwise returns
-false.
-*/
-QQmlImports::LocalQmldirResult QQmlImportsPrivate::locateLocalQmldir(
- const QString &uri, QTypeRevision version, QQmlImportDatabase *database,
- QString *outQmldirFilePath, QString *outQmldirPathUrl)
-{
- // Check cache first
-
- QQmlImportDatabase::QmldirCache *cacheHead = nullptr;
- {
- QQmlImportDatabase::QmldirCache **cachePtr = database->qmldirCache.value(uri);
- if (cachePtr) {
- cacheHead = *cachePtr;
- QQmlImportDatabase::QmldirCache *cache = cacheHead;
- while (cache) {
- if (cache->version == version) {
- *outQmldirFilePath = cache->qmldirFilePath;
- *outQmldirPathUrl = cache->qmldirPathUrl;
- return cache->qmldirFilePath.isEmpty() ? QQmlImports::QmldirNotFound
- : QQmlImports::QmldirFound;
- }
- cache = cache->next;
- }
- }
- }
+/*!
+ \internal
- QQmlEnginePrivate *enginePrivate = QQmlEnginePrivate::get(database->engine);
- QQmlTypeLoader &typeLoader = enginePrivate->typeLoader;
- const bool hasInterceptors = !enginePrivate->urlInterceptors.isEmpty();
-
- // Interceptor might redirect remote files to local ones.
- QStringList localImportPaths = database->importPathList(
- hasInterceptors ? QQmlImportDatabase::LocalOrRemote : QQmlImportDatabase::Local);
-
- // Search local import paths for a matching version
- const QStringList qmlDirPaths = QQmlImports::completeQmldirPaths(
- uri, localImportPaths, version);
- bool pathTurnedRemote = false;
- for (QString qmldirPath : qmlDirPaths) {
- if (hasInterceptors) {
- const QUrl intercepted = database->engine->interceptUrl(
- QQmlImports::urlFromLocalFileOrQrcOrUrl(qmldirPath),
- QQmlAbstractUrlInterceptor::QmldirFile);
- qmldirPath = QQmlFile::urlToLocalFileOrQrc(intercepted);
- if (!pathTurnedRemote && qmldirPath.isEmpty() && !QQmlFile::isLocalFile(intercepted))
- pathTurnedRemote = true;
- }
+ \fn template<typename Callback>
+ QQmlImportDatabase::LocalQmldirResult QQmlImportDatabase::locateLocalQmldir(
+ const QString &uri, QTypeRevision version, const Callback &callback)
- QString absoluteFilePath = typeLoader.absoluteFilePath(qmldirPath);
- if (!absoluteFilePath.isEmpty()) {
- QString url;
- const QStringView absolutePath = QStringView{absoluteFilePath}.left(absoluteFilePath.lastIndexOf(Slash) + 1);
- if (absolutePath.at(0) == Colon)
- url = QLatin1String("qrc") + absolutePath;
- else
- url = QUrl::fromLocalFile(absolutePath.toString()).toString();
-
- QQmlImportDatabase::QmldirCache *cache = new QQmlImportDatabase::QmldirCache;
- cache->version = version;
- cache->qmldirFilePath = absoluteFilePath;
- cache->qmldirPathUrl = url;
- cache->next = cacheHead;
- database->qmldirCache.insert(uri, cache);
-
- *outQmldirFilePath = absoluteFilePath;
- *outQmldirPathUrl = url;
-
- return QQmlImports::QmldirFound;
- }
- }
+ Locates the qmldir files for \a uri version \a version. For each one, calls
+ the \a callback. If the \a callback returns \c true, returns QmldirFound.
- QQmlImportDatabase::QmldirCache *cache = new QQmlImportDatabase::QmldirCache;
- cache->version = version;
- cache->next = cacheHead;
- database->qmldirCache.insert(uri, cache);
+ If at least one callback invocation returned \c false and there are no qmldir
+ files left to check, returns QmldirRejected.
- return pathTurnedRemote ? QQmlImports::QmldirInterceptedToRemote : QQmlImports::QmldirNotFound;
-}
+ Otherwise, if interception redirects a previously local qmldir URL to a remote
+ one, returns QmldirInterceptedToRemote. Otherwise, returns QmldirNotFound.
+*/
-QTypeRevision QQmlImportsPrivate::matchingQmldirVersion(
+QTypeRevision QQmlImports::matchingQmldirVersion(
const QQmlTypeLoaderQmldirContent &qmldir, const QString &uri, QTypeRevision version,
QList<QQmlError> *errors)
{
@@ -1498,9 +1043,11 @@ QTypeRevision QQmlImportsPrivate::matchingQmldirVersion(
if (cit2->typeName == cit->typeName && cit2->version == cit->version) {
// This entry clashes with a predecessor
QQmlError error;
- error.setDescription(QQmlImportDatabase::tr("\"%1\" version %2.%3 is defined more than once in module \"%4\"")
- .arg(cit->typeName).arg(cit->version.majorVersion())
- .arg(cit->version.minorVersion()).arg(uri));
+ error.setDescription(
+ QQmlImportDatabase::tr(
+ "\"%1\" version %2.%3 is defined more than once in module \"%4\"")
+ .arg(cit->typeName).arg(cit->version.majorVersion())
+ .arg(cit->version.minorVersion()).arg(uri));
errors->prepend(error);
return QTypeRevision();
}
@@ -1550,28 +1097,28 @@ QTypeRevision QQmlImportsPrivate::matchingQmldirVersion(
: highestMinorVersion);
}
-QQmlImportNamespace *QQmlImportsPrivate::importNamespace(const QString &prefix) const
+QQmlImportNamespace *QQmlImports::importNamespace(const QString &prefix)
{
QQmlImportNamespace *nameSpace = nullptr;
if (prefix.isEmpty()) {
- nameSpace = &unqualifiedset;
+ nameSpace = &m_unqualifiedset;
} else {
nameSpace = findQualifiedNamespace(prefix);
if (!nameSpace) {
nameSpace = new QQmlImportNamespace;
nameSpace->prefix = prefix;
- qualifiedSets.append(nameSpace);
+ m_qualifiedSets.append(nameSpace);
}
}
return nameSpace;
}
-QQmlImportInstance *QQmlImportsPrivate::addImportToNamespace(
+static QQmlImportInstance *addImportToNamespace(
QQmlImportNamespace *nameSpace, const QString &uri, const QString &url, QTypeRevision version,
- QV4::CompiledData::Import::ImportType type, QList<QQmlError> *errors, uint flags)
+ QV4::CompiledData::Import::ImportType type, QList<QQmlError> *errors, quint16 precedence)
{
Q_ASSERT(nameSpace);
Q_ASSERT(errors);
@@ -1583,59 +1130,59 @@ QQmlImportInstance *QQmlImportsPrivate::addImportToNamespace(
import->url = url;
import->version = version;
import->isLibrary = (type == QV4::CompiledData::Import::ImportLibrary);
- if (flags & QQmlImports::ImportImplicit) {
- import->implicitlyImported = true;
- nameSpace->imports.append(import);
- } else if (flags & QQmlImports::ImportLowPrecedence) {
- if (nameSpace->imports.isEmpty()) {
- nameSpace->imports.append(import);
- } else {
- for (auto it = nameSpace->imports.rbegin(), end = nameSpace->imports.rend();
- it != end; ++it) {
+ import->precedence = precedence;
+ import->implicitlyImported = precedence >= QQmlImportInstance::Implicit;
- if (!(*it)->implicitlyImported) {
- nameSpace->imports.insert(it.base(), import);
- break;
- }
- }
- }
- } else {
- nameSpace->imports.prepend(import);
- }
+ for (auto it = nameSpace->imports.cbegin(), end = nameSpace->imports.cend();
+ it != end; ++it) {
+ if ((*it)->precedence < precedence)
+ continue;
+ nameSpace->imports.insert(it, import);
+ return import;
+ }
+ nameSpace->imports.append(import);
return import;
}
-QTypeRevision QQmlImportsPrivate::addLibraryImport(
- const QString &uri, const QString &prefix, QTypeRevision version,
- const QString &qmldirIdentifier, const QString &qmldirUrl, uint flags,
- QQmlImportDatabase *database, QList<QQmlError> *errors)
+QTypeRevision QQmlImports::addLibraryImport(
+ QQmlTypeLoader *typeLoader, const QString &uri, const QString &prefix,
+ QTypeRevision version, const QString &qmldirIdentifier, const QString &qmldirUrl,
+ ImportFlags flags, quint16 precedence, QList<QQmlError> *errors)
{
- Q_ASSERT(database);
+ Q_ASSERT(typeLoader);
Q_ASSERT(errors);
+ qCDebug(lcQmlImport)
+ << "addLibraryImport:" << qPrintable(baseUrl().toString())
+ << uri << "version '" << version << "'" << "as" << prefix;
+
QQmlImportNamespace *nameSpace = importNamespace(prefix);
Q_ASSERT(nameSpace);
QQmlImportInstance *inserted = addImportToNamespace(
nameSpace, uri, qmldirUrl, version,
QV4::CompiledData::Import::ImportLibrary, errors,
- flags);
+ precedence);
Q_ASSERT(inserted);
if (!(flags & QQmlImports::ImportIncomplete)) {
QQmlTypeLoaderQmldirContent qmldir;
if (!qmldirIdentifier.isEmpty()) {
- if (!getQmldirContent(qmldirIdentifier, uri, &qmldir, errors))
+ if (!getQmldirContent(typeLoader, qmldirIdentifier, uri, &qmldir, errors))
return QTypeRevision();
if (qmldir.hasContent()) {
- version = importExtension(uri, version, database, qmldir, errors);
+ version = importExtension(typeLoader, uri, version, &qmldir, errors);
if (!version.isValid())
return QTypeRevision();
- if (!inserted->setQmldirContent(qmldirUrl, qmldir, nameSpace, errors))
+ const QString resolvedUrl = qmldir.hasRedirection()
+ ? redirectQmldirContent(typeLoader, &qmldir)
+ : qmldirUrl;
+
+ if (!inserted->setQmldirContent(resolvedUrl, qmldir, nameSpace, errors))
return QTypeRevision();
}
}
@@ -1646,8 +1193,12 @@ QTypeRevision QQmlImportsPrivate::addLibraryImport(
return matchingVersion;
if (inserted->qmlDirComponents.isEmpty() && inserted->qmlDirScripts.isEmpty()) {
- if (qmldir.plugins().isEmpty() && !qmldir.imports().isEmpty())
- return validVersion(); // This is a pure redirection
+ if (qmldir.plugins().isEmpty()) {
+ if (!qmldir.imports().isEmpty())
+ return validVersion(); // This is a pure redirection
+ if (qmldir.hasTypeInfo())
+ return validVersion(); // A pure C++ module without plugin
+ }
errors->prepend(moduleNotFoundError(uri, relevantVersion(uri, version)));
return QTypeRevision();
} else if (qmldir.hasContent()) {
@@ -1661,10 +1212,51 @@ QTypeRevision QQmlImportsPrivate::addLibraryImport(
return validVersion(version);
}
-QTypeRevision QQmlImportsPrivate::addFileImport(
- const QString& uri, const QString &prefix, QTypeRevision version, uint flags,
- QQmlImportDatabase *database, QList<QQmlError> *errors)
+/*!
+ \internal
+
+ Adds information to \a database such that subsequent calls to resolveType()
+ will resolve types qualified by \a prefix by considering types found at the given \a uri.
+
+ The \a uri is either a directory (if importType is FileImport), or a URI resolved using paths
+ added via addImportPath() (if importType is LibraryImport).
+
+ The \a prefix may be empty, in which case the import location is considered for
+ unqualified types.
+
+ The base URL must already have been set with Import::setBaseUrl().
+
+ Optionally, the qmldir the import resolved to can be returned by providing the \a localQmldir
+ parameter. Not all imports will have a local qmldir. If there is none, the \a localQmldir
+ parameter won't be set.
+
+ Returns a valid QTypeRevision on success, and an invalid one on failure.
+ In case of failure, the \a errors array will filled appropriately.
+*/
+QTypeRevision QQmlImports::addFileImport(
+ QQmlTypeLoader *typeLoader, const QString &uri, const QString &prefix,
+ QTypeRevision version, ImportFlags flags, quint16 precedence, QString *localQmldir,
+ QList<QQmlError> *errors)
{
+ Q_ASSERT(typeLoader);
+ Q_ASSERT(errors);
+
+ qCDebug(lcQmlImport)
+ << "addFileImport:" << qPrintable(baseUrl().toString())
+ << uri << version << "as" << prefix;
+
+ if (uri.startsWith(Slash) || uri.startsWith(Colon)) {
+ QQmlError error;
+ const QString fix = uri.startsWith(Slash) ? QLatin1String("file:") + uri
+ : QLatin1String("qrc") + uri;
+ error.setDescription(QQmlImportDatabase::tr(
+ "\"%1\" is not a valid import URL. "
+ "You can pass relative paths or URLs with schema, but not "
+ "absolute paths or resource paths. Try \"%2\".").arg(uri, fix));
+ errors->prepend(error);
+ return QTypeRevision();
+ }
+
Q_ASSERT(errors);
QQmlImportNamespace *nameSpace = importNamespace(prefix);
@@ -1673,7 +1265,7 @@ QTypeRevision QQmlImportsPrivate::addFileImport(
// The uri for this import. For library imports this is the same as uri
// specified by the user, but it may be different in the case of file imports.
QString importUri = uri;
- QString qmldirUrl = resolveLocalUrl(base, importUri + (importUri.endsWith(Slash)
+ QString qmldirUrl = resolveLocalUrl(m_base, importUri + (importUri.endsWith(Slash)
? String_qmldir
: Slash_qmldir));
qmldirUrl = typeLoader->engine()->interceptUrl(
@@ -1687,7 +1279,7 @@ QTypeRevision QQmlImportsPrivate::addFileImport(
const QString dir = localFileOrQrc.left(localFileOrQrc.lastIndexOf(Slash) + 1);
if (!typeLoader->directoryExists(dir)) {
- if (!(flags & QQmlImports::ImportImplicit)) {
+ if (precedence < QQmlImportInstance::Implicit) {
QQmlError error;
error.setDescription(QQmlImportDatabase::tr("\"%1\": no such directory").arg(uri));
error.setUrl(QUrl(qmldirUrl));
@@ -1698,16 +1290,19 @@ QTypeRevision QQmlImportsPrivate::addFileImport(
// Transforms the (possible relative) uri into our best guess relative to the
// import paths.
- importUri = resolvedUri(dir, database);
+ importUri = resolvedUri(dir, typeLoader->importDatabase());
if (importUri.endsWith(Slash))
importUri.chop(1);
- if (!typeLoader->absoluteFilePath(localFileOrQrc).isEmpty())
- qmldirIdentifier = localFileOrQrc;
+ if (!typeLoader->absoluteFilePath(localFileOrQrc).isEmpty()) {
+ qmldirIdentifier = std::move(localFileOrQrc);
+ if (localQmldir)
+ *localQmldir = qmldirIdentifier;
+ }
} else if (nameSpace->prefix.isEmpty() && !(flags & QQmlImports::ImportIncomplete)) {
- if (!(flags & QQmlImports::ImportImplicit)) {
+ if (precedence < QQmlImportInstance::Implicit) {
QQmlError error;
error.setDescription(QQmlImportDatabase::tr("import \"%1\" has no qmldir and no namespace").arg(importUri));
error.setUrl(QUrl(qmldirUrl));
@@ -1719,7 +1314,16 @@ QTypeRevision QQmlImportsPrivate::addFileImport(
}
// The url for the path containing files for this import
- QString url = resolveLocalUrl(base, uri);
+ QString url = resolveLocalUrl(m_base, uri);
+ if (url.isEmpty()) {
+ QQmlError error;
+ error.setDescription(
+ QQmlImportDatabase::tr("Cannot resolve URL for import \"%1\"").arg(uri));
+ error.setUrl(m_baseUrl);
+ errors->prepend(error);
+ return QTypeRevision();
+ }
+
if (!url.endsWith(Slash) && !url.endsWith(Backslash))
url += Slash;
@@ -1727,7 +1331,7 @@ QTypeRevision QQmlImportsPrivate::addFileImport(
// if the implicit import has already been explicitly added, otherwise we can run into issues
// with duplicate imports. However remember that we attempted to add this as implicit import, to
// allow for the loading of internal types.
- if (flags & QQmlImports::ImportImplicit) {
+ if (precedence >= QQmlImportInstance::Implicit) {
for (QList<QQmlImportInstance *>::const_iterator it = nameSpace->imports.constBegin();
it != nameSpace->imports.constEnd(); ++it) {
if ((*it)->url == url) {
@@ -1737,49 +1341,73 @@ QTypeRevision QQmlImportsPrivate::addFileImport(
}
}
- QQmlImportInstance *inserted = addImportToNamespace(
- nameSpace, importUri, url, version, QV4::CompiledData::Import::ImportFile,
- errors, flags);
- Q_ASSERT(inserted);
- if (flags & QQmlImports::ImportImplicit)
- inserted->implicitlyImported = true;
-
if (!(flags & QQmlImports::ImportIncomplete) && !qmldirIdentifier.isEmpty()) {
QQmlTypeLoaderQmldirContent qmldir;
- if (!getQmldirContent(qmldirIdentifier, importUri, &qmldir, errors))
+ if (!getQmldirContent(typeLoader, qmldirIdentifier, importUri, &qmldir, errors))
return QTypeRevision();
if (qmldir.hasContent()) {
- version = importExtension(importUri, version, database, qmldir, errors);
+ // Prefer the qmldir URI. Unless it doesn't exist.
+ const QString qmldirUri = qmldir.typeNamespace();
+ if (!qmldirUri.isEmpty())
+ importUri = qmldirUri;
+
+ QQmlImportInstance *inserted = addImportToNamespace(
+ nameSpace, importUri, url, version, QV4::CompiledData::Import::ImportFile,
+ errors, precedence);
+ Q_ASSERT(inserted);
+
+ version = importExtension(typeLoader, importUri, version, &qmldir, errors);
if (!version.isValid())
return QTypeRevision();
+ if (qmldir.hasRedirection())
+ url = redirectQmldirContent(typeLoader, &qmldir);
+
if (!inserted->setQmldirContent(url, qmldir, nameSpace, errors))
return QTypeRevision();
+
+ return validVersion(version);
}
}
+ QQmlImportInstance *inserted = addImportToNamespace(
+ nameSpace, importUri, url, version, QV4::CompiledData::Import::ImportFile,
+ errors, precedence);
+ Q_ASSERT(inserted);
return validVersion(version);
}
-QTypeRevision QQmlImportsPrivate::updateQmldirContent(const QString &uri, const QString &prefix,
- const QString &qmldirIdentifier, const QString& qmldirUrl,
- QQmlImportDatabase *database, QList<QQmlError> *errors)
+QTypeRevision QQmlImports::updateQmldirContent(
+ QQmlTypeLoader *typeLoader, const QString &uri, const QString &prefix,
+ const QString &qmldirIdentifier, const QString &qmldirUrl, QList<QQmlError> *errors)
{
+ Q_ASSERT(typeLoader);
+ Q_ASSERT(errors);
+
+ qDebug(lcQmlImport)
+ << "updateQmldirContent:" << qPrintable(baseUrl().toString())
+ << uri << "to" << qmldirUrl << "as" << prefix;
+
QQmlImportNamespace *nameSpace = importNamespace(prefix);
Q_ASSERT(nameSpace);
if (QQmlImportInstance *import = nameSpace->findImport(uri)) {
QQmlTypeLoaderQmldirContent qmldir;
- if (!getQmldirContent(qmldirIdentifier, uri, &qmldir, errors))
+ if (!getQmldirContent(typeLoader, qmldirIdentifier, uri, &qmldir, errors))
return QTypeRevision();
if (qmldir.hasContent()) {
- QTypeRevision version = importExtension(uri, import->version, database, qmldir, errors);
+ QTypeRevision version = importExtension(
+ typeLoader, uri, import->version, &qmldir, errors);
if (!version.isValid())
return QTypeRevision();
- if (import->setQmldirContent(qmldirUrl, qmldir, nameSpace, errors)) {
+ const QString resolvedUrl = qmldir.hasRedirection()
+ ? redirectQmldirContent(typeLoader, &qmldir)
+ : qmldirUrl;
+
+ if (import->setQmldirContent(resolvedUrl, qmldir, nameSpace, errors)) {
if (import->qmlDirComponents.isEmpty() && import->qmlDirScripts.isEmpty()) {
// The implicit import qmldir can be empty, and plugins have no extra versions
if (uri != QLatin1String(".") && !QQmlMetaType::matchingModuleVersion(uri, version).isValid()) {
@@ -1807,6 +1435,7 @@ QTypeRevision QQmlImportsPrivate::updateQmldirContent(const QString &uri, const
}
/*!
+ \fn QQmlImports::addImplicitImport(QQmlTypeLoader *typeLoader, QString *localQmldir, QList<QQmlError> *errors)
\internal
Adds an implicit "." file import. This is equivalent to calling addFileImport(), but error
@@ -1814,122 +1443,28 @@ QTypeRevision QQmlImportsPrivate::updateQmldirContent(const QString &uri, const
Additionally, this will add the import with lowest instead of highest precedence.
*/
-QTypeRevision QQmlImports::addImplicitImport(QQmlImportDatabase *importDb, QList<QQmlError> *errors)
-{
- Q_ASSERT(errors);
-
- if (qmlImportTrace())
- qDebug().nospace() << "QQmlImports(" << qPrintable(baseUrl().toString())
- << ")::addImplicitImport";
- uint flags = ImportImplicit | (!isLocal(baseUrl()) ? ImportIncomplete : 0);
- return d->addFileImport(QLatin1String("."), QString(), QTypeRevision(), flags,
- importDb, errors);
-}
/*!
\internal
*/
-bool QQmlImports::addInlineComponentImport(QQmlImportInstance *const importInstance, const QString &name, const QUrl importUrl, QQmlType containingType)
+bool QQmlImports::addInlineComponentImport(QQmlImportInstance *const importInstance, const QString &name, const QUrl importUrl)
{
importInstance->url = importUrl.toString();
importInstance->uri = name;
importInstance->isInlineComponent = true;
importInstance->version = QTypeRevision::zero();
- importInstance->containingType = containingType;
- d->unqualifiedset.imports.push_back(importInstance);
- d->unqualifiedset.setNeedsSorting(true);
+ m_unqualifiedset.imports.push_back(importInstance);
+ m_unqualifiedset.setNeedsSorting(true);
return true;
}
-/*!
- \internal
-
- Adds information to \a imports such that subsequent calls to resolveType()
- will resolve types qualified by \a prefix by considering types found at the given \a uri.
-
- The uri is either a directory (if importType is FileImport), or a URI resolved using paths
- added via addImportPath() (if importType is LibraryImport).
-
- The \a prefix may be empty, in which case the import location is considered for
- unqualified types.
-
- The base URL must already have been set with Import::setBaseUrl().
-
- Optionally, the url the import resolved to can be returned by providing the url parameter.
- Not all imports will result in an output url being generated, in which case the url will
- be set to an empty string.
-
- Returns true on success, and false on failure. In case of failure, the errors array will
- filled appropriately.
-*/
-QTypeRevision QQmlImports::addFileImport(
- QQmlImportDatabase *importDb, const QString& uri, const QString& prefix,
- QTypeRevision version, uint flags, QList<QQmlError> *errors)
-{
- Q_ASSERT(importDb);
- Q_ASSERT(errors);
-
- if (qmlImportTrace())
- qDebug().nospace() << "QQmlImports(" << qPrintable(baseUrl().toString()) << ')' << "::addFileImport: "
- << uri << ' ' << version << " as " << prefix;
-
- return d->addFileImport(uri, prefix, version, flags, importDb, errors);
-}
-
-QTypeRevision QQmlImports::addLibraryImport(
- QQmlImportDatabase *importDb, const QString &uri, const QString &prefix,
- QTypeRevision version, const QString &qmldirIdentifier, const QString& qmldirUrl,
- uint flags, QList<QQmlError> *errors)
-{
- Q_ASSERT(importDb);
- Q_ASSERT(errors);
-
- if (qmlImportTrace())
- qDebug().nospace() << "QQmlImports(" << qPrintable(baseUrl().toString()) << ')' << "::addLibraryImport: "
- << uri << ' ' << version << " as " << prefix;
-
- return d->addLibraryImport(uri, prefix, version, qmldirIdentifier, qmldirUrl, flags,
- importDb, errors);
-}
-
-QTypeRevision QQmlImports::updateQmldirContent(
- QQmlImportDatabase *importDb, const QString &uri, const QString &prefix,
- const QString &qmldirIdentifier, const QString& qmldirUrl, QList<QQmlError> *errors)
-{
- Q_ASSERT(importDb);
- Q_ASSERT(errors);
-
- if (qmlImportTrace())
- qDebug().nospace() << "QQmlImports(" << qPrintable(baseUrl().toString()) << ')' << "::updateQmldirContent: "
- << uri << " to " << qmldirUrl << " as " << prefix;
-
- return d->updateQmldirContent(uri, prefix, qmldirIdentifier, qmldirUrl, importDb, errors);
-}
-
-QQmlImports::LocalQmldirResult QQmlImports::locateLocalQmldir(
- QQmlImportDatabase *importDb, const QString &uri, QTypeRevision version,
- QString *qmldirFilePath, QString *url)
-{
- return d->locateLocalQmldir(uri, version, importDb, qmldirFilePath, url);
-}
-
-bool QQmlImports::isLocal(const QString &url)
-{
- return !QQmlFile::urlToLocalFileOrQrc(url).isEmpty();
-}
-
-bool QQmlImports::isLocal(const QUrl &url)
-{
- return !QQmlFile::urlToLocalFileOrQrc(url).isEmpty();
-}
-
QUrl QQmlImports::urlFromLocalFileOrQrcOrUrl(const QString &file)
{
QUrl url(QLatin1String(file.at(0) == Colon ? "qrc" : "") + file);
// We don't support single character schemes as those conflict with windows drive letters.
- if (url.scheme().length() < 2)
+ if (url.scheme().size() < 2)
return QUrl::fromLocalFile(file);
return url;
}
@@ -1939,7 +1474,7 @@ void QQmlImports::setDesignerSupportRequired(bool b)
designerSupportRequired = b;
}
-static QStringList parseEnvImportPath(const QString &envImportPath)
+static QStringList parseEnvPath(const QString &envImportPath)
{
if (QDir::listSeparator() == u':') {
// Double colons are interpreted as separator + resource path.
@@ -1972,15 +1507,22 @@ QQmlImportDatabase::QQmlImportDatabase(QQmlEngine *e)
: engine(e)
{
filePluginPath << QLatin1String(".");
- // Search order is applicationDirPath(), qrc:/qt-project.org/imports, $QML_IMPORT_PATH, $QML2_IMPORT_PATH, QLibraryInfo::QmlImportsPath
+ // Search order is:
+ // 1. android or macos specific bundle paths.
+ // 2. applicationDirPath()
+ // 3. qrc:/qt-project.org/imports
+ // 4. qrc:/qt/qml
+ // 5. $QML2_IMPORT_PATH
+ // 6. $QML_IMPORT_PATH
+ // 7. QLibraryInfo::QmlImportsPath
QString installImportsPath = QLibraryInfo::path(QLibraryInfo::QmlImportsPath);
addImportPath(installImportsPath);
auto addEnvImportPath = [this](const char *var) {
if (Q_UNLIKELY(!qEnvironmentVariableIsEmpty(var))) {
- const QStringList paths = parseEnvImportPath(qEnvironmentVariable(var));
- for (int ii = paths.count() - 1; ii >= 0; --ii)
+ const QStringList paths = parseEnvPath(qEnvironmentVariable(var));
+ for (int ii = paths.size() - 1; ii >= 0; --ii)
addImportPath(paths.at(ii));
}
};
@@ -1989,155 +1531,40 @@ QQmlImportDatabase::QQmlImportDatabase(QQmlEngine *e)
addEnvImportPath("QML_IMPORT_PATH");
addEnvImportPath("QML2_IMPORT_PATH");
+ addImportPath(QStringLiteral("qrc:/qt/qml"));
addImportPath(QStringLiteral("qrc:/qt-project.org/imports"));
addImportPath(QCoreApplication::applicationDirPath());
-#if defined(Q_OS_ANDROID)
- addImportPath(QStringLiteral("qrc:/android_rcc_bundle/qml"));
- if (Q_UNLIKELY(!qEnvironmentVariableIsEmpty("QT_BUNDLED_LIBS_PATH"))) {
- const QString envImportPath = qEnvironmentVariable("QT_BUNDLED_LIBS_PATH");
- QLatin1Char pathSep(':');
- QStringList paths = envImportPath.split(pathSep, Qt::SkipEmptyParts);
- for (int ii = paths.count() - 1; ii >= 0; --ii)
- addPluginPath(paths.at(ii));
- }
-#endif
-}
-
-QQmlImportDatabase::~QQmlImportDatabase()
-{
- clearDirCache();
-}
-
-/*!
- \internal
-
- Returns the result of the merge of \a baseName with \a path, \a suffixes, and \a prefix.
- The \a prefix must contain the dot.
-
- \a qmldirPath is the location of the qmldir file.
- */
-QString QQmlImportDatabase::resolvePlugin(QQmlTypeLoader *typeLoader,
- const QString &qmldirPath,
- const QString &qmldirPluginPath,
- const QString &baseName, const QStringList &suffixes,
- const QString &prefix) const
-{
- QStringList searchPaths = filePluginPath;
- bool qmldirPluginPathIsRelative = QDir::isRelativePath(qmldirPluginPath);
- if (!qmldirPluginPathIsRelative)
- searchPaths.prepend(qmldirPluginPath);
-
- for (const QString &pluginPath : qAsConst(searchPaths)) {
- QString resolvedPath;
- if (pluginPath == QLatin1String(".")) {
- if (qmldirPluginPathIsRelative && !qmldirPluginPath.isEmpty() && qmldirPluginPath != QLatin1String("."))
- resolvedPath = QDir::cleanPath(qmldirPath + Slash + qmldirPluginPath);
- else
- resolvedPath = qmldirPath;
- } else {
- if (QDir::isRelativePath(pluginPath))
- resolvedPath = QDir::cleanPath(qmldirPath + Slash + pluginPath);
- else
- resolvedPath = pluginPath;
- }
-
- // hack for resources, should probably go away
- if (resolvedPath.startsWith(Colon))
- resolvedPath = QCoreApplication::applicationDirPath();
-
- if (!resolvedPath.endsWith(Slash))
- resolvedPath += Slash;
-#if defined(Q_OS_ANDROID)
- if (qmldirPath.size() > 25 && qmldirPath.at(0) == QLatin1Char(':') && qmldirPath.at(1) == QLatin1Char('/') &&
- qmldirPath.startsWith(QStringLiteral(":/android_rcc_bundle/qml/"), Qt::CaseInsensitive)) {
- QString pluginName = qmldirPath.mid(21) + Slash + baseName;
- pluginName.replace(QLatin1Char('/'), QLatin1Char('_'));
- QString bundledPath = resolvedPath + QLatin1String("lib") + pluginName;
- for (const QString &suffix : suffixes) {
- const QString absolutePath = typeLoader->absoluteFilePath(bundledPath + suffix);
- if (!absolutePath.isEmpty())
- return absolutePath;
- }
- }
-#endif
- resolvedPath += prefix + baseName;
- for (const QString &suffix : suffixes) {
- const QString absolutePath = typeLoader->absoluteFilePath(resolvedPath + suffix);
- if (!absolutePath.isEmpty())
- return absolutePath;
+ auto addEnvPluginPath = [this](const char *var) {
+ if (Q_UNLIKELY(!qEnvironmentVariableIsEmpty(var))) {
+ const QStringList paths = parseEnvPath(qEnvironmentVariable(var));
+ for (int ii = paths.size() - 1; ii >= 0; --ii)
+ addPluginPath(paths.at(ii));
}
- }
-
- if (qmlImportTrace())
- qDebug() << "QQmlImportDatabase::resolvePlugin: Could not resolve plugin" << baseName
- << "in" << qmldirPath;
-
- return QString();
-}
-
-/*!
- \internal
-
- Returns the result of the merge of \a baseName with \a dir and the platform suffix.
-
- \table
- \header \li Platform \li Valid suffixes
- \row \li Windows \li \c .dll
- \row \li Unix/Linux \li \c .so
- \row \li \macos \li \c .dylib, \c .bundle, \c .so
- \endtable
-
- Version number on unix are ignored.
-*/
-QString QQmlImportDatabase::resolvePlugin(QQmlTypeLoader *typeLoader,
- const QString &qmldirPath, const QString &qmldirPluginPath,
- const QString &baseName) const
-{
-#if defined(Q_OS_WIN)
- static const QString prefix;
- static const QStringList suffixes = {
-# ifdef QT_DEBUG
- QLatin1String("d.dll"), // try a qmake-style debug build first
- QLatin1String(".dll")
-#else
- QLatin1String(".dll"),
- QLatin1String("d.dll") // try a qmake-style debug build after
-# endif
- };
-#elif defined(Q_OS_DARWIN)
- static const QString prefix = QLatin1String("lib");
- static const QStringList suffixes = {
-# ifdef QT_DEBUG
- QLatin1String("_debug.dylib"), // try a qmake-style debug build first
- QLatin1String(".dylib"),
-# else
- QLatin1String(".dylib"),
- QLatin1String("_debug.dylib"), // try a qmake-style debug build after
-# endif
- QLatin1String(".so"),
- QLatin1String(".bundle")
};
-#else // Unix
- static const QString prefix = QLatin1String("lib");
- static const QStringList suffixes = {
-# if defined(Q_OS_ANDROID)
- QStringLiteral(LIBS_SUFFIX),
-# endif
- QLatin1String(".so")
- };
-#endif
-
- return resolvePlugin(typeLoader, qmldirPath, qmldirPluginPath, baseName, suffixes, prefix);
-}
-
-/*!
- \internal
-*/
-QStringList QQmlImportDatabase::pluginPathList() const
-{
- return filePluginPath;
+ addEnvPluginPath("QML_PLUGIN_PATH");
+#if defined(Q_OS_ANDROID)
+ addImportPath(QStringLiteral("qrc:/android_rcc_bundle/qml"));
+ addEnvPluginPath("QT_BUNDLED_LIBS_PATH");
+#elif defined(Q_OS_MACOS)
+ // Add the main bundle's Resources/qml directory as an import path, so that QML modules are
+ // found successfully when running the app from its build dir.
+ // This is where macdeployqt and our CMake deployment logic puts Qt and user qmldir files.
+ if (CFBundleRef bundleRef = CFBundleGetMainBundle()) {
+ if (QCFType<CFURLRef> urlRef = CFBundleCopyResourceURL(
+ bundleRef,
+ QCFString(QLatin1String("qml")), 0, 0)) {
+ if (QCFType<CFURLRef> absoluteUrlRef = CFURLCopyAbsoluteURL(urlRef)) {
+ if (QCFString path = CFURLCopyFileSystemPath(absoluteUrlRef, kCFURLPOSIXPathStyle)) {
+ if (QFile::exists(path)) {
+ addImportPath(QDir(path).canonicalPath());
+ }
+ }
+ }
+ }
+ }
+#endif // Q_OS_DARWIN
}
/*!
@@ -2145,9 +1572,7 @@ QStringList QQmlImportDatabase::pluginPathList() const
*/
void QQmlImportDatabase::setPluginPathList(const QStringList &paths)
{
- if (qmlImportTrace())
- qDebug().nospace() << "QQmlImportDatabase::setPluginPathList: " << paths;
-
+ qCDebug(lcQmlImport) << "setPluginPathList:" << paths;
filePluginPath = paths;
}
@@ -2156,12 +1581,11 @@ void QQmlImportDatabase::setPluginPathList(const QStringList &paths)
*/
void QQmlImportDatabase::addPluginPath(const QString& path)
{
- if (qmlImportTrace())
- qDebug().nospace() << "QQmlImportDatabase::addPluginPath: " << path;
+ qCDebug(lcQmlImport) << "addPluginPath:" << path;
QUrl url = QUrl(path);
if (url.isRelative() || url.scheme() == QLatin1String("file")
- || (url.scheme().length() == 1 && QFile::exists(path)) ) { // windows path
+ || (url.scheme().size() == 1 && QFile::exists(path)) ) { // windows path
QDir dir = QDir(path);
filePluginPath.prepend(dir.canonicalPath());
} else {
@@ -2169,13 +1593,17 @@ void QQmlImportDatabase::addPluginPath(const QString& path)
}
}
+QString QQmlImportDatabase::absoluteFilePath(const QString &path) const
+{
+ return QQmlEnginePrivate::get(engine)->typeLoader.absoluteFilePath(path);
+}
+
/*!
\internal
*/
void QQmlImportDatabase::addImportPath(const QString& path)
{
- if (qmlImportTrace())
- qDebug().nospace() << "QQmlImportDatabase::addImportPath: " << path;
+ qCDebug(lcQmlImport) << "addImportPath:" << path;
if (path.isEmpty())
return;
@@ -2191,7 +1619,7 @@ void QQmlImportDatabase::addImportPath(const QString& path)
cPath = QLatin1String("qrc") + path;
cPath.replace(Backslash, Slash);
} else if (url.isRelative() ||
- (url.scheme().length() == 1 && QFile::exists(path)) ) { // windows path
+ (url.scheme().size() == 1 && QFile::exists(path)) ) { // windows path
QDir dir = QDir(path);
cPath = dir.canonicalPath();
} else {
@@ -2230,8 +1658,7 @@ QStringList QQmlImportDatabase::importPathList(PathType type) const
*/
void QQmlImportDatabase::setImportPathList(const QStringList &paths)
{
- if (qmlImportTrace())
- qDebug().nospace() << "QQmlImportDatabase::setImportPathList: " << paths;
+ qCDebug(lcQmlImport) << "setImportPathList:" << paths;
fileImportPath.clear();
for (auto it = paths.crbegin(); it != paths.crend(); ++it)
@@ -2244,8 +1671,8 @@ void QQmlImportDatabase::setImportPathList(const QStringList &paths)
/*!
\internal
*/
-static QTypeRevision lockModule(const QString &uri, const QString &typeNamespace,
- QTypeRevision version, QList<QQmlError> *errors)
+QTypeRevision QQmlImportDatabase::lockModule(const QString &uri, const QString &typeNamespace,
+ QTypeRevision version, QList<QQmlError> *errors)
{
if (!version.hasMajorVersion()) {
version = QQmlMetaType::latestModuleVersion(uri);
@@ -2266,165 +1693,14 @@ static QTypeRevision lockModule(const QString &uri, const QString &typeNamespace
return version;
}
-/*!
- \internal
-*/
-QTypeRevision QQmlImportDatabase::importStaticPlugin(
- QObject *instance, const QString &basePath, const QString &uri,
- const QString &typeNamespace, QTypeRevision version, QList<QQmlError> *errors)
+bool QQmlImportDatabase::removeDynamicPlugin(const QString &pluginId)
{
- // Dynamic plugins are differentiated by their filepath. For static plugins we
- // don't have that information so we use their address as key instead.
- const QString uniquePluginID = QString::asprintf("%p", instance);
- {
- PathPluginMapPtr plugins(qmlPluginsByPath());
-
- // Plugin types are global across all engines and should only be
- // registered once. But each engine still needs to be initialized.
- bool typesRegistered = plugins->find(uniquePluginID) != plugins->end();
-
- if (!typesRegistered) {
- plugins->insert(std::make_pair(uniquePluginID, QmlPlugin()));
- if (QQmlMetaType::registerPluginTypes(
- instance, basePath, uri, typeNamespace, version, errors)
- == QQmlMetaType::RegistrationResult::Failure) {
- return QTypeRevision();
- }
-
- version = lockModule(uri, typeNamespace, version, errors);
- if (!version.isValid())
- return QTypeRevision();
- }
-
- // Release the lock on plugins early as we're done with the global part. Releasing the lock
- // also allows other QML loader threads to acquire the lock while this thread is blocking
- // in the initializeEngine call to the gui thread (which in turn may be busy waiting for
- // other QML loader threads and thus not process the initializeEngine call).
- }
-
- if (!initializedPlugins.contains(uniquePluginID))
- finalizePlugin(instance, uniquePluginID, uri);
-
- return validVersion(version);
-}
-
-/*!
- \internal
-*/
-QTypeRevision QQmlImportDatabase::importDynamicPlugin(
- const QString &filePath, const QString &uri, const QString &typeNamespace,
- QTypeRevision version, bool isOptional, QList<QQmlError> *errors)
-{
- QFileInfo fileInfo(filePath);
- const QString absoluteFilePath = fileInfo.absoluteFilePath();
-
- QObject *instance = nullptr;
- bool engineInitialized = initializedPlugins.contains(absoluteFilePath);
- {
- PathPluginMapPtr plugins(qmlPluginsByPath());
- bool typesRegistered = plugins->find(absoluteFilePath) != plugins->end();
-
- if (!engineInitialized || !typesRegistered) {
- if (!QQml_isFileCaseCorrect(absoluteFilePath)) {
- if (errors) {
- QQmlError error;
- error.setDescription(tr("File name case mismatch for \"%1\"").arg(absoluteFilePath));
- errors->prepend(error);
- }
- return QTypeRevision();
- }
-
- QmlPlugin plugin;
-
- const QString absolutePath = fileInfo.absolutePath();
- if (!typesRegistered && isOptional) {
- switch (QQmlMetaType::registerPluginTypes(nullptr, absolutePath, uri, typeNamespace,
- version, errors)) {
- case QQmlMetaType::RegistrationResult::NoRegistrationFunction:
- // try again with plugin
- break;
- case QQmlMetaType::RegistrationResult::Success:
- version = lockModule(uri, typeNamespace, version, errors);
- if (!version.isValid())
- return QTypeRevision();
- // instance and loader intentionally left at nullptr
- plugins->insert(std::make_pair(absoluteFilePath, std::move(plugin)));
- // Not calling initializeEngine with null instance
- initializedPlugins.insert(absoluteFilePath);
- return version;
- case QQmlMetaType::RegistrationResult::Failure:
- return QTypeRevision();
- }
- }
-
-#if QT_CONFIG(library)
- if (!typesRegistered) {
- plugin.loader = std::make_unique<QPluginLoader>(absoluteFilePath);
- if (!plugin.loader->load()) {
- if (errors) {
- QQmlError error;
- error.setDescription(plugin.loader->errorString());
- errors->prepend(error);
- }
- return QTypeRevision();
- }
-
- instance = plugin.loader->instance();
- plugins->insert(std::make_pair(absoluteFilePath, std::move(plugin)));
-
- // Continue with shared code path for dynamic and static plugins:
- if (QQmlMetaType::registerPluginTypes(
- instance, fileInfo.absolutePath(), uri, typeNamespace, version, errors)
- == QQmlMetaType::RegistrationResult::Failure) {
- return QTypeRevision();
- }
-
- version = lockModule(uri, typeNamespace, version, errors);
- if (!version.isValid())
- return QTypeRevision();
- } else {
- auto it = plugins->find(absoluteFilePath);
- if (it != plugins->end() && it->second.loader)
- instance = it->second.loader->instance();
- }
-#endif // QT_CONFIG(library)
- }
-
- // Release the lock on plugins early as we're done with the global part. Releasing the lock
- // also allows other QML loader threads to acquire the lock while this thread is blocking
- // in the initializeEngine call to the gui thread (which in turn may be busy waiting for
- // other QML loader threads and thus not process the initializeEngine call).
- }
-
- if (!engineInitialized)
- finalizePlugin(instance, absoluteFilePath, uri);
-
- return validVersion(version);
-}
-
-bool QQmlImportDatabase::removeDynamicPlugin(const QString &filePath)
-{
- PathPluginMapPtr plugins(qmlPluginsByPath());
-
- auto it = plugins->find(QFileInfo(filePath).absoluteFilePath());
- if (it == plugins->end())
- return false;
-
- const bool success = unloadPlugin(*it);
-
- plugins->erase(it);
- return success;
+ return QQmlPluginImporter::removePlugin(pluginId);
}
QStringList QQmlImportDatabase::dynamicPlugins() const
{
- PathPluginMapPtr plugins(qmlPluginsByPath());
- QStringList results;
- for (auto it = plugins->cbegin(), end = plugins->cend(); it != end; ++it) {
- if (it->second.loader != nullptr)
- results.append(it->first);
- }
- return results;
+ return QQmlPluginImporter::plugins();
}
void QQmlImportDatabase::clearDirCache()
@@ -2443,20 +1719,4 @@ void QQmlImportDatabase::clearDirCache()
qmldirCache.clear();
}
-void QQmlImportDatabase::finalizePlugin(QObject *instance, const QString &path, const QString &uri)
-{
- // The plugin's per-engine initialization does not need lock protection, as this function is
- // only called from the engine specific loader thread and importDynamicPlugin as well as
- // importStaticPlugin are the only places of access.
-
- initializedPlugins.insert(path);
- if (auto *extensionIface = qobject_cast<QQmlExtensionInterface *>(instance)) {
- QQmlEnginePrivate::get(engine)->typeLoader.initializeEngine(
- extensionIface, uri.toUtf8().constData());
- } else if (auto *engineIface = qobject_cast<QQmlEngineExtensionInterface *>(instance)) {
- QQmlEnginePrivate::get(engine)->typeLoader.initializeEngine(
- engineIface, uri.toUtf8().constData());
- }
-}
-
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlimport_p.h b/src/qml/qml/qqmlimport_p.h
index 7a8e1f9dd4..ef9b4b3422 100644
--- a/src/qml/qml/qqmlimport_p.h
+++ b/src/qml/qml/qqmlimport_p.h
@@ -1,53 +1,21 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLIMPORT_P_H
#define QQMLIMPORT_P_H
#include <QtCore/qurl.h>
#include <QtCore/qcoreapplication.h>
+#include <QtCore/qloggingcategory.h>
#include <QtCore/qset.h>
#include <QtCore/qstringlist.h>
+#include <QtQml/qqmlengine.h>
#include <QtQml/qqmlerror.h>
+#include <QtQml/qqmlfile.h>
#include <private/qqmldirparser_p.h>
#include <private/qqmltype_p.h>
#include <private/qstringhash_p.h>
+#include <private/qfieldlist_p.h>
//
// W A R N I N G
@@ -66,10 +34,12 @@ class QQmlTypeNameCache;
class QQmlEngine;
class QDir;
class QQmlImportNamespace;
-class QQmlImportsPrivate;
class QQmlImportDatabase;
class QQmlTypeLoader;
class QQmlTypeLoaderQmldirContent;
+class QTypeRevision;
+
+const QLoggingCategory &lcQmlImport();
namespace QQmlImport {
enum RecursionRestriction { PreventRecursion, AllowRecursion };
@@ -77,13 +47,24 @@ namespace QQmlImport {
struct QQmlImportInstance
{
+ enum Precedence {
+ Lowest = std::numeric_limits<quint8>::max(),
+ Implicit = Lowest / 2,
+ Highest = 0,
+ };
+
QString uri; // e.g. QtQuick
QString url; // the base path of the import
- QQmlType containingType; // points to the containing type for inline components
QTypeRevision version; // the version imported
+
bool isLibrary; // true means that this is not a file import
+
+ // not covered by precedence. You can set a component as implicitly imported after the fact.
bool implicitlyImported = false;
bool isInlineComponent = false;
+
+ quint8 precedence = 0;
+
QQmlDirComponents qmlDirComponents; // a copy of the components listed in the qmldir
QQmlDirScripts qmlDirScripts; // a copy of the scripts in the qmldir
@@ -95,7 +76,7 @@ struct QQmlImportInstance
bool resolveType(QQmlTypeLoader *typeLoader, const QHashedStringRef &type,
QTypeRevision *version_return, QQmlType* type_return,
- QString *base = nullptr, bool *typeRecursionDetected = nullptr,
+ const QString *base = nullptr, bool *typeRecursionDetected = nullptr,
QQmlType::RegistrationType = QQmlType::AnyRegistrationType,
QQmlImport::RecursionRestriction recursionRestriction = QQmlImport::PreventRecursion,
QList<QQmlError> *errors = nullptr) const;
@@ -113,77 +94,85 @@ public:
bool resolveType(QQmlTypeLoader *typeLoader, const QHashedStringRef& type,
QTypeRevision *version_return, QQmlType* type_return,
- QString *base = nullptr, QList<QQmlError> *errors = nullptr,
+ const QString *base = nullptr, QList<QQmlError> *errors = nullptr,
QQmlType::RegistrationType registrationType = QQmlType::AnyRegistrationType,
bool *typeRecursionDeteced = nullptr);
// Prefix when used as a qualified import. Otherwise empty.
QHashedString prefix;
- // Used by QQmlImportsPrivate::qualifiedSets
+ // Used by QQmlImports::m_qualifiedSets
// set to this in unqualifiedSet to indicate that the lists of imports needs
// to be sorted when an inline component import was added
// We can't use flag pointer, as that does not work with QFieldList
- QQmlImportNamespace *nextNamespace;
- bool needsSorting() const;
- void setNeedsSorting(bool needsSorting);
+ QQmlImportNamespace *nextNamespace = nullptr;
+ bool needsSorting() const { return nextNamespace == this; }
+ void setNeedsSorting(bool needsSorting)
+ {
+ Q_ASSERT(nextNamespace == this || nextNamespace == nullptr);
+ nextNamespace = needsSorting ? this : nullptr;
+ }
};
-class Q_QML_PRIVATE_EXPORT QQmlImports
+class Q_QML_EXPORT QQmlImports final : public QQmlRefCounted<QQmlImports>
{
+ Q_DISABLE_COPY_MOVE(QQmlImports)
public:
enum ImportVersion { FullyVersioned, PartiallyVersioned, Unversioned };
- enum ImportFlag { ImportIncomplete = 0x1, ImportLowPrecedence = 0x2, ImportImplicit = 0x4 };
- QQmlImports(QQmlTypeLoader *);
- QQmlImports(const QQmlImports &);
- ~QQmlImports();
- QQmlImports &operator=(const QQmlImports &);
+ enum ImportFlag : quint8 {
+ ImportNoFlag = 0x0,
+ ImportIncomplete = 0x1,
+ };
+ Q_DECLARE_FLAGS(ImportFlags, ImportFlag)
+
+ QQmlImports() = default;
+ ~QQmlImports()
+ {
+ while (QQmlImportNamespace *ns = m_qualifiedSets.takeFirst())
+ delete ns;
+ }
void setBaseUrl(const QUrl &url, const QString &urlString = QString());
- QUrl baseUrl() const;
+ QUrl baseUrl() const { return m_baseUrl; }
- bool resolveType(const QHashedStringRef &type,
- QQmlType *type_return,
- QTypeRevision *version_return,
- QQmlImportNamespace **ns_return,
- QList<QQmlError> *errors = nullptr,
- QQmlType::RegistrationType registrationType = QQmlType::AnyRegistrationType,
- bool *typeRecursionDetected = nullptr) const;
- bool resolveType(QQmlImportNamespace *,
- const QHashedStringRef& type,
- QQmlType *type_return, QTypeRevision *version_return,
- QQmlType::RegistrationType registrationType
- = QQmlType::AnyRegistrationType) const;
+ bool resolveType(
+ QQmlTypeLoader *typeLoader, const QHashedStringRef &type, QQmlType *type_return,
+ QTypeRevision *version_return, QQmlImportNamespace **ns_return,
+ QList<QQmlError> *errors = nullptr,
+ QQmlType::RegistrationType registrationType = QQmlType::AnyRegistrationType,
+ bool *typeRecursionDetected = nullptr) const;
QTypeRevision addImplicitImport(
- QQmlImportDatabase *importDb, QList<QQmlError> *errors);
+ QQmlTypeLoader *typeLoader, QString *localQmldir, QList<QQmlError> *errors)
+ {
+ Q_ASSERT(errors);
+ qCDebug(lcQmlImport) << "addImplicitImport:" << qPrintable(baseUrl().toString());
+
+ const ImportFlags flags =
+ ImportFlags(!isLocal(baseUrl()) ? ImportIncomplete : ImportNoFlag);
+ return addFileImport(
+ typeLoader, QLatin1String("."), QString(), QTypeRevision(), flags,
+ QQmlImportInstance::Implicit, localQmldir, errors);
+ }
- bool addInlineComponentImport(QQmlImportInstance *const importInstance, const QString &name, const QUrl importUrl, QQmlType containingType);
+ bool addInlineComponentImport(
+ QQmlImportInstance *const importInstance, const QString &name, const QUrl importUrl);
QTypeRevision addFileImport(
- QQmlImportDatabase *, const QString& uri, const QString& prefix, QTypeRevision version,
- uint flags, QList<QQmlError> *errors);
+ QQmlTypeLoader *typeLoader, const QString &uri, const QString &prefix,
+ QTypeRevision version, ImportFlags flags, quint16 precedence, QString *localQmldir,
+ QList<QQmlError> *errors);
QTypeRevision addLibraryImport(
- QQmlImportDatabase *importDb, const QString &uri, const QString &prefix,
+ QQmlTypeLoader *typeLoader, const QString &uri, const QString &prefix,
QTypeRevision version, const QString &qmldirIdentifier, const QString &qmldirUrl,
- uint flags, QList<QQmlError> *errors);
+ ImportFlags flags, quint16 precedence, QList<QQmlError> *errors);
QTypeRevision updateQmldirContent(
- QQmlImportDatabase *importDb, const QString &uri, const QString &prefix,
+ QQmlTypeLoader *typeLoader, const QString &uri, const QString &prefix,
const QString &qmldirIdentifier, const QString &qmldirUrl, QList<QQmlError> *errors);
- enum LocalQmldirResult {
- QmldirFound,
- QmldirNotFound,
- QmldirInterceptedToRemote
- };
-
- LocalQmldirResult locateLocalQmldir(
- QQmlImportDatabase *, const QString &uri, QTypeRevision version,
- QString *qmldirFilePath, QString *url);
-
void populateCache(QQmlTypeNameCache *cache) const;
struct ScriptReference
@@ -204,58 +193,118 @@ public:
QList<CompositeSingletonReference> resolvedCompositeSingletons() const;
- static QStringList completeQmldirPaths(const QString &uri, const QStringList &basePaths,
- QTypeRevision version);
+ static QStringList completeQmldirPaths(
+ const QString &uri, const QStringList &basePaths, QTypeRevision version);
+
static QString versionString(QTypeRevision version, ImportVersion importVersion);
- static bool isLocal(const QString &url);
- static bool isLocal(const QUrl &url);
+ static bool isLocal(const QString &url)
+ {
+ return !QQmlFile::urlToLocalFileOrQrc(url).isEmpty();
+ }
+
+ static bool isLocal(const QUrl &url)
+ {
+ return !QQmlFile::urlToLocalFileOrQrc(url).isEmpty();
+ }
+
static QUrl urlFromLocalFileOrQrcOrUrl(const QString &);
static void setDesignerSupportRequired(bool b);
+ static QTypeRevision validVersion(QTypeRevision version = QTypeRevision());
+
private:
friend class QQmlImportDatabase;
- QQmlImportsPrivate *d;
+
+ QQmlImportNamespace *importNamespace(const QString &prefix);
+
+ bool resolveType(
+ QQmlTypeLoader *typeLoader, const QHashedStringRef &type, QTypeRevision *version_return,
+ QQmlType *type_return, QList<QQmlError> *errors,
+ QQmlType::RegistrationType registrationType,
+ bool *typeRecursionDetected = nullptr) const;
+
+ QQmlImportNamespace *findQualifiedNamespace(const QHashedStringRef &) const;
+
+ static QTypeRevision matchingQmldirVersion(
+ const QQmlTypeLoaderQmldirContent &qmldir, const QString &uri,
+ QTypeRevision version, QList<QQmlError> *errors);
+
+ QTypeRevision importExtension(
+ QQmlTypeLoader *typeLoader, const QString &uri, QTypeRevision version,
+ const QQmlTypeLoaderQmldirContent *qmldir, QList<QQmlError> *errors);
+
+ QString redirectQmldirContent(QQmlTypeLoader *typeLoader, QQmlTypeLoaderQmldirContent *qmldir);
+
+ bool getQmldirContent(
+ QQmlTypeLoader *typeLoader, const QString &qmldirIdentifier, const QString &uri,
+ QQmlTypeLoaderQmldirContent *qmldir, QList<QQmlError> *errors);
+
+ QString resolvedUri(const QString &dir_arg, QQmlImportDatabase *database);
+
+ QUrl m_baseUrl;
+ QString m_base;
+
+ // storage of data related to imports without a namespace
+ // TODO: This needs to be mutable because QQmlImportNamespace likes to sort itself on
+ // resolveType(). Therefore, QQmlImportNamespace::resolveType() is not const.
+ // There should be a better way to do this.
+ mutable QQmlImportNamespace m_unqualifiedset;
+
+ // storage of data related to imports with a namespace
+ QFieldList<QQmlImportNamespace, &QQmlImportNamespace::nextNamespace> m_qualifiedSets;
};
-class Q_QML_PRIVATE_EXPORT QQmlImportDatabase
+Q_DECLARE_OPERATORS_FOR_FLAGS(QQmlImports::ImportFlags)
+
+class Q_QML_EXPORT QQmlImportDatabase
{
Q_DECLARE_TR_FUNCTIONS(QQmlImportDatabase)
public:
enum PathType { Local, Remote, LocalOrRemote };
+ enum LocalQmldirSearchLocation {
+ QmldirFileAndCache,
+ QmldirCacheOnly,
+ };
+
+ enum LocalQmldirResult {
+ QmldirFound,
+ QmldirNotFound,
+ QmldirInterceptedToRemote,
+ QmldirRejected
+ };
+
QQmlImportDatabase(QQmlEngine *);
- ~QQmlImportDatabase();
+ ~QQmlImportDatabase() { clearDirCache(); }
- QTypeRevision importDynamicPlugin(
- const QString &filePath, const QString &uri, const QString &importNamespace,
- QTypeRevision version, bool isOptional, QList<QQmlError> *errors);
- bool removeDynamicPlugin(const QString &filePath);
+ bool removeDynamicPlugin(const QString &pluginId);
QStringList dynamicPlugins() const;
QStringList importPathList(PathType type = LocalOrRemote) const;
void setImportPathList(const QStringList &paths);
void addImportPath(const QString& dir);
- QStringList pluginPathList() const;
+ QStringList pluginPathList() const { return filePluginPath; }
void setPluginPathList(const QStringList &paths);
+
void addPluginPath(const QString& path);
- QString resolvePlugin(QQmlTypeLoader *typeLoader,
- const QString &qmldirPath, const QString &qmldirPluginPath,
- const QString &baseName) const;
+ template<typename Callback>
+ LocalQmldirResult locateLocalQmldir(
+ const QString &uri, QTypeRevision version, LocalQmldirSearchLocation location,
+ const Callback &callback);
+
+ static QTypeRevision lockModule(const QString &uri, const QString &typeNamespace,
+ QTypeRevision version, QList<QQmlError> *errors);
+
private:
- friend class QQmlImportsPrivate;
- QString resolvePlugin(QQmlTypeLoader *typeLoader,
- const QString &qmldirPath, const QString &qmldirPluginPath,
- const QString &baseName, const QStringList &suffixes,
- const QString &prefix = QString()) const;
- QTypeRevision importStaticPlugin(
- QObject *instance, const QString &basePath, const QString &uri,
- const QString &typeNamespace, QTypeRevision version, QList<QQmlError> *errors);
+ friend class QQmlImports;
+ friend class QQmlPluginImporter;
+
+ QString absoluteFilePath(const QString &path) const;
void clearDirCache();
- void finalizePlugin(QObject *instance, const QString &path, const QString &uri);
struct QmldirCache {
QTypeRevision version;
@@ -264,18 +313,136 @@ private:
QmldirCache *next;
};
// Maps from an import to a linked list of qmldir info.
- // Used in QQmlImportsPrivate::locateQmldir()
+ // Used in QQmlImports::locateQmldir()
QStringHash<QmldirCache *> qmldirCache;
// XXX thread
QStringList filePluginPath;
QStringList fileImportPath;
- QSet<QString> qmlDirFilesForWhichPluginsHaveBeenLoaded;
+ QSet<QString> modulesForWhichPluginsHaveBeenLoaded;
QSet<QString> initializedPlugins;
QQmlEngine *engine;
};
+template<typename Callback>
+QQmlImportDatabase::LocalQmldirResult QQmlImportDatabase::locateLocalQmldir(
+ const QString &uri, QTypeRevision version,
+ QQmlImportDatabase::LocalQmldirSearchLocation location, const Callback &callback)
+{
+ // Check cache first
+
+ LocalQmldirResult result = QmldirNotFound;
+ QmldirCache *cacheTail = nullptr;
+
+ QmldirCache **cachePtr = qmldirCache.value(uri);
+ QmldirCache *cacheHead = cachePtr ? *cachePtr : nullptr;
+ if (cacheHead) {
+ cacheTail = cacheHead;
+ do {
+ if (cacheTail->version == version) {
+ if (cacheTail->qmldirFilePath.isEmpty()) {
+ return cacheTail->qmldirPathUrl.isEmpty()
+ ? QmldirNotFound
+ : QmldirInterceptedToRemote;
+ }
+ if (callback(cacheTail->qmldirFilePath, cacheTail->qmldirPathUrl))
+ return QmldirFound;
+ result = QmldirRejected;
+ }
+ } while (cacheTail->next && (cacheTail = cacheTail->next));
+ }
+
+
+ // Do not try to construct the cache if it already had any entries for the URI.
+ // Otherwise we might duplicate cache entries.
+ if (location == QmldirCacheOnly || result != QmldirNotFound)
+ return result;
+
+ const bool hasInterceptors = !engine->urlInterceptors().isEmpty();
+
+ // Interceptor might redirect remote files to local ones.
+ QStringList localImportPaths = importPathList(hasInterceptors ? LocalOrRemote : Local);
+
+ // Search local import paths for a matching version
+ const QStringList qmlDirPaths = QQmlImports::completeQmldirPaths(
+ uri, localImportPaths, version);
+
+ QString qmldirAbsoluteFilePath;
+ for (QString qmldirPath : qmlDirPaths) {
+ if (hasInterceptors) {
+ const QUrl intercepted = engine->interceptUrl(
+ QQmlImports::urlFromLocalFileOrQrcOrUrl(qmldirPath),
+ QQmlAbstractUrlInterceptor::QmldirFile);
+ qmldirPath = QQmlFile::urlToLocalFileOrQrc(intercepted);
+ if (result != QmldirInterceptedToRemote
+ && qmldirPath.isEmpty()
+ && !QQmlFile::isLocalFile(intercepted)) {
+ result = QmldirInterceptedToRemote;
+ }
+ }
+
+ qmldirAbsoluteFilePath = absoluteFilePath(qmldirPath);
+ if (!qmldirAbsoluteFilePath.isEmpty()) {
+ QString url;
+ const QString absolutePath = qmldirAbsoluteFilePath.left(
+ qmldirAbsoluteFilePath.lastIndexOf(u'/') + 1);
+ if (absolutePath.at(0) == u':') {
+ url = QStringLiteral("qrc") + absolutePath;
+ } else {
+ url = QUrl::fromLocalFile(absolutePath).toString();
+ // This handles the UNC path case as when the path is retrieved from the QUrl it
+ // will convert the host name from upper case to lower case. So the absoluteFilePath
+ // is changed at this point to make sure it will match later on in that case.
+ if (qmldirAbsoluteFilePath.startsWith(QStringLiteral("//"))) {
+ qmldirAbsoluteFilePath = QUrl::fromLocalFile(qmldirAbsoluteFilePath)
+ .toString(QUrl::RemoveScheme);
+ }
+ }
+
+ QmldirCache *cache = new QmldirCache;
+ cache->version = version;
+ cache->qmldirFilePath = qmldirAbsoluteFilePath;
+ cache->qmldirPathUrl = url;
+ cache->next = nullptr;
+ if (cacheTail)
+ cacheTail->next = cache;
+ else
+ qmldirCache.insert(uri, cache);
+ cacheTail = cache;
+
+ if (result != QmldirFound)
+ result = callback(qmldirAbsoluteFilePath, url) ? QmldirFound : QmldirRejected;
+
+ // Do not return here. Rather, construct the complete cache for this URI.
+ }
+ }
+
+ // Nothing found? Add an empty cache entry to signal that for further requests.
+ if (result == QmldirNotFound || result == QmldirInterceptedToRemote) {
+ QmldirCache *cache = new QmldirCache;
+ cache->version = version;
+ cache->next = cacheHead;
+ if (result == QmldirInterceptedToRemote) {
+ // The actual value doesn't matter as long as it's not empty.
+ // We only use it to discern QmldirInterceptedToRemote from QmldirNotFound above.
+ cache->qmldirPathUrl = QStringLiteral("intercepted");
+ }
+ qmldirCache.insert(uri, cache);
+
+ if (result == QmldirNotFound) {
+ qCDebug(lcQmlImport)
+ << "locateLocalQmldir:" << qPrintable(uri) << "module's qmldir file not found";
+ }
+ } else {
+ qCDebug(lcQmlImport)
+ << "locateLocalQmldir:" << qPrintable(uri) << "module's qmldir found at"
+ << qmldirAbsoluteFilePath;
+ }
+
+ return result;
+}
+
void qmlClearEnginePlugins();// For internal use by qmlClearRegisteredProperties
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlincubator.cpp b/src/qml/qml/qqmlincubator.cpp
index 7d4ffcec3f..5c18230450 100644
--- a/src/qml/qml/qqmlincubator.cpp
+++ b/src/qml/qml/qqmlincubator.cpp
@@ -1,47 +1,10 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qqmlincubator.h"
#include "qqmlcomponent.h"
#include "qqmlincubator_p.h"
-#include "qqmlexpression_p.h"
#include "qqmlobjectcreator_p.h"
#include <private/qqmlcomponent_p.h>
@@ -140,7 +103,10 @@ QQmlIncubatorPrivate::~QQmlIncubatorPrivate()
void QQmlIncubatorPrivate::clear()
{
- compilationUnit = nullptr;
+ // reset the tagged pointer
+ if (requiredPropertiesFromComponent)
+ requiredPropertiesFromComponent = decltype(requiredPropertiesFromComponent){};
+ compilationUnit.reset();
if (next.isInList()) {
next.remove();
enginePriv->incubatorCount--;
@@ -152,7 +118,7 @@ void QQmlIncubatorPrivate::clear()
if (!rootContext.isNull()) {
if (rootContext->incubator())
rootContext->setIncubator(nullptr);
- rootContext = nullptr;
+ rootContext.setContextData({});
}
if (nextWaitingFor.isInList()) {
@@ -211,9 +177,15 @@ protected:
};
\endcode
-Although the previous example would work, it is not optimal. Real world incubation
-controllers should try and maximize the amount of idle time they consume - rather
-than a static amount like 5 milliseconds - while not disturbing the application.
+Although the example works, it is heavily simplified. Real world incubation controllers
+try and maximize the amount of idle time they consume while not disturbing the
+application. Using a static amount of 5 milliseconds like above may both leave idle
+time on the table in some frames and disturb the application in others.
+
+\l{QQuickWindow}, \l{QQuickView}, and \l{QQuickWidget} all pre-create an incubation
+controller that spaces out incubation over multiple frames using a more intelligent
+algorithm. You rarely have to write your own.
+
*/
/*!
@@ -263,12 +235,13 @@ void QQmlIncubatorPrivate::forceCompletion(QQmlInstantiationInterrupt &i)
{
while (QQmlIncubator::Loading == status) {
while (QQmlIncubator::Loading == status && !waitingFor.isEmpty())
- static_cast<QQmlIncubatorPrivate *>(waitingFor.first())->forceCompletion(i);
+ waitingFor.first()->forceCompletion(i);
if (QQmlIncubator::Loading == status)
incubate(i);
}
}
+
void QQmlIncubatorPrivate::incubate(QQmlInstantiationInterrupt &i)
{
if (!compilationUnit)
@@ -280,6 +253,20 @@ void QQmlIncubatorPrivate::incubate(QQmlInstantiationInterrupt &i)
// get a copy of the engine pointer as it might get reset;
QQmlEnginePrivate *enginePriv = this->enginePriv;
+ // Incubating objects takes quite a bit more stack space than our usual V4 function
+ enum { EstimatedSizeInV4Frames = 2 };
+ QV4::ExecutionEngineCallDepthRecorder<EstimatedSizeInV4Frames> callDepthRecorder(
+ compilationUnit->engine);
+ if (callDepthRecorder.hasOverflow()) {
+ QQmlError error;
+ error.setMessageType(QtCriticalMsg);
+ error.setUrl(compilationUnit->url());
+ error.setDescription(QQmlComponent::tr("Maximum call stack size exceeded."));
+ errors << error;
+ progress = QQmlIncubatorPrivate::Completed;
+ goto finishIncubate;
+ }
+
if (!vmeGuard.isOK()) {
QQmlError error;
error.setMessageType(QtInfoMsg);
@@ -300,11 +287,12 @@ void QQmlIncubatorPrivate::incubate(QQmlInstantiationInterrupt &i)
if (!tresult)
errors = creator->errors;
else {
- RequiredProperties& requiredProperties = creator->requiredProperties();
+ RequiredProperties* requiredProperties = creator->requiredProperties();
for (auto it = initialProperties.cbegin(); it != initialProperties.cend(); ++it) {
auto component = tresult;
auto name = it.key();
- QQmlProperty prop = QQmlComponentPrivate::removePropertyFromRequired(component, name, requiredProperties);
+ QQmlProperty prop = QQmlComponentPrivate::removePropertyFromRequired(
+ component, name, requiredProperties, QQmlEnginePrivate::get(enginePriv));
if (!prop.isValid() || !prop.write(it.value())) {
QQmlError error{};
error.setUrl(compilationUnit->url());
@@ -331,9 +319,9 @@ void QQmlIncubatorPrivate::incubate(QQmlInstantiationInterrupt &i)
ddata->rootObjectInCreation = false;
if (q) {
q->setInitialState(result);
- if (creator && !creator->requiredProperties().empty()) {
- const auto& unsetRequiredProperties = creator->requiredProperties();
- for (const auto& unsetRequiredProperty: unsetRequiredProperties)
+ if (creator && !creator->requiredProperties()->empty()) {
+ const RequiredProperties *unsetRequiredProperties = creator->requiredProperties();
+ for (const auto& unsetRequiredProperty: *unsetRequiredProperties)
errors << QQmlComponentPrivate::unsetRequiredPropertyToQQmlError(unsetRequiredProperty);
}
}
@@ -395,6 +383,37 @@ finishIncubate:
}
/*!
+ \internal
+ This is used to mimic the behavior of incubate when the
+ Component we want to incubate refers to a creatable
+ QQmlType (i.e., it is the result of loadFromModule).
+ */
+void QQmlIncubatorPrivate::incubateCppBasedComponent(QQmlComponent *component, QQmlContext *context)
+{
+ auto compPriv = QQmlComponentPrivate::get(component);
+ Q_ASSERT(compPriv->loadedType.isCreatable());
+ std::unique_ptr<QObject> object(component->beginCreate(context));
+ component->setInitialProperties(object.get(), initialProperties);
+ if (auto props = compPriv->state.requiredProperties()) {
+ requiredPropertiesFromComponent = props;
+ requiredPropertiesFromComponent.setTag(HadTopLevelRequired::Yes);
+ }
+ q->setInitialState(object.get());
+ if (requiredPropertiesFromComponent && !requiredPropertiesFromComponent->isEmpty()) {
+ for (const RequiredPropertyInfo &unsetRequiredProperty :
+ std::as_const(*requiredPropertiesFromComponent)) {
+ errors << QQmlComponentPrivate::unsetRequiredPropertyToQQmlError(unsetRequiredProperty);
+ }
+ } else {
+ compPriv->completeCreate();
+ result = object.release();
+ progress = QQmlIncubatorPrivate::Completed;
+ }
+ changeStatus(calculateStatus());
+
+}
+
+/*!
Incubate objects for \a msecs, or until there are no more objects to incubate.
*/
void QQmlIncubationController::incubateFor(int msecs)
@@ -402,8 +421,8 @@ void QQmlIncubationController::incubateFor(int msecs)
if (!d || !d->incubatorCount)
return;
- QQmlInstantiationInterrupt i(msecs * Q_INT64_C(1000000));
- i.reset();
+ QDeadlineTimer deadline(msecs);
+ QQmlInstantiationInterrupt i(deadline);
do {
static_cast<QQmlIncubatorPrivate*>(d->incubatorList.first())->incubate(i);
} while (d && d->incubatorCount != 0 && !i.shouldInterrupt());
@@ -426,8 +445,7 @@ void QQmlIncubationController::incubateWhile(std::atomic<bool> *flag, int msecs)
if (!d || !d->incubatorCount)
return;
- QQmlInstantiationInterrupt i(flag, msecs * Q_INT64_C(1000000));
- i.reset();
+ QQmlInstantiationInterrupt i(flag, msecs ? QDeadlineTimer(msecs) : QDeadlineTimer::Forever);
do {
static_cast<QQmlIncubatorPrivate*>(d->incubatorList.first())->incubate(i);
} while (d && d->incubatorCount != 0 && !i.shouldInterrupt());
@@ -445,25 +463,37 @@ synchronously which, depending on the complexity of the object, can cause notic
stutters in the application.
The use of QQmlIncubator gives more control over the creation of a QML object,
-including allowing it to be created asynchronously using application idle time. The following
+including allowing it to be created asynchronously using application idle time. The following
example shows a simple use of QQmlIncubator.
\code
+// Initialize the incubator
QQmlIncubator incubator;
component->create(incubator);
+\endcode
-while (!incubator.isReady()) {
- QCoreApplication::processEvents(QEventLoop::AllEvents, 50);
-}
+Let the incubator run for a while (normally by returning control to the event loop),
+then poll it. There are a number of ways to get back to the incubator later. You may
+want to connect to one of the signals sent by \l{QQuickWindow}, or you may want to run
+a \l{QTimer} especially for that. You may also need the object for some specific
+purpose and poll the incubator when that purpose arises.
-QObject *object = incubator.object();
+\code
+// Poll the incubator
+if (incubator.isReady()) {
+ QObject *object = incubator.object();
+ // Use created object
+}
\endcode
-Asynchronous incubators are controlled by a QQmlIncubationController that is
-set on the QQmlEngine, which lets the engine know when the application is idle and
+Asynchronous incubators are controlled by a \l{QQmlIncubationController} that is
+set on the \l{QQmlEngine}, which lets the engine know when the application is idle and
incubating objects should be processed. If an incubation controller is not set on the
-QQmlEngine, QQmlIncubator creates objects synchronously regardless of the
-specified IncubationMode.
+\l{QQmlEngine}, \l{QQmlIncubator} creates objects synchronously regardless of the
+specified IncubationMode. By default, no incubation controller is set. However,
+\l{QQuickView}, \l{QQuickWindow} and \l{QQuickWidget} all set incubation controllers
+on their respective \l{QQmlEngine}s. These incubation controllers space out incubations
+across multiple frames while the view is being rendered.
QQmlIncubator supports three incubation modes:
\list
@@ -683,21 +713,28 @@ QObject *QQmlIncubator::object() const
}
/*!
-Return a list of properties which are required but haven't been set yet.
+Return a pointer to a list of properties which are required but haven't
+been set yet.
This list can be modified, so that subclasses which implement special logic
setInitialProperties can mark properties set there as no longer required.
\sa QQmlIncubator::setInitialProperties
\since 5.15
*/
-RequiredProperties &QQmlIncubatorPrivate::requiredProperties()
+RequiredProperties *QQmlIncubatorPrivate::requiredProperties()
{
- return creator->requiredProperties();
+ if (creator)
+ return creator->requiredProperties();
+ else
+ return requiredPropertiesFromComponent.data();
}
-bool QQmlIncubatorPrivate::hadRequiredProperties() const
+bool QQmlIncubatorPrivate::hadTopLevelRequiredProperties() const
{
- return creator->componentHadRequiredProperties();
+ if (creator)
+ return creator->componentHadTopLevelRequiredProperties();
+ else
+ return requiredPropertiesFromComponent.tag() == HadTopLevelRequired::Yes;
}
/*!
@@ -723,13 +760,23 @@ void QQmlIncubator::statusChanged(Status status)
}
/*!
-Called after the \a object is first created, but before property bindings are
-evaluated and, if applicable, QQmlParserStatus::componentComplete() is
-called. This is equivalent to the point between QQmlComponent::beginCreate()
+Called after the \a object is first created, but before complex property
+bindings are evaluated and, if applicable, QQmlParserStatus::componentComplete()
+is called. This is equivalent to the point between QQmlComponent::beginCreate()
and QQmlComponent::completeCreate(), and can be used to assign initial values
to the object's properties.
The default implementation does nothing.
+
+\note Simple bindings such as numeric literals are evaluated before
+setInitialState() is called. The categorization of bindings into simple and
+complex ones is intentionally unspecified and may change between versions of
+Qt and depending on whether and how you are using \l{qmlcachegen}. You should
+not rely on any particular binding to be evaluated either before or after
+setInitialState() is called. For example, a constant expression like
+\e{MyType.EnumValue} may be recognized as such at compile time or deferred
+to be executed as binding. The same holds for constant expressions like
+\e{-(5)} or \e{"a" + " constant string"}.
*/
void QQmlIncubator::setInitialState(QObject *object)
{
diff --git a/src/qml/qml/qqmlincubator.h b/src/qml/qml/qqmlincubator.h
index 594f60a0d8..c2389fc878 100644
--- a/src/qml/qml/qqmlincubator.h
+++ b/src/qml/qml/qqmlincubator.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLINCUBATOR_H
#define QQMLINCUBATOR_H
@@ -50,7 +14,6 @@ QT_BEGIN_NAMESPACE
class QQmlEngine;
class QQmlPropertyData;
class QVariant;
-using QVariantMap = QMap<QString, QVariant>;
class QQmlIncubatorPrivate;
class Q_QML_EXPORT QQmlIncubator
diff --git a/src/qml/qml/qqmlincubator_p.h b/src/qml/qml/qqmlincubator_p.h
index b178c6aa29..f35679a8a1 100644
--- a/src/qml/qml/qqmlincubator_p.h
+++ b/src/qml/qml/qqmlincubator_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLINCUBATOR_P_H
#define QQMLINCUBATOR_P_H
@@ -48,6 +12,8 @@
#include <private/qqmlengine_p.h>
#include <private/qqmlguardedcontextdata_p.h>
+#include <QtCore/qpointer.h>
+
//
// W A R N I N G
// -------------
@@ -64,7 +30,7 @@ QT_BEGIN_NAMESPACE
class RequiredProperties;
class QQmlIncubator;
-class Q_QML_PRIVATE_EXPORT QQmlIncubatorPrivate : public QQmlEnginePrivate::Incubator
+class Q_QML_EXPORT QQmlIncubatorPrivate : public QQmlEnginePrivate::Incubator, public QSharedData
{
public:
QQmlIncubatorPrivate(QQmlIncubator *q, QQmlIncubator::IncubationMode m);
@@ -72,6 +38,7 @@ public:
inline static QQmlIncubatorPrivate *get(QQmlIncubator *incubator) { return incubator->d; }
+ int subComponentToCreate;
QQmlIncubator *q;
QQmlIncubator::Status calculateStatus() const;
@@ -80,23 +47,31 @@ public:
QQmlIncubator::IncubationMode mode;
bool isAsynchronous;
+ enum Progress : char { Execute, Completing, Completed };
+ Progress progress;
QList<QQmlError> errors;
- enum Progress { Execute, Completing, Completed };
- Progress progress;
QPointer<QObject> result;
+ enum HadTopLevelRequired : bool {No = 0, Yes = 1};
+ /* TODO: unify with Creator pointer once QTBUG-108760 is implemented
+ though we don't acutally own the properties here; if we ever end up
+ with a use case for async incubation of C++ types, we however could
+ not rely on the component to still exist during incubation, and
+ would need to store a copy of the required properties instead
+ */
+ QTaggedPointer<RequiredProperties, HadTopLevelRequired> requiredPropertiesFromComponent;
QQmlGuardedContextData rootContext;
QQmlEnginePrivate *enginePriv;
QQmlRefPointer<QV4::ExecutableCompilationUnit> compilationUnit;
QScopedPointer<QQmlObjectCreator> creator;
- int subComponentToCreate;
QQmlVMEGuard vmeGuard;
QExplicitlySharedDataPointer<QQmlIncubatorPrivate> waitingOnMe;
typedef QQmlEnginePrivate::Incubator QIPBase;
- QIntrusiveList<QIPBase, &QIPBase::nextWaitingFor> waitingFor;
+ QIntrusiveListNode nextWaitingFor;
+ QIntrusiveList<QQmlIncubatorPrivate, &QQmlIncubatorPrivate::nextWaitingFor> waitingFor;
QRecursionNode recursion;
QVariantMap initialProperties;
@@ -105,8 +80,9 @@ public:
void forceCompletion(QQmlInstantiationInterrupt &i);
void incubate(QQmlInstantiationInterrupt &i);
- RequiredProperties &requiredProperties();
- bool hadRequiredProperties() const;
+ void incubateCppBasedComponent(QQmlComponent *component, QQmlContext *context);
+ RequiredProperties *requiredProperties();
+ bool hadTopLevelRequiredProperties() const;
};
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlinfo.cpp b/src/qml/qml/qqmlinfo.cpp
index ab55393406..159a519bdc 100644
--- a/src/qml/qml/qqmlinfo.cpp
+++ b/src/qml/qml/qqmlinfo.cpp
@@ -1,47 +1,9 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qqmlinfo.h"
#include "qqmldata_p.h"
-#include "qqmlcontext.h"
-#include "qqmlcontext_p.h"
#include "qqmlmetatype_p.h"
#include "qqmlengine_p.h"
#include "qqmlsourcecoordinate_p.h"
@@ -51,8 +13,21 @@
QT_BEGIN_NAMESPACE
/*!
+ \class QQmlInfo
+ \inmodule QtQml
+ \brief The QQmlInfo class allows logging of QML-related messages.
+
+ QQmlInfo is an opaque handle for QML-related diagnostic messages. You can
+ use the \c{<<} operator to add content to the message. When the QQmlInfo
+ object is destroyed, it prints the resulting message along with information
+ on the context.
+
+ \sa qmlDebug, qmlInfo, qmlWarning
+*/
+
+/*!
\fn QQmlInfo qmlDebug(const QObject *object)
- \relates QQmlEngine
+ \relates QQmlInfo
\since 5.9
Prints debug messages that include the file and line number for the
@@ -86,7 +61,7 @@ QT_BEGIN_NAMESPACE
/*!
\fn QQmlInfo qmlInfo(const QObject *object)
- \relates QQmlEngine
+ \relates QQmlInfo
Prints informational messages that include the file and line number for the
specified QML \a object.
@@ -114,7 +89,7 @@ QT_BEGIN_NAMESPACE
/*!
\fn QQmlInfo qmlWarning(const QObject *object)
- \relates QQmlEngine
+ \relates QQmlInfo
\since 5.9
Prints warning messages that include the file and line number for the
diff --git a/src/qml/qml/qqmlinfo.h b/src/qml/qml/qqmlinfo.h
index fe865658d4..1fc0d4a2ae 100644
--- a/src/qml/qml/qqmlinfo.h
+++ b/src/qml/qml/qqmlinfo.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLINFO_H
#define QQMLINFO_H
diff --git a/src/qml/qml/qqmlirloader.cpp b/src/qml/qml/qqmlirloader.cpp
index ee75a2b4f7..b29ce185ef 100644
--- a/src/qml/qml/qqmlirloader.cpp
+++ b/src/qml/qml/qqmlirloader.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the tools applications 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$
-**
-****************************************************************************/
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qqmlirloader_p.h"
#include <private/qqmlirbuilder_p.h>
@@ -58,18 +22,71 @@ void QQmlIRLoader::load()
for (quint32 i = 0; i < qmlUnit->nImports; ++i)
output->imports << qmlUnit->importAt(i);
- const auto createPragma = [&](QmlIR::Pragma::PragmaType type) {
- QmlIR::Pragma *p = New<QmlIR::Pragma>();
+ using QmlIR::Pragma;
+ const auto createPragma = [&](Pragma::PragmaType type) {
+ Pragma *p = New<Pragma>();
p->location = QV4::CompiledData::Location();
p->type = type;
output->pragmas << p;
+ return p;
+ };
+
+ const auto createListPragma = [&](
+ Pragma::PragmaType type,
+ Pragma::ListPropertyAssignBehaviorValue value) {
+ createPragma(type)->listPropertyAssignBehavior = value;
+ };
+
+ const auto createComponentPragma = [&](
+ Pragma::PragmaType type,
+ Pragma::ComponentBehaviorValue value) {
+ createPragma(type)->componentBehavior = value;
+ };
+
+ const auto createFunctionSignaturePragma = [&](
+ Pragma::PragmaType type,
+ Pragma::FunctionSignatureBehaviorValue value) {
+ createPragma(type)->functionSignatureBehavior = value;
+ };
+
+ const auto createNativeMethodPragma = [&](
+ Pragma::PragmaType type,
+ Pragma::NativeMethodBehaviorValue value) {
+ createPragma(type)->nativeMethodBehavior = value;
+ };
+
+ const auto createValueTypePragma = [&](
+ Pragma::PragmaType type,
+ Pragma::ValueTypeBehaviorValues value) {
+ createPragma(type)->valueTypeBehavior = value;
};
if (unit->flags & QV4::CompiledData::Unit::IsSingleton)
- createPragma(QmlIR::Pragma::PragmaSingleton);
+ createPragma(Pragma::Singleton);
if (unit->flags & QV4::CompiledData::Unit::IsStrict)
- createPragma(QmlIR::Pragma::PragmaStrict);
+ createPragma(Pragma::Strict);
+
+ if (unit->flags & QV4::CompiledData::Unit::ListPropertyAssignReplace)
+ createListPragma(Pragma::ListPropertyAssignBehavior, Pragma::Replace);
+ else if (unit->flags & QV4::CompiledData::Unit::ListPropertyAssignReplaceIfNotDefault)
+ createListPragma(Pragma::ListPropertyAssignBehavior, Pragma::ReplaceIfNotDefault);
+
+ if (unit->flags & QV4::CompiledData::Unit::ComponentsBound)
+ createComponentPragma(Pragma::ComponentBehavior, Pragma::Bound);
+
+ if (unit->flags & QV4::CompiledData::Unit::FunctionSignaturesIgnored)
+ createFunctionSignaturePragma(Pragma::FunctionSignatureBehavior, Pragma::Ignored);
+
+ if (unit->flags & QV4::CompiledData::Unit::NativeMethodsAcceptThisObject)
+ createNativeMethodPragma(Pragma::NativeMethodBehavior, Pragma::AcceptThisObject);
+ Pragma::ValueTypeBehaviorValues valueTypeBehavior = {};
+ if (unit->flags & QV4::CompiledData::Unit::ValueTypesCopied)
+ valueTypeBehavior |= Pragma::Copy;
+ if (unit->flags & QV4::CompiledData::Unit::ValueTypesAddressable)
+ valueTypeBehavior |= Pragma::Addressable;
+ if (valueTypeBehavior)
+ createValueTypePragma(Pragma::ValueTypeBehavior, valueTypeBehavior);
for (uint i = 0; i < qmlUnit->nObjects; ++i) {
const QV4::CompiledData::Object *serializedObject = qmlUnit->objectAt(i);
@@ -101,10 +118,9 @@ QmlIR::Object *QQmlIRLoader::loadObject(const QV4::CompiledData::Object *seriali
serializedObject->location);
object->indexOfDefaultPropertyOrAlias = serializedObject->indexOfDefaultPropertyOrAlias;
- object->defaultPropertyIsAlias = serializedObject->defaultPropertyIsAlias;
- object->isInlineComponent = serializedObject->flags & QV4::CompiledData::Object::IsInlineComponentRoot;
- object->flags = serializedObject->flags;
- object->id = serializedObject->id;
+ object->defaultPropertyIsAlias = serializedObject->hasAliasAsDefaultProperty();
+ object->flags = serializedObject->flags();
+ object->id = serializedObject->objectId();
object->locationOfIdProperty = serializedObject->locationOfIdProperty;
QVector<int> functionIndices;
@@ -114,9 +130,9 @@ QmlIR::Object *QQmlIRLoader::loadObject(const QV4::CompiledData::Object *seriali
QmlIR::Binding *b = pool->New<QmlIR::Binding>();
*static_cast<QV4::CompiledData::Binding*>(b) = serializedObject->bindingTable()[i];
object->bindings->append(b);
- if (b->type == QV4::CompiledData::Binding::Type_Script) {
+ if (b->type() == QV4::CompiledData::Binding::Type_Script) {
functionIndices.append(b->value.compiledScriptIndex);
- b->value.compiledScriptIndex = functionIndices.count() - 1;
+ b->value.compiledScriptIndex = functionIndices.size() - 1;
QmlIR::CompiledFunctionOrExpression *foe = pool->New<QmlIR::CompiledFunctionOrExpression>();
foe->nameIndex = 0;
@@ -124,9 +140,9 @@ QmlIR::Object *QQmlIRLoader::loadObject(const QV4::CompiledData::Object *seriali
QQmlJS::AST::ExpressionNode *expr;
if (b->stringIndex != quint32(0)) {
- const int start = output->code.length();
+ const int start = output->code.size();
const QString script = output->stringAt(b->stringIndex);
- const int length = script.length();
+ const int length = script.size();
output->code.append(script);
expr = new (pool) FakeExpression(start, length);
} else
@@ -136,7 +152,7 @@ QmlIR::Object *QQmlIRLoader::loadObject(const QV4::CompiledData::Object *seriali
}
}
- Q_ASSERT(object->functionsAndExpressions->count == functionIndices.count());
+ Q_ASSERT(object->functionsAndExpressions->count == functionIndices.size());
for (uint i = 0; i < serializedObject->nSignals; ++i) {
const QV4::CompiledData::Signal *serializedSignal = serializedObject->signalAt(i);
@@ -192,7 +208,7 @@ QmlIR::Object *QQmlIRLoader::loadObject(const QV4::CompiledData::Object *seriali
const QV4::CompiledData::Function *compiledFunction = unit->functionAt(*functionIdx);
functionIndices.append(*functionIdx);
- f->index = functionIndices.count() - 1;
+ f->index = functionIndices.size() - 1;
f->location = compiledFunction->location;
f->nameIndex = compiledFunction->nameIndex;
f->returnType = compiledFunction->returnType;
diff --git a/src/qml/qml/qqmlirloader_p.h b/src/qml/qml/qqmlirloader_p.h
index 4812946ef0..8a14d6833e 100644
--- a/src/qml/qml/qqmlirloader_p.h
+++ b/src/qml/qml/qqmlirloader_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the tools applications 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$
-**
-****************************************************************************/
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLIRLOADER_P_H
#define QQMLIRLOADER_P_H
@@ -62,7 +26,7 @@ struct Document;
struct Object;
}
-struct Q_QML_PRIVATE_EXPORT QQmlIRLoader {
+struct Q_QML_EXPORT QQmlIRLoader {
QQmlIRLoader(const QV4::CompiledData::Unit *unit, QmlIR::Document *output);
void load();
diff --git a/src/qml/qml/qqmljavascriptexpression.cpp b/src/qml/qml/qqmljavascriptexpression.cpp
index 1a4d452bfd..d7cf38984b 100644
--- a/src/qml/qml/qqmljavascriptexpression.cpp
+++ b/src/qml/qml/qqmljavascriptexpression.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qqmljavascriptexpression_p.h"
#include "qqmljavascriptexpression_p.h"
@@ -129,8 +93,8 @@ QString QQmlJavaScriptExpression::expressionIdentifier() const
{
if (auto f = function()) {
QString url = f->sourceFile();
- uint lineNumber = f->compiledFunction->location.line;
- uint columnNumber = f->compiledFunction->location.column;
+ uint lineNumber = f->compiledFunction->location.line();
+ uint columnNumber = f->compiledFunction->location.column();
return url + QString::asprintf(":%u:%u", lineNumber, columnNumber);
}
@@ -172,98 +136,142 @@ void QQmlJavaScriptExpression::setContext(const QQmlRefPointer<QQmlContextData>
context->addExpression(this);
}
-QV4::Function *QQmlJavaScriptExpression::function() const
-{
- return m_v4Function;
-}
-
void QQmlJavaScriptExpression::refresh()
{
}
QV4::ReturnedValue QQmlJavaScriptExpression::evaluate(bool *isUndefined)
{
- QV4::ExecutionEngine *v4 = m_context->engine()->handle();
- QV4::Scope scope(v4);
- QV4::JSCallData jsCall(scope);
+ QQmlEngine *qmlengine = engine();
+ if (!qmlengine) {
+ if (isUndefined)
+ *isUndefined = true;
+ return QV4::Encode::undefined();
+ }
- return evaluate(jsCall.callData(), isUndefined);
+ QV4::Scope scope(qmlengine->handle());
+ QV4::JSCallArguments jsCall(scope);
+
+ return evaluate(jsCall.callData(scope), isUndefined);
}
-QV4::ReturnedValue QQmlJavaScriptExpression::evaluate(QV4::CallData *callData, bool *isUndefined)
+class QQmlJavaScriptExpressionCapture
{
- Q_ASSERT(m_context && m_context->engine());
+ Q_DISABLE_COPY_MOVE(QQmlJavaScriptExpressionCapture)
+public:
+ QQmlJavaScriptExpressionCapture(QQmlJavaScriptExpression *expression, QQmlEngine *engine)
+ : watcher(expression)
+ , capture(engine, expression, &watcher)
+ , ep(QQmlEnginePrivate::get(engine))
+ {
+ Q_ASSERT(expression->notifyOnValueChanged() || expression->activeGuards.isEmpty());
+
+ lastPropertyCapture = ep->propertyCapture;
+ ep->propertyCapture = expression->notifyOnValueChanged() ? &capture : nullptr;
+
+ if (expression->notifyOnValueChanged())
+ capture.guards.copyAndClearPrepend(expression->activeGuards);
+ }
+
+ ~QQmlJavaScriptExpressionCapture()
+ {
+ if (capture.errorString) {
+ for (int ii = 0; ii < capture.errorString->size(); ++ii)
+ qWarning("%s", qPrintable(capture.errorString->at(ii)));
+ delete capture.errorString;
+ capture.errorString = nullptr;
+ }
+
+ while (QQmlJavaScriptExpressionGuard *g = capture.guards.takeFirst())
+ g->Delete();
+
+ ep->propertyCapture = lastPropertyCapture;
+ }
+
+ bool catchException(const QV4::Scope &scope) const
+ {
+ if (scope.hasException()) {
+ if (watcher.wasDeleted())
+ scope.engine->catchException(); // ignore exception
+ else
+ capture.expression->delayedError()->catchJavaScriptException(scope.engine);
+ return true;
+ }
+
+ if (!watcher.wasDeleted() && capture.expression->hasDelayedError())
+ capture.expression->delayedError()->clearError();
+ return false;
+ }
+private:
+ QQmlJavaScriptExpression::DeleteWatcher watcher;
+ QQmlPropertyCapture capture;
+ QQmlEnginePrivate *ep;
+ QQmlPropertyCapture *lastPropertyCapture;
+};
+
+QV4::ReturnedValue QQmlJavaScriptExpression::evaluate(QV4::CallData *callData, bool *isUndefined)
+{
+ QQmlEngine *qmlEngine = engine();
QV4::Function *v4Function = function();
- if (!v4Function) {
+ if (!v4Function || !qmlEngine) {
if (isUndefined)
*isUndefined = true;
return QV4::Encode::undefined();
}
- QQmlEnginePrivate *ep = QQmlEnginePrivate::get(m_context->engine());
-
// All code that follows must check with watcher before it accesses data members
// incase we have been deleted.
- DeleteWatcher watcher(this);
-
- Q_ASSERT(notifyOnValueChanged() || activeGuards.isEmpty());
- QQmlPropertyCapture capture(m_context->engine(), this, &watcher);
+ QQmlJavaScriptExpressionCapture capture(this, qmlEngine);
- QQmlPropertyCapture *lastPropertyCapture = ep->propertyCapture;
- ep->propertyCapture = notifyOnValueChanged() ? &capture : nullptr;
+ QV4::Scope scope(qmlEngine->handle());
-
- if (notifyOnValueChanged())
- capture.guards.copyAndClearPrepend(activeGuards);
-
- QV4::ExecutionEngine *v4 = m_context->engine()->handle();
- callData->thisObject = v4->globalObject;
- if (scopeObject()) {
- QV4::ReturnedValue scope = QV4::QObjectWrapper::wrap(v4, scopeObject());
- if (QV4::Value::fromReturnedValue(scope).isObject())
- callData->thisObject = scope;
+ if (QObject *thisObject = scopeObject()) {
+ callData->thisObject = QV4::QObjectWrapper::wrap(scope.engine, thisObject);
+ if (callData->thisObject.isNullOrUndefined())
+ callData->thisObject = scope.engine->globalObject;
+ } else {
+ callData->thisObject = scope.engine->globalObject;
}
Q_ASSERT(m_qmlScope.valueRef());
- QV4::ReturnedValue res = v4Function->call(
+ QV4::ScopedValue result(scope, v4Function->call(
&(callData->thisObject.asValue<QV4::Value>()),
callData->argValues<QV4::Value>(), callData->argc(),
- static_cast<QV4::ExecutionContext *>(m_qmlScope.valueRef()));
- QV4::Scope scope(v4);
- QV4::ScopedValue result(scope, res);
+ static_cast<QV4::ExecutionContext *>(m_qmlScope.valueRef())));
- if (scope.hasException()) {
- if (watcher.wasDeleted())
- scope.engine->catchException(); // ignore exception
- else
- delayedError()->catchJavaScriptException(scope.engine);
+ if (capture.catchException(scope)) {
if (isUndefined)
*isUndefined = true;
- } else {
- if (isUndefined)
- *isUndefined = result->isUndefined();
-
- if (!watcher.wasDeleted() && hasDelayedError())
- delayedError()->clearError();
+ } else if (isUndefined) {
+ *isUndefined = result->isUndefined();
}
- if (capture.errorString) {
- for (int ii = 0; ii < capture.errorString->count(); ++ii)
- qWarning("%s", qPrintable(capture.errorString->at(ii)));
- delete capture.errorString;
- capture.errorString = nullptr;
- }
+ return result->asReturnedValue();
+}
- while (QQmlJavaScriptExpressionGuard *g = capture.guards.takeFirst())
- g->Delete();
+bool QQmlJavaScriptExpression::evaluate(void **a, const QMetaType *types, int argc)
+{
+ // All code that follows must check with watcher before it accesses data members
+ // incase we have been deleted.
+ QQmlEngine *qmlEngine = engine();
- if (!watcher.wasDeleted())
- setTranslationsCaptured(capture.translationCaptured);
+ // If there is no engine, we have no way to evaluate anything.
+ // This can happen on destruction.
+ if (!qmlEngine)
+ return false;
- ep->propertyCapture = lastPropertyCapture;
+ QQmlJavaScriptExpressionCapture capture(this, qmlEngine);
- return result->asReturnedValue();
+ QV4::Scope scope(qmlEngine->handle());
+
+ Q_ASSERT(m_qmlScope.valueRef());
+ Q_ASSERT(function());
+ const bool resultIsDefined = function()->call(
+ scopeObject(), a, types, argc,
+ static_cast<QV4::ExecutionContext *>(m_qmlScope.valueRef()));
+
+ return !capture.catchException(scope) && resultIsDefined;
}
void QQmlPropertyCapture::captureProperty(QQmlNotifier *n)
@@ -305,7 +313,7 @@ void QQmlPropertyCapture::captureProperty(QObject *o, int c, int n, bool doNotif
if (c >= 0) {
const QQmlData *ddata = QQmlData::get(o, /*create=*/false);
const QMetaObject *metaObjectForBindable = nullptr;
- if (auto const propCache = ddata ? ddata->propertyCache : nullptr; propCache) {
+ if (auto const propCache = (ddata ? ddata->propertyCache.data() : nullptr)) {
Q_ASSERT(propCache->property(c));
if (propCache->property(c)->isBindable())
metaObjectForBindable = propCache->metaObject();
@@ -315,24 +323,83 @@ void QQmlPropertyCapture::captureProperty(QObject *o, int c, int n, bool doNotif
metaObjectForBindable = m;
}
if (metaObjectForBindable) {
- // if the property is a QPropery, and we're binding to a QProperty
- // the automatic capturing process already takes care of everything
- if (typeid(QQmlPropertyBindingJS) == typeid(*expression))
- return;
- for (auto trigger = expression->qpropertyChangeTriggers; trigger;
- trigger = trigger->next) {
- if (trigger->target == o && trigger->propertyIndex == c)
- return; // already installed
- }
- auto trigger = expression->allocatePropertyChangeTrigger(o, c);
- QUntypedBindable bindable;
- void *argv[] = { &bindable };
- metaObjectForBindable->metacall(o, QMetaObject::BindableProperty, c, argv);
- bindable.observe(trigger);
+ captureBindableProperty(o, metaObjectForBindable, c);
+ return;
+ }
+ }
+
+ captureNonBindableProperty(o, n, c, doNotify);
+}
+
+void QQmlPropertyCapture::captureProperty(
+ QObject *o, const QQmlPropertyCache *propertyCache, const QQmlPropertyData *propertyData,
+ bool doNotify)
+{
+ if (watcher->wasDeleted())
+ return;
+
+ Q_ASSERT(expression);
+
+ if (propertyData->isBindable()) {
+ if (const QMetaObject *metaObjectForBindable = propertyCache->metaObject()) {
+ captureBindableProperty(o, metaObjectForBindable, propertyData->coreIndex());
return;
}
}
+ captureNonBindableProperty(o, propertyData->notifyIndex(), propertyData->coreIndex(), doNotify);
+}
+
+bool QQmlJavaScriptExpression::needsPropertyChangeTrigger(QObject *target, int propertyIndex)
+{
+ TriggerList **prev = &qpropertyChangeTriggers;
+ TriggerList *current = qpropertyChangeTriggers;
+ while (current) {
+ if (!current->target) {
+ *prev = current->next;
+ QRecyclePool<TriggerList>::Delete(current);
+ current = *prev;
+ } else if (current->target == target && current->propertyIndex == propertyIndex) {
+ return false; // already installed
+ } else {
+ prev = &current->next;
+ current = current->next;
+ }
+ }
+
+ return true;
+}
+
+void QQmlPropertyCapture::captureTranslation()
+{
+ // use a unique invalid index to avoid needlessly querying the metaobject for
+ // the correct index of of the translationLanguage property
+ int const invalidIndex = -2;
+ if (expression->needsPropertyChangeTrigger(engine, invalidIndex)) {
+ auto trigger = expression->allocatePropertyChangeTrigger(engine, invalidIndex);
+ trigger->setSource(QQmlEnginePrivate::get(engine)->translationLanguage);
+ }
+}
+
+void QQmlPropertyCapture::captureBindableProperty(
+ QObject *o, const QMetaObject *metaObjectForBindable, int c)
+{
+ // if the property is a QPropery, and we're binding to a QProperty
+ // the automatic capturing process already takes care of everything
+ if (!expression->mustCaptureBindableProperty())
+ return;
+
+ if (expression->needsPropertyChangeTrigger(o, c)) {
+ auto trigger = expression->allocatePropertyChangeTrigger(o, c);
+ QUntypedBindable bindable;
+ void *argv[] = { &bindable };
+ metaObjectForBindable->metacall(o, QMetaObject::BindableProperty, c, argv);
+ bindable.observe(trigger);
+ }
+}
+
+void QQmlPropertyCapture::captureNonBindableProperty(QObject *o, int n, int c, bool doNotify)
+{
if (n == -1) {
if (!errorString) {
errorString = new QStringList;
@@ -447,7 +514,7 @@ void QQmlJavaScriptExpression::setupFunction(QV4::ExecutionContext *qmlContext,
return;
m_qmlScope.set(qmlContext->engine(), *qmlContext);
m_v4Function = f;
- setCompilationUnit(m_v4Function->executableCompilationUnit());
+ m_compilationUnit.reset(m_v4Function->executableCompilationUnit());
}
void QQmlJavaScriptExpression::setCompilationUnit(const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit)
@@ -460,6 +527,16 @@ void QPropertyChangeTrigger::trigger(QPropertyObserver *observer, QUntypedProper
This->m_expression->expressionChanged();
}
+QMetaProperty QPropertyChangeTrigger::property() const
+{
+ if (!target)
+ return {};
+ auto const mo = target->metaObject();
+ if (!mo)
+ return {};
+ return mo->property(propertyIndex);
+}
+
QPropertyChangeTrigger *QQmlJavaScriptExpression::allocatePropertyChangeTrigger(QObject *target, int propertyIndex)
{
auto trigger = QQmlEnginePrivate::get(engine())->qPropertyTriggerPool.New( this );
diff --git a/src/qml/qml/qqmljavascriptexpression_p.h b/src/qml/qml/qqmljavascriptexpression_p.h
index 499d4d430f..80e2033627 100644
--- a/src/qml/qml/qqmljavascriptexpression_p.h
+++ b/src/qml/qml/qqmljavascriptexpression_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLJAVASCRIPTEXPRESSION_P_H
#define QQMLJAVASCRIPTEXPRESSION_P_H
@@ -55,6 +19,7 @@
#include <QtCore/qtaggedpointer.h>
#include <QtQml/qqmlerror.h>
#include <private/qqmlengine_p.h>
+#include <QtQml/private/qbipointer_p.h>
QT_BEGIN_NAMESPACE
@@ -97,8 +62,9 @@ private:
QQmlDelayedError **prevError;
};
-class Q_QML_PRIVATE_EXPORT QQmlJavaScriptExpression
+class Q_QML_EXPORT QQmlJavaScriptExpression
{
+ Q_DISABLE_COPY_MOVE(QQmlJavaScriptExpression)
public:
QQmlJavaScriptExpression();
virtual ~QQmlJavaScriptExpression();
@@ -108,6 +74,7 @@ public:
QV4::ReturnedValue evaluate(bool *isUndefined);
QV4::ReturnedValue evaluate(QV4::CallData *callData, bool *isUndefined);
+ bool evaluate(void **a, const QMetaType *types, int argc);
inline bool notifyOnValueChanged() const;
@@ -135,7 +102,7 @@ public:
*listHead = this;
}
- QV4::Function *function() const;
+ QV4::Function *function() const { return m_v4Function; }
virtual void refresh();
@@ -157,6 +124,7 @@ public:
void clearError();
void clearActiveGuards();
QQmlDelayedError *delayedError();
+ virtual bool mustCaptureBindableProperty() const {return true;}
static QV4::ReturnedValue evalFunction(
const QQmlRefPointer<QQmlContextData> &ctxt, QObject *scope, const QString &code,
@@ -164,6 +132,8 @@ public:
QQmlEngine *engine() const { return m_context ? m_context->engine() : nullptr; }
bool hasUnresolvedNames() const { return m_context && m_context->hasUnresolvedNames(); }
+
+ bool needsPropertyChangeTrigger(QObject *target, int propertyIndex);
QPropertyChangeTrigger *allocatePropertyChangeTrigger(QObject *target, int propertyIndex);
protected:
@@ -185,28 +155,20 @@ protected:
QForwardFieldList<QQmlJavaScriptExpressionGuard, &QQmlJavaScriptExpressionGuard::next, GuardTag> activeGuards;
- void setTranslationsCaptured(bool captured) {
- Tag newTag = captured ? TranslationsCaptured : NoTag;
- if (m_error.tag() & InEvaluationLoop)
- newTag = Tag(newTag | InEvaluationLoop);
- m_error.setTag(newTag);
- }
- bool translationsCaptured() const { return m_error.tag() & TranslationsCaptured; }
-
enum Tag {
NoTag,
- TranslationsCaptured,
InEvaluationLoop
};
- // m_error:flag1 translationsCapturedDuringEvaluation
- QTaggedPointer<QQmlDelayedError> m_error;
+ QTaggedPointer<QQmlDelayedError, Tag> m_error;
private:
friend class QQmlContextData;
friend class QQmlPropertyCapture;
friend void QQmlJavaScriptExpressionGuard_callback(QQmlNotifierEndpoint *, void **);
- friend class QQmlTranslationBinding;
+ friend class QQmlTranslationBindingFromBinding;
+ friend class QQmlTranslationBindingFromTranslationInfo;
+ friend class QQmlJavaScriptExpressionCapture;
// Not refcounted as the context will clear the expressions when destructed.
QQmlContextData *m_context;
@@ -216,13 +178,14 @@ private:
QV4::PersistentValue m_qmlScope;
QQmlRefPointer<QV4::ExecutableCompilationUnit> m_compilationUnit;
+
QV4::Function *m_v4Function;
protected:
TriggerList *qpropertyChangeTriggers = nullptr;
};
-class Q_QML_PRIVATE_EXPORT QQmlPropertyCapture
+class Q_QML_EXPORT QQmlPropertyCapture
{
public:
QQmlPropertyCapture(QQmlEngine *engine, QQmlJavaScriptExpression *e, QQmlJavaScriptExpression::DeleteWatcher *w)
@@ -235,14 +198,18 @@ public:
void captureProperty(QQmlNotifier *);
void captureProperty(QObject *, int, int, bool doNotify = true);
- void captureTranslation() { translationCaptured = true; }
+ void captureProperty(QObject *, const QQmlPropertyCache *, const QQmlPropertyData *, bool doNotify = true);
+ void captureTranslation();
QQmlEngine *engine;
QQmlJavaScriptExpression *expression;
QQmlJavaScriptExpression::DeleteWatcher *watcher;
QForwardFieldList<QQmlJavaScriptExpressionGuard, &QQmlJavaScriptExpressionGuard::next> guards;
QStringList *errorString;
- bool translationCaptured = false;
+
+private:
+ void captureBindableProperty(QObject *o, const QMetaObject *metaObjectForBindable, int c);
+ void captureNonBindableProperty(QObject *o, int n, int c, bool doNotify);
};
QQmlJavaScriptExpression::DeleteWatcher::DeleteWatcher(QQmlJavaScriptExpression *e)
diff --git a/src/qml/qml/qqmllist.cpp b/src/qml/qml/qqmllist.cpp
index b266157d28..a166041070 100644
--- a/src/qml/qml/qqmllist.cpp
+++ b/src/qml/qml/qqmllist.cpp
@@ -1,68 +1,36 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qqmllist.h"
#include "qqmllist_p.h"
-#include "qqmlengine_p.h"
-#include "qqmlproperty_p.h"
+#include <QtQml/private/qqmlproperty_p.h>
QT_BEGIN_NAMESPACE
+static bool isObjectCompatible(QObject *object, QQmlListReferencePrivate *d)
+{
+ if (object) {
+ const QQmlMetaObject elementType = d->elementType();
+ if (elementType.isNull() || !QQmlMetaObject::canConvert(object, elementType))
+ return false;
+ }
+ return true;
+}
+
QQmlListReferencePrivate::QQmlListReferencePrivate()
-: propertyType(-1), refCount(1)
+: refCount(1)
{
}
-QQmlListReference QQmlListReferencePrivate::init(const QQmlListProperty<QObject> &prop, int propType, QQmlEngine *engine)
+QQmlListReference QQmlListReferencePrivate::init(
+ const QQmlListProperty<QObject> &prop, QMetaType propType)
{
QQmlListReference rv;
if (!prop.object) return rv;
- QQmlEnginePrivate *p = engine?QQmlEnginePrivate::get(engine):nullptr;
-
- int listType = QQmlMetaType::listType(propType);
- if (listType == -1) return rv;
-
rv.d = new QQmlListReferencePrivate;
rv.d->object = prop.object;
- rv.d->elementType = QQmlPropertyPrivate::rawMetaObjectForType(p, listType);
rv.d->property = prop;
rv.d->propertyType = propType;
@@ -119,8 +87,10 @@ QQmlListReference::QQmlListReference()
{
}
+#if QT_DEPRECATED_SINCE(6, 4)
/*!
\since 6.1
+\obsolete [6.4] Use the constructors without QQmlEngine argument instead.
Constructs a QQmlListReference from a QVariant \a variant containing a QQmlListProperty. If
\a variant does not contain a list property, an invalid QQmlListReference is created. If the object
@@ -128,26 +98,46 @@ owning the list property is destroyed after the reference is constructed, it wil
become invalid. That is, it is safe to hold QQmlListReference instances even after the object is
deleted.
-The \a engine is required to look up the element type, which may be a dynamically created QML type.
-If it's omitted, only pre-registered types are available.
+The \a engine is unused.
*/
-QQmlListReference::QQmlListReference(const QVariant &variant, QQmlEngine *engine)
+QQmlListReference::QQmlListReference(const QVariant &variant, [[maybe_unused]] QQmlEngine *engine)
+ : QQmlListReference(variant)
+{}
+
+/*!
+\obsolete [6.4] Use the constructors without QQmlEngine argument instead.
+
+Constructs a QQmlListReference for \a object's \a property. If \a property is not a list
+property, an invalid QQmlListReference is created. If \a object is destroyed after
+the reference is constructed, it will automatically become invalid. That is, it is safe to hold
+QQmlListReference instances even after \a object is deleted.
+
+The \a engine is unused.
+*/
+QQmlListReference::QQmlListReference(QObject *object, const char *property,
+ [[maybe_unused]] QQmlEngine *engine)
+ : QQmlListReference(object, property)
+{}
+#endif
+
+/*!
+\since 6.1
+
+Constructs a QQmlListReference from a QVariant \a variant containing a QQmlListProperty. If
+\a variant does not contain a list property, an invalid QQmlListReference is created. If the object
+owning the list property is destroyed after the reference is constructed, it will automatically
+become invalid. That is, it is safe to hold QQmlListReference instances even after the object is
+deleted.
+*/
+QQmlListReference::QQmlListReference(const QVariant &variant)
: d(nullptr)
{
const QMetaType t = variant.metaType();
if (!(t.flags() & QMetaType::IsQmlList))
return;
- QQmlEnginePrivate *p = engine ? QQmlEnginePrivate::get(engine) : nullptr;
- const int listType = QQmlMetaType::listType(t.id());
- if (listType == -1)
- return;
-
d = new QQmlListReferencePrivate;
- d->propertyType = t.id();
- d->elementType = p
- ? p->rawMetaObjectForType(listType)
- : QQmlMetaType::qmlType(listType).baseMetaObject();
+ d->propertyType = t;
d->property.~QQmlListProperty();
t.construct(&d->property, variant.constData());
@@ -160,30 +150,21 @@ Constructs a QQmlListReference for \a object's \a property. If \a property is n
property, an invalid QQmlListReference is created. If \a object is destroyed after
the reference is constructed, it will automatically become invalid. That is, it is safe to hold
QQmlListReference instances even after \a object is deleted.
-
-Passing \a engine is required to access some QML created list properties. If in doubt, and an engine
-is available, pass it.
*/
-QQmlListReference::QQmlListReference(QObject *object, const char *property, QQmlEngine *engine)
-: d(nullptr)
+QQmlListReference::QQmlListReference(QObject *object, const char *property)
+ : d(nullptr)
{
if (!object || !property) return;
QQmlPropertyData local;
- QQmlPropertyData *data =
- QQmlPropertyCache::property(engine, object, QLatin1String(property), nullptr, &local);
+ const QQmlPropertyData *data =
+ QQmlPropertyCache::property(object, QLatin1String(property), nullptr, &local);
if (!data || !data->isQList()) return;
- QQmlEnginePrivate *p = engine?QQmlEnginePrivate::get(engine):nullptr;
-
- int listType = QQmlMetaType::listType(data->propType().id());
- if (listType == -1) return;
-
d = new QQmlListReferencePrivate;
d->object = object;
- d->elementType = p ? p->rawMetaObjectForType(listType) : QQmlMetaType::qmlType(listType).baseMetaObject();
- d->propertyType = data->propType().id();
+ d->propertyType = data->propType();
void *args[] = { &d->property, nullptr };
QMetaObject::metacall(object, QMetaObject::ReadProperty, data->coreIndex(), args);
@@ -233,12 +214,11 @@ Returns the QMetaObject for the elements stored in the list property,
or \nullptr if the reference is invalid.
The QMetaObject can be used ahead of time to determine whether a given instance can be added
-to a list.
+to a list. If you didn't pass an engine on construction this may return nullptr.
*/
const QMetaObject *QQmlListReference::listElementType() const
{
- if (isValid()) return d->elementType.metaObject();
- else return nullptr;
+ return isValid() ? d->elementType() : nullptr;
}
/*!
@@ -347,7 +327,7 @@ bool QQmlListReference::append(QObject *object) const
{
if (!canAppend()) return false;
- if (object && !QQmlMetaObject::canConvert(object, d->elementType))
+ if (!isObjectCompatible(object, d))
return false;
d->property.append(&d->property, object);
@@ -392,6 +372,12 @@ qsizetype QQmlListReference::count() const
}
/*!
+\fn qsizetype QQmlListReference::size() const
+\since 6.2
+Returns the number of objects in the list, or 0 if the operation failed.
+*/
+
+/*!
Replaces the item at \a index in the list with \a object.
Returns true if the operation succeeded, otherwise false.
@@ -402,7 +388,7 @@ bool QQmlListReference::replace(qsizetype index, QObject *object) const
if (!canReplace())
return false;
- if (object && !QQmlMetaObject::canConvert(object, d->elementType))
+ if (!isObjectCompatible(object, d))
return false;
d->property.replace(&d->property, index, object);
@@ -461,7 +447,7 @@ Q_PROPERTY(QQmlListProperty<Fruit> fruit READ fruit)
QML list properties are type-safe - in this case \c {Fruit} is a QObject type that
\c {Apple}, \c {Orange} and \c {Banana} all derive from.
-\sa {Extending QML - Object and List Property Types Example}
+\sa {Chapter 5: Using List Property Types}
*/
/*!
@@ -476,6 +462,7 @@ QML list properties are type-safe - in this case \c {Fruit} is a QObject type th
\sa QML_LIST_PROPERTY_ASSIGN_BEHAVIOR_REPLACE_IF_NOT_DEFAULT
\sa QML_LIST_PROPERTY_ASSIGN_BEHAVIOR_REPLACE
+ \sa {Defining Object Types through QML Documents}
*/
/*!
@@ -492,6 +479,7 @@ QML list properties are type-safe - in this case \c {Fruit} is a QObject type th
\sa QML_LIST_PROPERTY_ASSIGN_BEHAVIOR_APPEND
\sa QML_LIST_PROPERTY_ASSIGN_BEHAVIOR_REPLACE
+ \sa {Defining Object Types through QML Documents}
*/
/*!
@@ -506,6 +494,7 @@ QML list properties are type-safe - in this case \c {Fruit} is a QObject type th
\sa QML_LIST_PROPERTY_ASSIGN_BEHAVIOR_APPEND
\sa QML_LIST_PROPERTY_ASSIGN_BEHAVIOR_REPLACE_IF_NOT_DEFAULT
+ \sa {Defining Object Types through QML Documents}
*/
/*!
diff --git a/src/qml/qml/qqmllist.h b/src/qml/qml/qqmllist.h
index abf4ec6ebf..6f2c077764 100644
--- a/src/qml/qml/qqmllist.h
+++ b/src/qml/qml/qqmllist.h
@@ -1,49 +1,15 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLLIST_H
#define QQMLLIST_H
#include <QtQml/qtqmlglobal.h>
+
+#include <QtCore/qcontainerinfo.h>
#include <QtCore/qlist.h>
+#include <QtCore/qmetatype.h>
#include <QtCore/qvariant.h>
-#include <QtCore/QMetaType>
QT_BEGIN_NAMESPACE
@@ -54,11 +20,11 @@ struct QMetaObject;
#define QML_LIST_PROPERTY_ASSIGN_BEHAVIOR_REPLACE_IF_NOT_DEFAULT Q_CLASSINFO("QML.ListPropertyAssignBehavior", "ReplaceIfNotDefault")
#define QML_LIST_PROPERTY_ASSIGN_BEHAVIOR_REPLACE Q_CLASSINFO("QML.ListPropertyAssignBehavior", "Replace")
-#ifndef QQMLLISTPROPERTY
-#define QQMLLISTPROPERTY
template<typename T>
class QQmlListProperty {
public:
+ using value_type = T*;
+
using AppendFunction = void (*)(QQmlListProperty<T> *, T *);
using CountFunction = qsizetype (*)(QQmlListProperty<T> *);
using AtFunction = T *(*)(QQmlListProperty<T> *, qsizetype);
@@ -122,24 +88,45 @@ public:
ReplaceFunction replace = nullptr;
RemoveLastFunction removeLast = nullptr;
+ template<typename List>
+ List toList()
+ {
+ if constexpr (std::is_same_v<List, QList<T *>>) {
+ if (append == qlist_append)
+ return *static_cast<QList<T *> *>(data);
+ }
+
+ const qsizetype size = count(this);
+
+ List result;
+ if constexpr (QContainerInfo::has_reserve_v<List>)
+ result.reserve(size);
+
+ static_assert(QContainerInfo::has_push_back_v<List>);
+ for (qsizetype i = 0; i < size; ++i)
+ result.push_back(at(this, i));
+
+ return result;
+ }
+
private:
static void qlist_append(QQmlListProperty *p, T *v) {
- reinterpret_cast<QList<T *> *>(p->data)->append(v);
+ static_cast<QList<T *> *>(p->data)->append(v);
}
static qsizetype qlist_count(QQmlListProperty *p) {
- return reinterpret_cast<QList<T *> *>(p->data)->count();
+ return static_cast<QList<T *> *>(p->data)->size();
}
static T *qlist_at(QQmlListProperty *p, qsizetype idx) {
- return reinterpret_cast<QList<T *> *>(p->data)->at(idx);
+ return static_cast<QList<T *> *>(p->data)->at(idx);
}
static void qlist_clear(QQmlListProperty *p) {
- return reinterpret_cast<QList<T *> *>(p->data)->clear();
+ return static_cast<QList<T *> *>(p->data)->clear();
}
static void qlist_replace(QQmlListProperty *p, qsizetype idx, T *v) {
- return reinterpret_cast<QList<T *> *>(p->data)->replace(idx, v);
+ return static_cast<QList<T *> *>(p->data)->replace(idx, v);
}
static void qlist_removeLast(QQmlListProperty *p) {
- return reinterpret_cast<QList<T *> *>(p->data)->removeLast();
+ return static_cast<QList<T *> *>(p->data)->removeLast();
}
static void qslow_replace(QQmlListProperty<T> *list, qsizetype idx, T *v)
@@ -154,7 +141,7 @@ private:
for (qsizetype i = 0; i < length; ++i)
stash.append(i == idx ? v : list->at(list, i));
list->clear(list);
- for (T *item : qAsConst(stash))
+ for (T *item : std::as_const(stash))
list->append(list, item);
} else {
stash.reserve(length - idx - 1);
@@ -185,11 +172,10 @@ private:
for (qsizetype i = 0; i < length; ++i)
stash.append(list->at(list, i));
list->clear(list);
- for (T *item : qAsConst(stash))
+ for (T *item : std::as_const(stash))
list->append(list, item);
}
};
-#endif
class QQmlEngine;
class QQmlListReferencePrivate;
@@ -197,8 +183,17 @@ class Q_QML_EXPORT QQmlListReference
{
public:
QQmlListReference();
- explicit QQmlListReference(const QVariant &variant, QQmlEngine *engine = nullptr);
- QQmlListReference(QObject *, const char *property, QQmlEngine * = nullptr);
+
+#if QT_DEPRECATED_SINCE(6, 4)
+ QT_DEPRECATED_X("Drop the QQmlEngine* argument")
+ QQmlListReference(const QVariant &variant, [[maybe_unused]] QQmlEngine *engine);
+
+ QT_DEPRECATED_X("Drop the QQmlEngine* argument")
+ QQmlListReference(QObject *o, const char *property, [[maybe_unused]] QQmlEngine *engine);
+#endif
+
+ explicit QQmlListReference(const QVariant &variant);
+ QQmlListReference(QObject *o, const char *property);
QQmlListReference(const QQmlListReference &);
QQmlListReference &operator=(const QQmlListReference &);
~QQmlListReference();
@@ -222,6 +217,7 @@ public:
QObject *at(qsizetype) const;
bool clear() const;
qsizetype count() const;
+ qsizetype size() const { return count(); }
bool replace(qsizetype, QObject *) const;
bool removeLast() const;
bool operator==(const QQmlListReference &other) const {return d == other.d;}
diff --git a/src/qml/qml/qqmllist_p.h b/src/qml/qml/qqmllist_p.h
index e182ced51d..642b3c3db1 100644
--- a/src/qml/qml/qqmllist_p.h
+++ b/src/qml/qml/qqmllist_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLLIST_P_H
#define QQMLLIST_P_H
@@ -53,6 +17,10 @@
#include "qqmllist.h"
#include "qqmlmetaobject_p.h"
+#include "qqmlmetatype_p.h"
+#include <QtQml/private/qbipointer_p.h>
+
+#include <QtCore/qpointer.h>
QT_BEGIN_NAMESPACE
@@ -61,12 +29,11 @@ class QQmlListReferencePrivate
public:
QQmlListReferencePrivate();
- static QQmlListReference init(const QQmlListProperty<QObject> &, int, QQmlEngine *);
+ static QQmlListReference init(const QQmlListProperty<QObject> &, QMetaType);
QPointer<QObject> object;
- QQmlMetaObject elementType;
QQmlListProperty<QObject> property;
- int propertyType;
+ QMetaType propertyType;
void addref();
void release();
@@ -75,8 +42,189 @@ public:
static inline QQmlListReferencePrivate *get(QQmlListReference *ref) {
return ref->d;
}
+
+ const QMetaObject *elementType()
+ {
+ if (!m_elementType) {
+ m_elementType = QQmlMetaType::rawMetaObjectForType(
+ QQmlMetaType::listValueType(propertyType)).metaObject();
+ }
+
+ return m_elementType;
+ }
+
+private:
+ const QMetaObject *m_elementType = nullptr;
+};
+
+template<typename T>
+class QQmlListIterator {
+public:
+ using difference_type = qsizetype;
+ using iterator_category = std::random_access_iterator_tag;
+ using value_type = T*;
+
+ class reference
+ {
+ public:
+ explicit reference(const QQmlListIterator *iter) : m_iter(iter) {}
+ reference(const reference &) = default;
+ reference(reference &&) = default;
+ ~reference() = default;
+
+ operator T *() const
+ {
+ if (m_iter == nullptr)
+ return nullptr;
+ return m_iter->m_list->at(m_iter->m_list, m_iter->m_i);
+ }
+
+ reference &operator=(T *value) {
+ m_iter->m_list->replace(m_iter->m_list, m_iter->m_i, value);
+ return *this;
+ }
+
+ reference &operator=(const reference &value) { return operator=((T *)(value)); }
+ reference &operator=(reference &&value) { return operator=((T *)(value)); }
+
+ friend void swap(reference a, reference b)
+ {
+ T *tmp = a;
+ a = b;
+ b = std::move(tmp);
+ }
+ private:
+ const QQmlListIterator *m_iter;
+ };
+
+ class pointer
+ {
+ public:
+ explicit pointer(const QQmlListIterator *iter) : m_iter(iter) {}
+ reference operator*() const { return reference(m_iter); }
+ QQmlListIterator operator->() const { return *m_iter; }
+
+ private:
+ const QQmlListIterator *m_iter;
+ };
+
+ QQmlListIterator() = default;
+ QQmlListIterator(QQmlListProperty<T> *list, qsizetype i) : m_list(list), m_i(i) {}
+
+ QQmlListIterator &operator++()
+ {
+ ++m_i;
+ return *this;
+ }
+
+ QQmlListIterator operator++(int)
+ {
+ QQmlListIterator result = *this;
+ ++m_i;
+ return result;
+ }
+
+ QQmlListIterator &operator--()
+ {
+ --m_i;
+ return *this;
+ }
+
+ QQmlListIterator operator--(int)
+ {
+ QQmlListIterator result = *this;
+ --m_i;
+ return result;
+ }
+
+ QQmlListIterator &operator+=(qsizetype j)
+ {
+ m_i += j;
+ return *this;
+ }
+
+ QQmlListIterator &operator-=(qsizetype j)
+ {
+ m_i -= j;
+ return *this;
+ }
+
+ QQmlListIterator operator+(qsizetype j)
+ {
+ return QQmlListIterator(m_list, m_i + j);
+ }
+
+ QQmlListIterator operator-(qsizetype j)
+ {
+ return QQmlListIterator(m_list, m_i - j);
+ }
+
+ reference operator*() const
+ {
+ return reference(this);
+ }
+
+ pointer operator->() const
+ {
+ return pointer(this);
+ }
+
+private:
+ friend inline bool operator==(const QQmlListIterator &a, const QQmlListIterator &b)
+ {
+ return a.m_list == b.m_list && a.m_i == b.m_i;
+ }
+
+ friend inline bool operator!=(const QQmlListIterator &a, const QQmlListIterator &b)
+ {
+ return a.m_list != b.m_list || a.m_i != b.m_i;
+ }
+
+ friend inline bool operator<(const QQmlListIterator &i, const QQmlListIterator &j)
+ {
+ return i - j < 0;
+ }
+
+ friend inline bool operator>=(const QQmlListIterator &i, const QQmlListIterator &j)
+ {
+ return !(i < j);
+ }
+
+ friend inline bool operator>(const QQmlListIterator &i, const QQmlListIterator &j)
+ {
+ return i - j > 0;
+ }
+
+ friend inline bool operator<=(const QQmlListIterator &i, const QQmlListIterator &j)
+ {
+ return !(i > j);
+ }
+
+ friend inline QQmlListIterator operator+(qsizetype i, const QQmlListIterator &j)
+ {
+ return j + i;
+ }
+
+ friend inline qsizetype operator-(const QQmlListIterator &i, const QQmlListIterator &j)
+ {
+ return i.m_i - j.m_i;
+ }
+
+ QQmlListProperty<T> *m_list = nullptr;
+ qsizetype m_i = 0;
};
+template<typename T>
+QQmlListIterator<T> begin(QQmlListProperty<T> &list)
+{
+ return QQmlListIterator<T>(&list, 0);
+}
+
+template<typename T>
+QQmlListIterator<T> end(QQmlListProperty<T> &list)
+{
+ return QQmlListIterator<T>(&list, list.count(&list));
+}
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmllistwrapper.cpp b/src/qml/qml/qqmllistwrapper.cpp
index e5c1cb04a9..8d5a585b62 100644
--- a/src/qml/qml/qqmllistwrapper.cpp
+++ b/src/qml/qml/qqmllistwrapper.cpp
@@ -1,105 +1,174 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qqmllistwrapper_p.h"
+
+#include <QtQml/qqmlinfo.h>
+
#include <private/qqmllist_p.h>
-#include <private/qv4objectproto_p.h>
-#include <qv4objectiterator_p.h>
+#include <private/qv4arrayiterator_p.h>
+#include <private/qv4arrayobject_p.h>
#include <private/qv4functionobject_p.h>
+#include <private/qv4objectiterator_p.h>
+#include <private/qv4objectproto_p.h>
#include <private/qv4qobjectwrapper_p.h>
+#include <private/qv4symbol_p.h>
QT_BEGIN_NAMESPACE
using namespace QV4;
+using namespace Qt::StringLiterals;
DEFINE_OBJECT_VTABLE(QmlListWrapper);
-void Heap::QmlListWrapper::init()
+static void setArrayData(Heap::QmlListWrapper *d)
+{
+ QV4::Scope scope(d->internalClass->engine);
+ QV4::ScopedObject o(scope, d);
+ o->arrayCreate();
+}
+
+struct ListWrapperObject
+{
+ QV4::Scope scope;
+ QV4::ScopedObject object;
+
+ ListWrapperObject(QQmlListProperty<QObject> *p)
+ : scope(static_cast<Heap::QmlListWrapper *>(p->data)->internalClass->engine)
+ , object(scope, static_cast<Heap::QmlListWrapper *>(p->data))
+ {
+ Q_ASSERT(object);
+ Q_ASSERT(object->arrayData());
+ }
+
+ Heap::ArrayData *arrayData() const
+ {
+ return object->arrayData();
+ }
+};
+
+static void appendWrapped(QQmlListProperty<QObject> *p, QObject *o)
+{
+ ListWrapperObject object(p);
+ Heap::ArrayData *arrayData = object.arrayData();
+
+ const uint length = arrayData->length();
+ if (Q_UNLIKELY(length == std::numeric_limits<uint>::max())) {
+ object.scope.engine->throwRangeError(QLatin1String("Too many elements."));
+ return;
+ }
+
+ ArrayData::realloc(object.object, Heap::ArrayData::Simple, length + 1, false);
+ arrayData->vtable()->put(
+ object.object, length, QV4::QObjectWrapper::wrap(object.scope.engine, o));
+}
+
+static qsizetype countWrapped(QQmlListProperty<QObject> *p)
+{
+ ListWrapperObject object(p);
+ return object.arrayData()->length();
+}
+
+static QObject *atWrapped(QQmlListProperty<QObject> *p, qsizetype i)
+{
+ ListWrapperObject object(p);
+ QV4::Scoped<QObjectWrapper> result(object.scope, object.arrayData()->get(i));
+ return result ? result->object() : nullptr;
+}
+
+static void clearWrapped(QQmlListProperty<QObject> *p)
+{
+ ListWrapperObject object(p);
+ object.arrayData()->vtable()->truncate(object.object, 0);
+}
+
+static void replaceWrapped(QQmlListProperty<QObject> *p, qsizetype i, QObject *o)
+{
+ ListWrapperObject object(p);
+ object.arrayData()->vtable()->put(
+ object.object, i, QV4::QObjectWrapper::wrap(object.scope.engine, o));
+}
+
+static void removeLastWrapped(QQmlListProperty<QObject> *p)
+{
+ ListWrapperObject object(p);
+ Heap::ArrayData *arrayData = object.arrayData();
+ const uint length = arrayData->length();
+ if (length > 0)
+ arrayData->vtable()->truncate(object.object, length - 1);
+}
+
+void Heap::QmlListWrapper::init(QMetaType propertyType)
+{
+ Object::init();
+ m_object.init();
+ m_propertyType = propertyType.iface();
+ setArrayData(this);
+ *property() = QQmlListProperty<QObject>(
+ nullptr, this,
+ appendWrapped, countWrapped, atWrapped,
+ clearWrapped, replaceWrapped, removeLastWrapped);
+}
+
+void Heap::QmlListWrapper::init(QObject *object, int propertyId, QMetaType propertyType)
+{
+ Object::init();
+ m_object.init(object);
+ m_propertyType = propertyType.iface();
+ void *args[] = { property(), nullptr };
+ QMetaObject::metacall(object, QMetaObject::ReadProperty, propertyId, args);
+}
+
+void Heap::QmlListWrapper::init(
+ QObject *object, const QQmlListProperty<QObject> &list, QMetaType propertyType)
{
Object::init();
- object.init();
- QV4::Scope scope(internalClass->engine);
- QV4::ScopedObject o(scope, this);
- o->setArrayType(Heap::ArrayData::Custom);
+ m_object.init(object);
+ m_propertyType = propertyType.iface();
+ *property() = list;
}
void Heap::QmlListWrapper::destroy()
{
- object.destroy();
+ m_object.destroy();
Object::destroy();
}
-ReturnedValue QmlListWrapper::create(ExecutionEngine *engine, QObject *object, int propId, int propType)
+ReturnedValue QmlListWrapper::create(
+ ExecutionEngine *engine, QObject *object, int propId, QMetaType propType)
{
if (!object || propId == -1)
return Encode::null();
-
- Scope scope(engine);
-
- Scoped<QmlListWrapper> r(scope, engine->memoryManager->allocate<QmlListWrapper>());
- r->d()->object = object;
- r->d()->propertyType = propType;
- void *args[] = { &r->d()->property(), nullptr };
- QMetaObject::metacall(object, QMetaObject::ReadProperty, propId, args);
- return r.asReturnedValue();
+ return engine->memoryManager->allocate<QmlListWrapper>(object, propId, propType)
+ ->asReturnedValue();
}
-ReturnedValue QmlListWrapper::create(ExecutionEngine *engine, const QQmlListProperty<QObject> &prop, int propType)
+ReturnedValue QmlListWrapper::create(
+ ExecutionEngine *engine, const QQmlListProperty<QObject> &prop, QMetaType propType)
{
- Scope scope(engine);
+ return engine->memoryManager->allocate<QmlListWrapper>(prop.object, prop, propType)
+ ->asReturnedValue();
+}
- Scoped<QmlListWrapper> r(scope, engine->memoryManager->allocate<QmlListWrapper>());
- r->d()->object = prop.object;
- r->d()->property() = prop;
- r->d()->propertyType = propType;
- return r.asReturnedValue();
+ReturnedValue QmlListWrapper::create(ExecutionEngine *engine, QMetaType propType)
+{
+ return engine->memoryManager->allocate<QmlListWrapper>(propType)->asReturnedValue();
}
QVariant QmlListWrapper::toVariant() const
{
- if (!d()->object)
+ if (!d()->object())
return QVariant();
- return QVariant::fromValue(QQmlListReferencePrivate::init(d()->property(), d()->propertyType, engine()->qmlEngine()));
+ return QVariant::fromValue(toListReference());
}
+QQmlListReference QmlListWrapper::toListReference() const
+{
+ const Heap::QmlListWrapper *wrapper = d();
+ return QQmlListReferencePrivate::init(*wrapper->property(), wrapper->propertyType());
+}
ReturnedValue QmlListWrapper::virtualGet(const Managed *m, PropertyKey id, const Value *receiver, bool *hasProperty)
{
@@ -108,12 +177,14 @@ ReturnedValue QmlListWrapper::virtualGet(const Managed *m, PropertyKey id, const
QV4::ExecutionEngine *v4 = w->engine();
if (id.isArrayIndex()) {
- uint index = id.asArrayIndex();
- quint32 count = w->d()->property().count ? w->d()->property().count(&w->d()->property()) : 0;
- if (index < count && w->d()->property().at) {
+ const uint index = id.asArrayIndex();
+ const quint32 count = w->d()->property()->count
+ ? w->d()->property()->count(w->d()->property())
+ : 0;
+ if (index < count && w->d()->property()->at) {
if (hasProperty)
*hasProperty = true;
- return QV4::QObjectWrapper::wrap(v4, w->d()->property().at(&w->d()->property(), index));
+ return QV4::QObjectWrapper::wrap(v4, w->d()->property()->at(w->d()->property(), index));
}
if (hasProperty)
@@ -121,16 +192,17 @@ ReturnedValue QmlListWrapper::virtualGet(const Managed *m, PropertyKey id, const
return Value::undefinedValue().asReturnedValue();
}
- if (id.isString() && id == v4->id_length()->propertyKey()) {
- if (hasProperty)
- *hasProperty = true;
- quint32 count = w->d()->property().count ? w->d()->property().count(&w->d()->property()) : 0;
- return Value::fromUInt32(count).asReturnedValue();
- }
-
return Object::virtualGet(m, id, receiver, hasProperty);
}
+qint64 QmlListWrapper::virtualGetLength(const Managed *m)
+{
+ Q_ASSERT(m->as<QmlListWrapper>());
+ QQmlListProperty<QObject> *property = static_cast<const QmlListWrapper *>(m)->d()->property();
+ Q_ASSERT(property);
+ return property->count ? property->count(property) : 0;
+}
+
bool QmlListWrapper::virtualPut(Managed *m, PropertyKey id, const Value &value, Value *receiver)
{
Q_ASSERT(m->as<QmlListWrapper>());
@@ -138,7 +210,7 @@ bool QmlListWrapper::virtualPut(Managed *m, PropertyKey id, const Value &value,
const auto *w = static_cast<const QmlListWrapper *>(m);
QV4::ExecutionEngine *v4 = w->engine();
- QQmlListProperty<QObject> *prop = &(w->d()->property());
+ QQmlListProperty<QObject> *prop = w->d()->property();
if (id.isArrayIndex()) {
if (!prop->count || !prop->replace)
@@ -149,6 +221,11 @@ bool QmlListWrapper::virtualPut(Managed *m, PropertyKey id, const Value &value,
if (count < 0 || index >= uint(count))
return false;
+ if (value.isNull()) {
+ prop->replace(prop, index, nullptr);
+ return true;
+ }
+
QV4::Scope scope(v4);
QV4::ScopedObject so(scope, value.toObject(scope.engine));
if (auto *wrapper = so->as<QV4::QObjectWrapper>()) {
@@ -159,43 +236,6 @@ bool QmlListWrapper::virtualPut(Managed *m, PropertyKey id, const Value &value,
return false;
}
- if (id.isString() && id == v4->id_length()->propertyKey()) {
- if (!prop->count)
- return false;
-
- const quint32 count = prop->count(prop);
-
- bool ok = false;
- const uint newLength = value.asArrayLength(&ok);
- if (!ok)
- return false;
-
- if (newLength == 0) {
- if (!prop->clear)
- return false;
- prop->clear(prop);
- return true;
- }
-
- if (newLength < count) {
- if (!prop->removeLast)
- return false;
-
- for (uint i = newLength; i < count; ++i)
- prop->removeLast(prop);
-
- return true;
- }
-
- if (!prop->append)
- return false;
-
- for (uint i = count; i < newLength; ++i)
- prop->append(prop, nullptr);
-
- return true;
- }
-
return Object::virtualPut(m, id, value, receiver);
}
@@ -210,18 +250,24 @@ PropertyKey QmlListWrapperOwnPropertyKeyIterator::next(const Object *o, Property
{
const QmlListWrapper *w = static_cast<const QmlListWrapper *>(o);
- quint32 count = w->d()->property().count ? w->d()->property().count(&w->d()->property()) : 0;
+ quint32 count = w->d()->property()->count ? w->d()->property()->count(w->d()->property()) : 0;
if (arrayIndex < count) {
uint index = arrayIndex;
++arrayIndex;
if (attrs)
*attrs = QV4::Attr_Data;
- if (pd)
- pd->value = QV4::QObjectWrapper::wrap(w->engine(), w->d()->property().at(&w->d()->property(), index));
+ if (pd) {
+ pd->value = QV4::QObjectWrapper::wrap(
+ w->engine(), w->d()->property()->at(w->d()->property(), index));
+ }
return PropertyKey::fromArrayIndex(index);
+ } else if (memberIndex == 0) {
+ ++memberIndex;
+ return o->engine()->id_length()->propertyKey();
}
- return ObjectOwnPropertyKeyIterator::next(o, pd, attrs);
+ // You cannot add any own properties via the regular JavaScript interfaces.
+ return PropertyKey::invalid();
}
OwnPropertyKeyIterator *QmlListWrapper::virtualOwnPropertyKeys(const Object *m, Value *target)
@@ -230,9 +276,48 @@ OwnPropertyKeyIterator *QmlListWrapper::virtualOwnPropertyKeys(const Object *m,
return new QmlListWrapperOwnPropertyKeyIterator;
}
-void PropertyListPrototype::init(ExecutionEngine *)
+void PropertyListPrototype::init()
{
+ defineDefaultProperty(QStringLiteral("pop"), method_pop, 0);
defineDefaultProperty(QStringLiteral("push"), method_push, 1);
+ defineDefaultProperty(QStringLiteral("shift"), method_shift, 0);
+ defineDefaultProperty(QStringLiteral("splice"), method_splice, 2);
+ defineDefaultProperty(QStringLiteral("unshift"), method_unshift, 1);
+ defineDefaultProperty(QStringLiteral("indexOf"), method_indexOf, 1);
+ defineDefaultProperty(QStringLiteral("lastIndexOf"), method_lastIndexOf, 1);
+ defineDefaultProperty(QStringLiteral("sort"), method_sort, 1);
+ defineAccessorProperty(QStringLiteral("length"), method_get_length, method_set_length);
+}
+
+ReturnedValue PropertyListPrototype::method_pop(const FunctionObject *b, const Value *thisObject, const Value *, int)
+{
+ Scope scope(b);
+ ScopedObject instance(scope, thisObject->toObject(scope.engine));
+ if (!instance)
+ RETURN_UNDEFINED();
+
+ QmlListWrapper *w = instance->as<QmlListWrapper>();
+ if (!w)
+ RETURN_UNDEFINED();
+
+ QQmlListProperty<QObject> *property = w->d()->property();
+
+ if (!property->count)
+ return scope.engine->throwTypeError(u"List doesn't define a Count function"_s);
+ const qsizetype len = property->count(property);
+ if (!len)
+ RETURN_UNDEFINED();
+
+ if (!property->at)
+ return scope.engine->throwTypeError(u"List doesn't define an At function"_s);
+ ScopedValue result(
+ scope, QV4::QObjectWrapper::wrap(scope.engine, property->at(property, len - 1)));
+
+ if (!property->removeLast)
+ return scope.engine->throwTypeError(u"List doesn't define a RemoveLast function"_s);
+ property->removeLast(property);
+
+ return result->asReturnedValue();
}
ReturnedValue PropertyListPrototype::method_push(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
@@ -244,17 +329,425 @@ ReturnedValue PropertyListPrototype::method_push(const FunctionObject *b, const
QmlListWrapper *w = instance->as<QmlListWrapper>();
if (!w)
RETURN_UNDEFINED();
- if (!w->d()->property().append)
- THROW_GENERIC_ERROR("List doesn't define an Append function");
- QV4::ScopedObject so(scope);
- for (int i = 0, ei = argc; i < ei; ++i)
- {
- so = argv[i].toObject(scope.engine);
- if (QV4::QObjectWrapper *wrapper = so->as<QV4::QObjectWrapper>())
- w->d()->property().append(&w->d()->property(), wrapper->object() );
+ QQmlListProperty<QObject> *property = w->d()->property();
+ if (!property->append)
+ return scope.engine->throwTypeError(u"List doesn't define an Append function"_s);
+ if (!property->count)
+ return scope.engine->throwTypeError(u"List doesn't define a Count function"_s);
+
+ for (int i = 0; i < argc; ++i) {
+ const Value &arg = argv[i];
+ if (!arg.isNull() && !arg.as<QObjectWrapper>())
+ THROW_TYPE_ERROR();
+ }
+
+ const qsizetype length = property->count(property);
+ if (!qIsAtMostUintLimit(length, std::numeric_limits<uint>::max() - argc))
+ return scope.engine->throwRangeError(QString::fromLatin1("List length out of range."));
+
+ for (int i = 0; i < argc; ++i) {
+ if (argv[i].isNull())
+ property->append(property, nullptr);
+ else
+ property->append(property, argv[i].as<QV4::QObjectWrapper>()->object());
+ }
+
+ const auto actualLength = property->count(property);
+ if (actualLength != length + argc)
+ qmlWarning(property->object) << "List didn't append all objects";
+
+ return Encode(uint(actualLength));
+}
+
+ReturnedValue PropertyListPrototype::method_shift(const FunctionObject *b, const Value *thisObject, const Value *, int)
+{
+ Scope scope(b);
+ ScopedObject instance(scope, thisObject->toObject(scope.engine));
+ if (!instance)
+ RETURN_UNDEFINED();
+ QmlListWrapper *w = instance->as<QmlListWrapper>();
+ if (!w)
+ RETURN_UNDEFINED();
+
+ QQmlListProperty<QObject> *property = w->d()->property();
+
+ if (!property->count)
+ return scope.engine->throwTypeError(u"List doesn't define a Count function"_s);
+ const qsizetype len = property->count(property);
+ if (!len)
+ RETURN_UNDEFINED();
+
+ if (!property->at)
+ return scope.engine->throwTypeError(u"List doesn't define an At function"_s);
+ ScopedValue result(scope, QV4::QObjectWrapper::wrap(scope.engine, property->at(property, 0)));
+
+ if (!property->replace)
+ return scope.engine->throwTypeError(u"List doesn't define a Replace function"_s);
+ if (!property->removeLast)
+ return scope.engine->throwTypeError(u"List doesn't define a RemoveLast function"_s);
+
+ for (qsizetype i = 1; i < len; ++i)
+ property->replace(property, i - 1, property->at(property, i));
+ property->removeLast(property);
+
+ return result->asReturnedValue();
+}
+
+ReturnedValue PropertyListPrototype::method_splice(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
+{
+ Scope scope(b);
+ ScopedObject instance(scope, thisObject->toObject(scope.engine));
+ if (!instance)
+ RETURN_UNDEFINED();
+ QmlListWrapper *w = instance->as<QmlListWrapper>();
+ if (!w)
+ RETURN_UNDEFINED();
+
+ QQmlListProperty<QObject> *property = w->d()->property();
+
+ if (!property->count)
+ return scope.engine->throwTypeError(u"List doesn't define a Count function"_s);
+ const qsizetype len = property->count(property);
+
+ const double rs = (argc ? argv[0] : Value::undefinedValue()).toInteger();
+ qsizetype start;
+ if (rs < 0)
+ start = static_cast<qsizetype>(qMax(0., len + rs));
+ else
+ start = static_cast<qsizetype>(qMin(rs, static_cast<double>(len)));
+
+ qsizetype deleteCount = 0;
+ qsizetype itemCount = 0;
+ if (argc == 1) {
+ deleteCount = len - start;
+ } else if (argc > 1){
+ itemCount = argc - 2;
+ double dc = argv[1].toInteger();
+ deleteCount = static_cast<qsizetype>(qMin(qMax(dc, 0.), double(len - start)));
+ }
+
+ if (itemCount > deleteCount
+ && len > std::numeric_limits<qsizetype>::max() - itemCount + deleteCount) {
+ return scope.engine->throwTypeError();
+ }
+
+ if (!qIsAtMostUintLimit(deleteCount, std::numeric_limits<uint>::max() - 1))
+ return scope.engine->throwRangeError(QString::fromLatin1("List length out of range."));
+
+ if (!property->at)
+ return scope.engine->throwTypeError(u"List doesn't define an At function"_s);
+
+ for (qsizetype i = 0; i < itemCount; ++i) {
+ const auto arg = argv[i + 2];
+ if (!arg.isNull() && !arg.as<QObjectWrapper>())
+ THROW_TYPE_ERROR();
+ }
+
+ ScopedArrayObject newArray(scope, scope.engine->newArrayObject());
+ newArray->arrayReserve(deleteCount);
+ ScopedValue v(scope);
+ for (qsizetype i = 0; i < deleteCount; ++i) {
+ newArray->arrayPut(
+ i, QObjectWrapper::wrap(scope.engine, property->at(property, start + i)));
+ }
+ newArray->setArrayLengthUnchecked(deleteCount);
+
+ if (!property->replace)
+ return scope.engine->throwTypeError(u"List doesn't define a Replace function"_s);
+ if (!property->removeLast)
+ return scope.engine->throwTypeError(u"List doesn't define a RemoveLast function"_s);
+ if (!property->append)
+ return scope.engine->throwTypeError(u"List doesn't define an Append function"_s);
+
+ if (itemCount < deleteCount) {
+ for (qsizetype k = start; k < len - deleteCount; ++k)
+ property->replace(property, k + itemCount, property->at(property, k + deleteCount));
+ for (qsizetype k = len; k > len - deleteCount + itemCount; --k)
+ property->removeLast(property);
+ } else if (itemCount > deleteCount) {
+ for (qsizetype k = 0; k < itemCount - deleteCount; ++k)
+ property->append(property, nullptr);
+ for (qsizetype k = len - deleteCount; k > start; --k) {
+ property->replace(
+ property, k + itemCount - 1, property->at(property, k + deleteCount - 1));
+ }
+ }
+
+ for (qsizetype i = 0; i < itemCount; ++i) {
+ const auto arg = argv[i + 2];
+ if (arg.isNull())
+ property->replace(property, start + i, nullptr);
+ else
+ property->replace(property, start + i, arg.as<QObjectWrapper>()->object());
+ }
+
+ return newArray->asReturnedValue();
+}
+
+ReturnedValue PropertyListPrototype::method_unshift(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
+{
+ Scope scope(b);
+ ScopedObject instance(scope, thisObject->toObject(scope.engine));
+ if (!instance)
+ RETURN_UNDEFINED();
+
+ QmlListWrapper *w = instance->as<QmlListWrapper>();
+ if (!w)
+ RETURN_UNDEFINED();
+
+ QQmlListProperty<QObject> *property = w->d()->property();
+
+ if (!property->count)
+ return scope.engine->throwTypeError(u"List doesn't define a Count function"_s);
+ const qsizetype len = property->count(property);
+
+ if (std::numeric_limits<qsizetype>::max() - len < argc || !qIsAtMostUintLimit(len + argc))
+ return scope.engine->throwRangeError(QString::fromLatin1("List length out of range."));
+
+ if (!property->append)
+ return scope.engine->throwTypeError(u"List doesn't define an Append function"_s);
+ if (!property->replace)
+ return scope.engine->throwTypeError(u"List doesn't define a Replace function"_s);
+
+ for (int i = 0; i < argc; ++i) {
+ const auto arg = argv[i];
+ if (!arg.isNull() && !arg.as<QObjectWrapper>())
+ THROW_TYPE_ERROR();
+ }
+
+ for (int i = 0; i < argc; ++i)
+ property->append(property, nullptr);
+ if (property->count(property) != argc + len)
+ return scope.engine->throwTypeError(u"List doesn't append null objects"_s);
+
+ for (qsizetype k = len; k > 0; --k)
+ property->replace(property, k + argc - 1, property->at(property, k - 1));
+
+ for (int i = 0; i < argc; ++i) {
+ const auto *wrapper = argv[i].as<QObjectWrapper>();
+ property->replace(property, i, wrapper ? wrapper->object() : nullptr);
+ }
+
+ return Encode(uint(len + argc));
+}
+
+template<typename Iterate>
+ReturnedValue firstOrLastIndexOf(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc, Iterate iterate)
+{
+ Scope scope(b);
+
+ // Undefined cannot be encoded as QObject*. In particular it's not nullptr.
+ if (argc == 0)
+ THROW_TYPE_ERROR();
+
+ QObject *searchValue;
+ if (argv[0].isNull()) {
+ searchValue = nullptr;
+ } else {
+ Scoped<QObjectWrapper> wrapper(scope, argv[0]);
+ if (wrapper)
+ searchValue = wrapper->object();
+ else
+ THROW_TYPE_ERROR();
}
- return Encode::undefined();
+
+ ScopedObject instance(scope, thisObject->toObject(scope.engine));
+ if (!instance)
+ RETURN_UNDEFINED();
+
+ QmlListWrapper *w = instance->as<QmlListWrapper>();
+ if (!w)
+ RETURN_UNDEFINED();
+
+ QQmlListProperty<QObject> *property = w->d()->property();
+
+ if (!property->count)
+ return scope.engine->throwTypeError(u"List doesn't define a Count function"_s);
+ const qsizetype len = property->count(property);
+ if (!len)
+ return Encode(-1);
+
+
+ return iterate(scope.engine, property, len, searchValue);
+}
+
+ReturnedValue PropertyListPrototype::method_indexOf(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
+{
+ return firstOrLastIndexOf(
+ b, thisObject, argv, argc,
+ [argc, argv](ExecutionEngine *engine, QQmlListProperty<QObject> *property,
+ qsizetype len, QObject *searchValue) -> ReturnedValue {
+ qsizetype fromIndex = 0;
+ if (argc >= 2) {
+ double f = argv[1].toInteger();
+ if (hasExceptionOrIsInterrupted(engine))
+ return Encode::undefined();
+ if (f >= len)
+ return Encode(-1);
+ if (f < 0)
+ f = qMax(len + f, 0.);
+ fromIndex = qsizetype(f);
+ }
+
+ for (qsizetype i = fromIndex; i < len; ++i) {
+ if (property->at(property, i) == searchValue) {
+ if (qIsAtMostUintLimit(i))
+ return Encode(uint(i));
+ return engine->throwRangeError(QString::fromLatin1("List length out of range."));
+ }
+ }
+
+ return Encode(-1);
+ });
+}
+
+ReturnedValue PropertyListPrototype::method_lastIndexOf(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
+{
+ return firstOrLastIndexOf(
+ b, thisObject, argv, argc,
+ [argc, argv](ExecutionEngine *engine, QQmlListProperty<QObject> *property,
+ qsizetype len, QObject *searchValue) -> ReturnedValue {
+ qsizetype fromIndex = len - 1;
+ if (argc >= 2) {
+ double f = argv[1].toInteger();
+ if (hasExceptionOrIsInterrupted(engine))
+ return Encode::undefined();
+ if (f > 0)
+ f = qMin(f, (double)(len - 1));
+ else if (f < 0) {
+ f = len + f;
+ if (f < 0)
+ return Encode(-1);
+ }
+ fromIndex = qsizetype(f);
+ }
+
+ for (qsizetype i = fromIndex; i >= 0; --i) {
+ if (property->at(property, i) == searchValue) {
+ if (qIsAtMostUintLimit(i))
+ return Encode(uint(i));
+ return engine->throwRangeError(QString::fromLatin1("List length out of range."));
+ }
+ }
+
+ return Encode(-1);
+ });
+}
+
+ReturnedValue PropertyListPrototype::method_sort(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
+{
+ Scope scope(b);
+ ScopedObject instance(scope, thisObject->toObject(scope.engine));
+ if (!instance)
+ RETURN_UNDEFINED();
+
+ QmlListWrapper *w = instance->as<QmlListWrapper>();
+ if (!w)
+ RETURN_UNDEFINED();
+
+ QQmlListProperty<QObject> *property = w->d()->property();
+
+ if (!property->count)
+ return scope.engine->throwTypeError(u"List doesn't define a Count function"_s);
+ if (property->count(property) == 0)
+ return thisObject->asReturnedValue();
+ if (!property->at)
+ return scope.engine->throwTypeError(u"List doesn't define an At function"_s);
+ if (!property->replace)
+ return scope.engine->throwTypeError(u"List doesn't define a Replace function"_s);
+
+ ScopedValue comparefn(scope, argc ? argv[0] : Value::undefinedValue());
+ if (!comparefn->isUndefined() && !comparefn->isFunctionObject())
+ THROW_TYPE_ERROR();
+
+ const ArrayElementLessThan lessThan(scope.engine, comparefn);
+ sortHelper(begin(*property), end(*property), [&](QObject *a, QObject *b) {
+ Scoped<QObjectWrapper> o1(scope, QObjectWrapper::wrap(scope.engine, a));
+ Scoped<QObjectWrapper> o2(scope, QObjectWrapper::wrap(scope.engine, b));
+ return lessThan(o1, o2);
+ });
+
+ return thisObject->asReturnedValue();
+}
+
+ReturnedValue PropertyListPrototype::method_get_length(const FunctionObject *b, const Value *thisObject, const Value *, int)
+{
+ Scope scope(b);
+ ScopedObject instance(scope, thisObject->toObject(scope.engine));
+ if (!instance)
+ RETURN_UNDEFINED();
+
+ const QmlListWrapper *w = instance->as<QmlListWrapper>();
+ if (!w)
+ RETURN_UNDEFINED();
+
+ QQmlListProperty<QObject> *property = w->d()->property();
+ if (!property->count)
+ return scope.engine->throwTypeError(u"List doesn't define a Count function"_s);
+
+ qsizetype count = property->count(property);
+ if (qIsAtMostUintLimit(count))
+ return Encode(uint(count));
+
+ return scope.engine->throwRangeError(QString::fromLatin1("List length out of range."));
+}
+
+ReturnedValue PropertyListPrototype::method_set_length(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
+{
+ QV4::Scope scope(b);
+ ScopedObject instance(scope, thisObject->toObject(scope.engine));
+ if (!instance)
+ RETURN_UNDEFINED();
+
+ const QmlListWrapper *w = instance->as<QmlListWrapper>();
+ if (!w)
+ RETURN_UNDEFINED();
+
+ QQmlListProperty<QObject> *property = w->d()->property();
+
+ bool ok = false;
+ const uint newLength = argc ? argv[0].asArrayLength(&ok) : 0;
+ if (!ok)
+ return scope.engine->throwRangeError(QString::fromLatin1("Invalid list length."));
+
+ if (newLength == 0 && property->clear) {
+ property->clear(property);
+ return true;
+ }
+
+ if (!property->count)
+ return scope.engine->throwTypeError(u"List doesn't define a Count function"_s);
+
+ qsizetype count = property->count(property);
+ if (!qIsAtMostUintLimit(count))
+ return scope.engine->throwRangeError(QString::fromLatin1("List length out of range."));
+
+ if (newLength < uint(count)) {
+ if (!property->removeLast)
+ return scope.engine->throwTypeError(u"List doesn't define a RemoveLast function"_s);
+
+ for (uint i = count; i > newLength; --i)
+ property->removeLast(property);
+
+ return true;
+ }
+
+ if (!property->append)
+ return scope.engine->throwTypeError(u"List doesn't define an Append function"_s);
+
+ for (uint i = count; i < newLength; ++i)
+ property->append(property, nullptr);
+
+ count = property->count(property);
+ if (!qIsAtMostUintLimit(count))
+ return scope.engine->throwRangeError(QString::fromLatin1("List length out of range."));
+
+ if (uint(count) != newLength)
+ return scope.engine->throwTypeError(u"List doesn't append null objects"_s);
+
+ return true;
+
}
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmllistwrapper_p.h b/src/qml/qml/qqmllistwrapper_p.h
index 26a5023e6b..55100e9a07 100644
--- a/src/qml/qml/qqmllistwrapper_p.h
+++ b/src/qml/qml/qqmllistwrapper_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLLISTWRAPPER_P_H
#define QQMLLISTWRAPPER_P_H
@@ -65,19 +29,33 @@ namespace QV4 {
namespace Heap {
-struct QmlListWrapper : Object {
- void init();
+struct QmlListWrapper : Object
+{
+ void init(QMetaType propertyType);
+ void init(QObject *object, int propertyId, QMetaType propertyType);
+ void init(QObject *object, const QQmlListProperty<QObject> &list, QMetaType propertyType);
void destroy();
- QV4QPointer<QObject> object;
- QQmlListProperty<QObject> &property() {
- return *reinterpret_cast<QQmlListProperty<QObject>*>(propertyData);
+ QObject *object() const { return m_object.data(); }
+ QMetaType propertyType() const { return QMetaType(m_propertyType); }
+
+ const QQmlListProperty<QObject> *property() const
+ {
+ return reinterpret_cast<const QQmlListProperty<QObject>*>(m_propertyData);
}
- int propertyType;
+ QQmlListProperty<QObject> *property()
+ {
+ return reinterpret_cast<QQmlListProperty<QObject>*>(m_propertyData);
+ }
private:
- void *propertyData[sizeof(QQmlListProperty<QObject>)/sizeof(void*)];
+ void *m_propertyData[sizeof(QQmlListProperty<QObject>)/sizeof(void*)];
+
+ QV4QPointer<QObject> m_object;
+
+ // interface instead of QMetaType to keep class a POD
+ const QtPrivate::QMetaTypeInterface *m_propertyType;
};
}
@@ -87,22 +65,37 @@ struct Q_QML_EXPORT QmlListWrapper : Object
V4_OBJECT2(QmlListWrapper, Object)
V4_NEEDS_DESTROY
V4_PROTOTYPE(propertyListPrototype)
+ Q_MANAGED_TYPE(QmlListProperty)
- static ReturnedValue create(ExecutionEngine *engine, QObject *object, int propId, int propType);
- static ReturnedValue create(ExecutionEngine *engine, const QQmlListProperty<QObject> &prop, int propType);
+ static ReturnedValue create(ExecutionEngine *engine, QObject *object, int propId, QMetaType propType);
+ static ReturnedValue create(ExecutionEngine *engine, const QQmlListProperty<QObject> &prop, QMetaType propType);
+ static ReturnedValue create(ExecutionEngine *engine, QMetaType propType);
QVariant toVariant() const;
+ QQmlListReference toListReference() const;
static ReturnedValue virtualGet(const Managed *m, PropertyKey id, const Value *receiver, bool *hasProperty);
+ static qint64 virtualGetLength(const Managed *m);
static bool virtualPut(Managed *m, PropertyKey id, const Value &value, Value *receiver);
static OwnPropertyKeyIterator *virtualOwnPropertyKeys(const Object *m, Value *target);
};
struct PropertyListPrototype : Object
{
- void init(ExecutionEngine *engine);
+ V4_PROTOTYPE(arrayPrototype)
+
+ void init();
+ static ReturnedValue method_pop(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
static ReturnedValue method_push(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
+ static ReturnedValue method_shift(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
+ static ReturnedValue method_splice(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
+ static ReturnedValue method_unshift(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
+ static ReturnedValue method_indexOf(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
+ static ReturnedValue method_lastIndexOf(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
+ static ReturnedValue method_sort(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
+ static ReturnedValue method_get_length(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
+ static ReturnedValue method_set_length(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
};
}
diff --git a/src/qml/qml/qqmllocale.cpp b/src/qml/qml/qqmllocale.cpp
index 8046a76b92..3249f5a6eb 100644
--- a/src/qml/qml/qqmllocale.cpp
+++ b/src/qml/qml/qqmllocale.cpp
@@ -1,47 +1,11 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qqmllocale_p.h"
-#include "qqmlengine_p.h"
#include <private/qqmlcontext_p.h>
#include <QtCore/qnumeric.h>
#include <QtCore/qdatetime.h>
+#include <QtCore/qtimezone.h>
#include <private/qlocale_p.h>
#include <private/qlocale_data_p.h>
@@ -49,13 +13,12 @@
#include <private/qv4dateobject_p.h>
#include <private/qv4numberobject_p.h>
#include <private/qv4stringobject_p.h>
+#include <private/qqmlvaluetypewrapper_p.h>
QT_BEGIN_NAMESPACE
using namespace QV4;
-DEFINE_OBJECT_VTABLE(QQmlLocaleData);
-
#define THROW_ERROR(string) \
do { \
return scope.engine->throwError(QString::fromUtf8(string)); \
@@ -63,13 +26,18 @@ DEFINE_OBJECT_VTABLE(QQmlLocaleData);
#define GET_LOCALE_DATA_RESOURCE(OBJECT) \
- QV4::Scoped<QQmlLocaleData> r(scope, OBJECT.as<QQmlLocaleData>()); \
+ QLocale *r = [&]() { \
+ QV4::Scoped<QQmlValueTypeWrapper> r(scope, OBJECT.as<QQmlValueTypeWrapper>()); \
+ return r ? r->cast<QLocale>() : nullptr; \
+ }(); \
if (!r) \
THROW_ERROR("Not a valid Locale object")
static bool isLocaleObject(const QV4::Value &val)
{
- return val.as<QQmlLocaleData>();
+ if (const QV4::QQmlValueTypeWrapper *wrapper = val.as<QQmlValueTypeWrapper>())
+ return wrapper->type() == QMetaType::fromType<QLocale>();
+ return false;
}
//--------------
@@ -114,16 +82,16 @@ ReturnedValue QQmlDateExtension::method_toLocaleString(const QV4::FunctionObject
if (argc == 2) {
if (String *s = argv[1].stringValue()) {
QString format = s->toQString();
- formattedDt = r->d()->locale->toString(dt, format);
+ formattedDt = r->toString(dt, format);
} else if (argv[1].isNumber()) {
quint32 intFormat = argv[1].toNumber();
QLocale::FormatType format = QLocale::FormatType(intFormat);
- formattedDt = r->d()->locale->toString(dt, format);
+ formattedDt = r->toString(dt, format);
} else {
THROW_ERROR("Locale: Date.toLocaleString(): Invalid datetime format");
}
} else {
- formattedDt = r->d()->locale->toString(dt, enumFormat);
+ formattedDt = r->toString(dt, enumFormat);
}
RETURN_RESULT(scope.engine->newString(formattedDt));
@@ -158,16 +126,16 @@ ReturnedValue QQmlDateExtension::method_toLocaleTimeString(const QV4::FunctionOb
if (argc == 2) {
if (String *s = argv[1].stringValue()) {
QString format = s->toQString();
- formattedTime = r->d()->locale->toString(time, format);
+ formattedTime = r->toString(time, format);
} else if (argv[1].isNumber()) {
quint32 intFormat = argv[1].toNumber();
QLocale::FormatType format = QLocale::FormatType(intFormat);
- formattedTime = r->d()->locale->toString(time, format);
+ formattedTime = r->toString(time, format);
} else {
THROW_ERROR("Locale: Date.toLocaleTimeString(): Invalid time format");
}
} else {
- formattedTime = r->d()->locale->toString(time, enumFormat);
+ formattedTime = r->toString(time, enumFormat);
}
RETURN_RESULT(scope.engine->newString(formattedTime));
@@ -202,16 +170,16 @@ ReturnedValue QQmlDateExtension::method_toLocaleDateString(const QV4::FunctionOb
if (argc == 2) {
if (String *s = argv[1].stringValue()) {
QString format = s->toQString();
- formattedDate = r->d()->locale->toString(date, format);
+ formattedDate = r->toString(date, format);
} else if (argv[1].isNumber()) {
quint32 intFormat = argv[1].toNumber();
QLocale::FormatType format = QLocale::FormatType(intFormat);
- formattedDate = r->d()->locale->toString(date, format);
+ formattedDate = r->toString(date, format);
} else {
THROW_ERROR("Locale: Date.loLocaleDateString(): Invalid date format");
}
} else {
- formattedDate = r->d()->locale->toString(date, enumFormat);
+ formattedDate = r->toString(date, enumFormat);
}
RETURN_RESULT(scope.engine->newString(formattedDate));
@@ -241,16 +209,16 @@ ReturnedValue QQmlDateExtension::method_fromLocaleString(const QV4::FunctionObje
if (argc == 3) {
if (String *s = argv[2].stringValue()) {
QString format = s->toQString();
- dt = r->d()->locale->toDateTime(dateString, format);
+ dt = r->toDateTime(dateString, format);
} else if (argv[2].isNumber()) {
quint32 intFormat = argv[2].toNumber();
QLocale::FormatType format = QLocale::FormatType(intFormat);
- dt = r->d()->locale->toDateTime(dateString, format);
+ dt = r->toDateTime(dateString, format);
} else {
THROW_ERROR("Locale: Date.fromLocaleString(): Invalid datetime format");
}
} else {
- dt = r->d()->locale->toDateTime(dateString, enumFormat);
+ dt = r->toDateTime(dateString, enumFormat);
}
RETURN_RESULT(engine->newDateObject(dt));
@@ -283,16 +251,16 @@ ReturnedValue QQmlDateExtension::method_fromLocaleTimeString(const QV4::Function
if (argc == 3) {
if (String *s = argv[2].stringValue()) {
QString format = s->toQString();
- tm = r->d()->locale->toTime(dateString, format);
+ tm = r->toTime(dateString, format);
} else if (argv[2].isNumber()) {
quint32 intFormat = argv[2].toNumber();
QLocale::FormatType format = QLocale::FormatType(intFormat);
- tm = r->d()->locale->toTime(dateString, format);
+ tm = r->toTime(dateString, format);
} else {
THROW_ERROR("Locale: Date.fromLocaleTimeString(): Invalid datetime format");
}
} else {
- tm = r->d()->locale->toTime(dateString, enumFormat);
+ tm = r->toTime(dateString, enumFormat);
}
QDateTime dt;
@@ -314,7 +282,7 @@ ReturnedValue QQmlDateExtension::method_fromLocaleDateString(const QV4::Function
QLocale locale;
QString dateString = s->toQString();
QDate date = locale.toDate(dateString);
- RETURN_RESULT(engine->newDateObject(date.startOfDay()));
+ RETURN_RESULT(engine->newDateObject(date.startOfDay(QTimeZone::UTC)));
}
}
@@ -329,19 +297,19 @@ ReturnedValue QQmlDateExtension::method_fromLocaleDateString(const QV4::Function
if (argc == 3) {
if (String *s = argv[2].stringValue()) {
QString format = s->toQString();
- dt = r->d()->locale->toDate(dateString, format);
+ dt = r->toDate(dateString, format);
} else if (argv[2].isNumber()) {
quint32 intFormat = argv[2].toNumber();
QLocale::FormatType format = QLocale::FormatType(intFormat);
- dt = r->d()->locale->toDate(dateString, format);
+ dt = r->toDate(dateString, format);
} else {
THROW_ERROR("Locale: Date.fromLocaleDateString(): Invalid datetime format");
}
} else {
- dt = r->d()->locale->toDate(dateString, enumFormat);
+ dt = r->toDate(dateString, enumFormat);
}
- RETURN_RESULT(engine->newDateObject(dt.startOfDay()));
+ RETURN_RESULT(engine->newDateObject(dt.startOfDay(QTimeZone::UTC)));
}
ReturnedValue QQmlDateExtension::method_timeZoneUpdated(const QV4::FunctionObject *b, const QV4::Value *, const QV4::Value *, int argc)
@@ -389,7 +357,7 @@ QV4::ReturnedValue QQmlNumberExtension::method_toLocaleString(const QV4::Functio
if (!argv[1].isString())
THROW_ERROR("Locale: Number.toLocaleString(): Invalid arguments");
QString fs = argv[1].toQString();
- if (fs.length())
+ if (fs.size())
format = fs.at(0).unicode();
}
int prec = 2;
@@ -399,7 +367,7 @@ QV4::ReturnedValue QQmlNumberExtension::method_toLocaleString(const QV4::Functio
prec = argv[2].toInt32();
}
- RETURN_RESULT(scope.engine->newString(r->d()->locale->toString(number, (char)format, prec)));
+ RETURN_RESULT(scope.engine->newString(r->toString(number, (char)format, prec)));
}
ReturnedValue QQmlNumberExtension::method_toLocaleCurrencyString(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc)
@@ -428,7 +396,7 @@ ReturnedValue QQmlNumberExtension::method_toLocaleCurrencyString(const QV4::Func
symbol = argv[1].toQStringNoThrow();
}
- RETURN_RESULT(scope.engine->newString(r->d()->locale->toCurrencyString(number, symbol)));
+ RETURN_RESULT(scope.engine->newString(r->toCurrencyString(number, symbol)));
}
ReturnedValue QQmlNumberExtension::method_fromLocaleString(const QV4::FunctionObject *b, const QV4::Value *, const QV4::Value *argv, int argc)
@@ -445,13 +413,13 @@ ReturnedValue QQmlNumberExtension::method_fromLocaleString(const QV4::FunctionOb
THROW_ERROR("Locale: Number.fromLocaleString(): Invalid arguments");
GET_LOCALE_DATA_RESOURCE(argv[0]);
- locale = *r->d()->locale;
+ locale = *r;
numberIdx = 1;
}
QString ns = argv[numberIdx].toQString();
- if (!ns.length())
+ if (!ns.size())
RETURN_RESULT(QV4::Encode(Q_QNAN));
bool ok = false;
@@ -466,268 +434,160 @@ ReturnedValue QQmlNumberExtension::method_fromLocaleString(const QV4::FunctionOb
//--------------
// Locale object
-ReturnedValue QQmlLocaleData::method_get_firstDayOfWeek(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *, int)
+void QQmlLocaleValueType::formattedDataSize(QQmlV4FunctionPtr args) const
{
- QV4::Scope scope(b);
- const QLocale *locale = getThisLocale(scope, thisObject);
- if (!locale)
- return Encode::undefined();
- int fdow = int(locale->firstDayOfWeek());
- if (fdow == 7)
- fdow = 0; // Qt::Sunday = 7, but Sunday is 0 in JS Date
- RETURN_RESULT(fdow);
-}
+ QV4::Scope scope(args->v4engine());
+ const auto doThrow = [&](const QString &message) {
+ args->setReturnValue(scope.engine->throwError(message));
+ };
+
+ const int argc = args->length();
+
+ if (argc < 1 || argc > 3) {
+ doThrow(QString::fromLatin1(
+ "Locale: formattedDataSize(): Expected 1-3 arguments, but received %1")
+ .arg(argc));
+ return;
+ }
-ReturnedValue QQmlLocaleData::method_get_numberOptions(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *, int) {
- QV4::Scope scope(b);
- const QLocale *locale = getThisLocale(scope, thisObject);
- if (!locale)
- return Encode::undefined();
- int numberOptions = int(locale->numberOptions());
- RETURN_RESULT(numberOptions);
-}
+ QV4::ScopedValue arg0(scope, (*args)[0]);
+ bool mismatched0 = false;
+ if (!arg0->isNumber()) {
+ // ### Qt7: Throw an exception here, so that we don't have to handle mismatched0 below.
+ qWarning() << "Locale: formattedDataSize(): Invalid argument ('bytes' should be a number)";
+ if (argc == 1) {
+ args->setReturnValue(
+ scope.engine->newString(locale.formattedDataSize(qint64(arg0->toInteger())))
+ ->asReturnedValue());
+ return;
+ }
-ReturnedValue QQmlLocaleData::method_set_numberOptions(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc) {
- QV4::Scope scope(b);
- QLocale *locale = getThisLocale(scope, thisObject);
- int const numberOptions = argc ? int(argv[0].toNumber()) : QLocale::DefaultNumberOptions;
- locale->setNumberOptions(QLocale::NumberOptions {numberOptions});
- return Encode::undefined();
-}
+ mismatched0 = true;
+ }
-ReturnedValue QQmlLocaleData::method_get_measurementSystem(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *, int)
-{
- QV4::Scope scope(b);
- const QLocale *locale = getThisLocale(scope, thisObject);
- if (!locale)
- return Encode::undefined();
- return QV4::Encode(locale->measurementSystem());
-}
+ // Anything can be coerced to a number, for better or worse ...
+ Q_ASSERT(argc >= 2);
-ReturnedValue QQmlLocaleData::method_get_textDirection(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *, int)
-{
- QV4::Scope scope(b);
- const QLocale *locale = getThisLocale(scope, thisObject);
- if (!locale)
- return Encode::undefined();
+ QV4::ScopedValue arg1(scope, (*args)[1]);
+ if (!arg1->isInteger()) {
+ doThrow(QLatin1String(
+ "Locale: formattedDataSize(): Invalid argument ('precision' must be an int)"));
+ return;
+ }
- return QV4::Encode(locale->textDirection());
-}
+ if (mismatched0) {
+ if (argc == 2) {
+ const QString result = locale.formattedDataSize(
+ qint64(arg0->toInteger()), arg1->integerValue());
+ args->setReturnValue(scope.engine->newString(result)->asReturnedValue());
+ return;
+ }
-ReturnedValue QQmlLocaleData::method_get_weekDays(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *, int)
-{
- QV4::Scope scope(b);
- const QLocale *locale = getThisLocale(scope, thisObject);
- if (!locale)
- return Encode::undefined();
-
- QList<Qt::DayOfWeek> days = locale->weekdays();
-
- QV4::ScopedArrayObject result(scope, scope.engine->newArrayObject());
- result->arrayReserve(days.size());
- for (int i = 0; i < days.size(); ++i) {
- int day = days.at(i);
- if (day == 7) // JS Date days in range 0(Sunday) to 6(Saturday)
- day = 0;
- result->arrayPut(i, QV4::Value::fromInt32(day));
+ QV4::ScopedValue arg2(scope, (*args)[2]);
+ if (arg2->isNumber()) {
+ const QString result = locale.formattedDataSize(
+ qint64(arg0->toInteger()), arg1->integerValue(),
+ QLocale::DataSizeFormats(arg2->integerValue()));
+ args->setReturnValue(scope.engine->newString(result)->asReturnedValue());
+ return;
+ }
}
- result->setArrayLengthUnchecked(days.size());
- return result.asReturnedValue();
+ Q_ASSERT(argc == 3);
+ Q_ASSERT(!QV4::ScopedValue(scope, (*args)[2])->isNumber());
+
+ doThrow(QLatin1String(
+ "Locale: formattedDataSize(): Invalid argument ('format' must be DataSizeFormat)"));
}
-ReturnedValue QQmlLocaleData::method_get_uiLanguages(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *, int)
+static QQmlLocale::DayOfWeek qtDayToQmlDay(Qt::DayOfWeek day)
{
- QV4::Scope scope(b);
- const QLocale *locale = getThisLocale(scope, thisObject);
- if (!locale)
- return Encode::undefined();
-
- QStringList langs = locale->uiLanguages();
- QV4::ScopedArrayObject result(scope, scope.engine->newArrayObject());
- result->arrayReserve(langs.size());
- QV4::ScopedValue v(scope);
- for (int i = 0; i < langs.size(); ++i)
- result->arrayPut(i, (v = scope.engine->newString(langs.at(i))));
+ return day == Qt::Sunday ? QQmlLocale::DayOfWeek::Sunday : QQmlLocale::DayOfWeek(day);
+}
- result->setArrayLengthUnchecked(langs.size());
+QQmlLocale::DayOfWeek QQmlLocaleValueType::firstDayOfWeek() const
+{
+ return qtDayToQmlDay(locale.firstDayOfWeek());
+}
- return result.asReturnedValue();
+QList<QQmlLocale::DayOfWeek> QQmlLocaleValueType::weekDays() const
+{
+ const QList<Qt::DayOfWeek> days = locale.weekdays();
+ QList<QQmlLocale::DayOfWeek> result;
+ result.reserve(days.size());
+ for (Qt::DayOfWeek day : days)
+ result.append(qtDayToQmlDay(day));
+ return result;
}
-ReturnedValue QQmlLocaleData::method_currencySymbol(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc)
+void QQmlLocaleValueType::toString(QQmlV4FunctionPtr args) const
{
- QV4::Scope scope(b);
- const QLocale *locale = getThisLocale(scope, thisObject);
- if (!locale)
- return Encode::undefined();
+ Scope scope(args->v4engine());
+ const auto doThrow = [&](const QString &message) {
+ args->setReturnValue(scope.engine->throwError(message));
+ };
- if (argc > 1)
- THROW_ERROR("Locale: currencySymbol(): Invalid arguments");
+ const int argc = args->length();
- QLocale::CurrencySymbolFormat format = QLocale::CurrencySymbol;
- if (argc == 1) {
- quint32 intFormat = argv[0].toNumber();
- format = QLocale::CurrencySymbolFormat(intFormat);
+ // toString()
+ Q_ASSERT(argc > 0);
+
+ if (argc > 3) {
+ doThrow(QString::fromLatin1("Locale: toString(): Expected 1-3 arguments, but received %1")
+ .arg(argc));
+ return;
}
- RETURN_RESULT(scope.engine->newString(locale->currencySymbol(format)));
-}
+ QV4::ScopedValue arg0(scope, (*args)[0]);
+ if (arg0->isNumber()) {
-#define LOCALE_FORMAT(FUNC) \
-ReturnedValue QQmlLocaleData::method_ ##FUNC (const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc) { \
- QV4::Scope scope(b); \
- const QLocale *locale = getThisLocale(scope, thisObject); \
- if (!locale) \
- return Encode::undefined(); \
- if (argc > 1) \
- THROW_ERROR("Locale: " #FUNC "(): Invalid arguments"); \
- QLocale::FormatType format = QLocale::LongFormat;\
- if (argc == 1) { \
- quint32 intFormat = argv[0].toUInt32(); \
- format = QLocale::FormatType(intFormat); \
- } \
- RETURN_RESULT(scope.engine->newString(locale-> FUNC (format))); \
-}
+ // toString(int)
+ // toString(double)
+ Q_ASSERT(argc != 1);
-LOCALE_FORMAT(dateTimeFormat)
-LOCALE_FORMAT(timeFormat)
-LOCALE_FORMAT(dateFormat)
-
-// +1 added to idx because JS is 0-based, whereas QLocale months begin at 1.
-#define LOCALE_FORMATTED_MONTHNAME(VARIABLE) \
-ReturnedValue QQmlLocaleData::method_ ## VARIABLE (const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc) {\
- Scope scope(b); \
- const QLocale *locale = getThisLocale(scope, thisObject); \
- if (!locale) \
- return Encode::undefined(); \
- if (argc < 1 || argc > 2) \
- THROW_ERROR("Locale: " #VARIABLE "(): Invalid arguments"); \
- QLocale::FormatType enumFormat = QLocale::LongFormat; \
- int idx = argv[0].toInt32() + 1; \
- if (idx < 1 || idx > 12) \
- THROW_ERROR("Locale: Invalid month"); \
- QString name; \
- if (argc == 2) { \
- if (argv[1].isNumber()) { \
- quint32 intFormat = argv[1].toUInt32(); \
- QLocale::FormatType format = QLocale::FormatType(intFormat); \
- name = locale-> VARIABLE(idx, format); \
- } else { \
- THROW_ERROR("Locale: Invalid datetime format"); \
- } \
- } else { \
- name = locale-> VARIABLE(idx, enumFormat); \
- } \
- RETURN_RESULT(scope.engine->newString(name)); \
-}
+ QV4::ScopedValue arg1(scope, (*args)[1]);
+ if (!arg1->isString()) {
+ doThrow(QLatin1String("Locale: the second argument to the toString overload "
+ "whose first argument is a double should be a char"));
+ return;
+ }
-// 0 -> 7 as Qt::Sunday is 7, but Sunday is 0 in JS Date
-#define LOCALE_FORMATTED_DAYNAME(VARIABLE) \
-ReturnedValue QQmlLocaleData::method_ ## VARIABLE (const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc) {\
- Scope scope(b); \
- const QLocale *locale = getThisLocale(scope, thisObject); \
- if (!locale) \
- return Encode::undefined(); \
- if (argc < 1 || argc > 2) \
- THROW_ERROR("Locale: " #VARIABLE "(): Invalid arguments"); \
- QLocale::FormatType enumFormat = QLocale::LongFormat; \
- int idx = argv[0].toInt32(); \
- if (idx < 0 || idx > 7) \
- THROW_ERROR("Locale: Invalid day"); \
- if (idx == 0) idx = 7; \
- QString name; \
- if (argc == 2) { \
- if (argv[1].isNumber()) { \
- quint32 intFormat = argv[1].toUInt32(); \
- QLocale::FormatType format = QLocale::FormatType(intFormat); \
- name = locale-> VARIABLE(idx, format); \
- } else { \
- THROW_ERROR("Locale: Invalid datetime format"); \
- } \
- } else { \
- name = locale-> VARIABLE(idx, enumFormat); \
- } \
- RETURN_RESULT(scope.engine->newString(name)); \
-}
+ // toString(double, const QString &)
+ // toString(double, const QString &, int)
+ Q_ASSERT(argc == 3);
+ Q_ASSERT(!QV4::ScopedValue(scope, (*args)[2])->isInteger());
-LOCALE_FORMATTED_MONTHNAME(monthName)
-LOCALE_FORMATTED_MONTHNAME(standaloneMonthName)
-LOCALE_FORMATTED_DAYNAME(dayName)
-LOCALE_FORMATTED_DAYNAME(standaloneDayName)
-
-#define LOCALE_STRING_PROPERTY(VARIABLE) \
-ReturnedValue QQmlLocaleData::method_get_ ## VARIABLE (const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *, int) \
-{ \
- Scope scope(b); \
- const QLocale *locale = getThisLocale(scope, thisObject); \
- if (!locale) \
- return Encode::undefined(); \
- RETURN_RESULT(scope.engine->newString(locale-> VARIABLE()));\
-}
+ doThrow(QLatin1String("Locale: the third argument to the toString overload "
+ "whose first argument is a double should be an int"));
+ return;
+ }
-LOCALE_STRING_PROPERTY(name)
-LOCALE_STRING_PROPERTY(nativeLanguageName)
-LOCALE_STRING_PROPERTY(nativeCountryName)
-LOCALE_STRING_PROPERTY(decimalPoint)
-LOCALE_STRING_PROPERTY(groupSeparator)
-LOCALE_STRING_PROPERTY(percent)
-LOCALE_STRING_PROPERTY(zeroDigit)
-LOCALE_STRING_PROPERTY(negativeSign)
-LOCALE_STRING_PROPERTY(positiveSign)
-LOCALE_STRING_PROPERTY(exponential)
-LOCALE_STRING_PROPERTY(amText)
-LOCALE_STRING_PROPERTY(pmText)
-
-class QV4LocaleDataDeletable : public QV4::ExecutionEngine::Deletable
-{
-public:
- QV4LocaleDataDeletable(QV4::ExecutionEngine *engine);
- ~QV4LocaleDataDeletable();
+ if (arg0->as<DateObject>()) {
+ if (argc > 2) {
+ doThrow(QString::fromLatin1(
+ "Locale: the toString() overload that takes a Date as its first "
+ "argument expects 1 or 2 arguments, but received %1").arg(argc));
+ return;
+ }
- QV4::PersistentValue prototype;
-};
+ // toString(QDateTime)
+ Q_ASSERT(argc == 2);
+ QV4::ScopedValue arg1(scope, (*args)[1]);
-QV4LocaleDataDeletable::QV4LocaleDataDeletable(QV4::ExecutionEngine *engine)
-{
- QV4::Scope scope(engine);
- QV4::Scoped<QV4::Object> o(scope, engine->newObject());
-
- o->defineDefaultProperty(QStringLiteral("dateFormat"), QQmlLocaleData::method_dateFormat, 0);
- o->defineDefaultProperty(QStringLiteral("standaloneDayName"), QQmlLocaleData::method_standaloneDayName, 0);
- o->defineDefaultProperty(QStringLiteral("standaloneMonthName"), QQmlLocaleData::method_standaloneMonthName, 0);
- o->defineDefaultProperty(QStringLiteral("dayName"), QQmlLocaleData::method_dayName, 0);
- o->defineDefaultProperty(QStringLiteral("timeFormat"), QQmlLocaleData::method_timeFormat, 0);
- o->defineDefaultProperty(QStringLiteral("monthName"), QQmlLocaleData::method_monthName, 0);
- o->defineDefaultProperty(QStringLiteral("currencySymbol"), QQmlLocaleData::method_currencySymbol, 0);
- o->defineDefaultProperty(QStringLiteral("dateTimeFormat"), QQmlLocaleData::method_dateTimeFormat, 0);
- o->defineAccessorProperty(QStringLiteral("name"), QQmlLocaleData::method_get_name, nullptr);
- o->defineAccessorProperty(QStringLiteral("positiveSign"), QQmlLocaleData::method_get_positiveSign, nullptr);
- o->defineAccessorProperty(QStringLiteral("uiLanguages"), QQmlLocaleData::method_get_uiLanguages, nullptr);
- o->defineAccessorProperty(QStringLiteral("firstDayOfWeek"), QQmlLocaleData::method_get_firstDayOfWeek, nullptr);
- o->defineAccessorProperty(QStringLiteral("pmText"), QQmlLocaleData::method_get_pmText, nullptr);
- o->defineAccessorProperty(QStringLiteral("percent"), QQmlLocaleData::method_get_percent, nullptr);
- o->defineAccessorProperty(QStringLiteral("textDirection"), QQmlLocaleData::method_get_textDirection, nullptr);
- o->defineAccessorProperty(QStringLiteral("weekDays"), QQmlLocaleData::method_get_weekDays, nullptr);
- o->defineAccessorProperty(QStringLiteral("negativeSign"), QQmlLocaleData::method_get_negativeSign, nullptr);
- o->defineAccessorProperty(QStringLiteral("groupSeparator"), QQmlLocaleData::method_get_groupSeparator, nullptr);
- o->defineAccessorProperty(QStringLiteral("decimalPoint"), QQmlLocaleData::method_get_decimalPoint, nullptr);
- o->defineAccessorProperty(QStringLiteral("nativeLanguageName"), QQmlLocaleData::method_get_nativeLanguageName, nullptr);
- o->defineAccessorProperty(QStringLiteral("nativeCountryName"), QQmlLocaleData::method_get_nativeCountryName, nullptr);
- o->defineAccessorProperty(QStringLiteral("zeroDigit"), QQmlLocaleData::method_get_zeroDigit, nullptr);
- o->defineAccessorProperty(QStringLiteral("amText"), QQmlLocaleData::method_get_amText, nullptr);
- o->defineAccessorProperty(QStringLiteral("measurementSystem"), QQmlLocaleData::method_get_measurementSystem, nullptr);
- o->defineAccessorProperty(QStringLiteral("exponential"), QQmlLocaleData::method_get_exponential, nullptr);
- o->defineAccessorProperty(QStringLiteral("numberOptions"), QQmlLocaleData::method_get_numberOptions, QQmlLocaleData::method_set_numberOptions);
-
- prototype.set(engine, o);
-}
+ // toString(QDateTime, QString)
+ Q_ASSERT(!arg1->isString());
-QV4LocaleDataDeletable::~QV4LocaleDataDeletable()
-{
-}
+ // toString(QDateTime, QLocale::FormatType)
+ Q_ASSERT(!arg1->isNumber());
-V4_DEFINE_EXTENSION(QV4LocaleDataDeletable, localeV4Data);
+ doThrow(QLatin1String("Locale: the second argument to the toString overloads whose "
+ "first argument is a Date should be a string or FormatType"));
+ return;
+ }
+
+ doThrow(QLatin1String("Locale: toString() expects either an int, double, "
+ "or Date as its first argument"));
+}
/*!
\qmltype Locale
@@ -785,19 +645,17 @@ V4_DEFINE_EXTENSION(QV4LocaleDataDeletable, localeV4Data);
can use the following enumeration values to specify the formatting of
the string representation for a Date object.
- \list
- \li Locale.LongFormat The long version of day and month names; for
- example, returning "January" as a month name.
- \li Locale.ShortFormat The short version of day and month names; for
- example, returning "Jan" as a month name.
- \li Locale.NarrowFormat A special version of day and month names for
- use when space is limited; for example, returning "J" as a month
- name. Note that the narrow format might contain the same text for
- different months and days or it can even be an empty string if the
- locale doesn't support narrow names, so you should avoid using it
- for date formatting. Also, for the system locale this format is
- the same as ShortFormat.
- \endlist
+ \value Locale.LongFormat The long version of day and month names; for
+ example, returning "January" as a month name.
+ \value Locale.ShortFormat The short version of day and month names; for
+ example, returning "Jan" as a month name.
+ \value Locale.NarrowFormat A special version of day and month names for
+ use when space is limited; for example, returning "J" as a month
+ name. Note that the narrow format might contain the same text for
+ different months and days or it can even be an empty string if the
+ locale doesn't support narrow names, so you should avoid using it
+ for date formatting. Also, for the system locale this format is
+ the same as ShortFormat.
Additionally the double-to-string and string-to-double conversion functions are
@@ -825,21 +683,16 @@ V4_DEFINE_EXTENSION(QV4LocaleDataDeletable, localeV4Data);
QV4::ReturnedValue QQmlLocale::locale(ExecutionEngine *engine, const QString &localeName)
{
- QLocale qlocale;
- if (!localeName.isEmpty())
- qlocale = QLocale(localeName);
- return wrap(engine, qlocale);
-}
+ if (localeName.isEmpty()) {
+ return QQmlValueTypeWrapper::create(
+ engine, nullptr, &QQmlLocaleValueType::staticMetaObject,
+ QMetaType::fromType<QLocale>());
+ }
-QV4::ReturnedValue QQmlLocale::wrap(ExecutionEngine *v4, const QLocale &locale)
-{
- QV4::Scope scope(v4);
- QV4LocaleDataDeletable *d = localeV4Data(scope.engine);
- QV4::Scoped<QQmlLocaleData> wrapper(scope, v4->memoryManager->allocate<QQmlLocaleData>());
- *wrapper->d()->locale = locale;
- QV4::ScopedObject p(scope, d->prototype.value());
- wrapper->setPrototypeOf(p);
- return wrapper.asReturnedValue();
+ QLocale qlocale(localeName);
+ return QQmlValueTypeWrapper::create(
+ engine, &qlocale, &QQmlLocaleValueType::staticMetaObject,
+ QMetaType::fromType<QLocale>());
}
void QQmlLocale::registerStringLocaleCompare(QV4::ExecutionEngine *engine)
@@ -864,10 +717,10 @@ ReturnedValue QQmlLocale::method_localeCompare(const QV4::FunctionObject *b, con
/*!
\qmlproperty string QtQml::Locale::name
- Holds the language and country of this locale as a
- string of the form "language_country", where
+ Holds the language and territory of this locale as a
+ string of the form "language_territory", where
language is a lowercase, two-letter ISO 639 language code,
- and country is an uppercase, two- or three-letter ISO 3166 country code.
+ and territory is an uppercase, two- or three-letter ISO 3166 territory code.
*/
/*!
@@ -951,6 +804,20 @@ ReturnedValue QQmlLocale::method_localeCompare(const QV4::FunctionObject *b, con
*/
/*!
+ \qmlmethod string QtQml::Locale::formattedDataSize(int bytes, int precision, DataSizeFormat format)
+ \since 6.2
+
+ Converts a size in \a bytes to a human-readable localized string, comprising a
+ number and a quantified unit.
+
+ The \a precision and \a format arguments are optional.
+
+ For more information, see \l QLocale::formattedDataSize().
+
+ \sa QLocale::DataSizeFormats
+*/
+
+/*!
\qmlmethod string QtQml::Locale::monthName(month, type)
Returns the localized name of \a month (0-11), in the optional
@@ -1005,15 +872,13 @@ ReturnedValue QQmlLocale::method_localeCompare(const QV4::FunctionObject *b, con
Holds the first day of the week according to the current locale.
- \list
- \li Locale.Sunday = 0
- \li Locale.Monday = 1
- \li Locale.Tuesday = 2
- \li Locale.Wednesday = 3
- \li Locale.Thursday = 4
- \li Locale.Friday = 5
- \li Locale.Saturday = 6
- \endlist
+ \value Locale.Sunday 0
+ \value Locale.Monday 1
+ \value Locale.Tuesday 2
+ \value Locale.Wednesday 3
+ \value Locale.Thursday 4
+ \value Locale.Friday 5
+ \value Locale.Saturday 6
\note that these values match the JS Date API which is different
from the Qt C++ API where Qt::Sunday = 7.
@@ -1029,6 +894,51 @@ ReturnedValue QQmlLocale::method_localeCompare(const QV4::FunctionObject *b, con
*/
/*!
+ \qmlmethod string QtQml::Locale::toString(int i)
+ \since 6.5
+
+ Returns a localized string representation of \a i.
+
+ \sa QLocale::toString(int)
+*/
+
+/*!
+ \qmlmethod string QtQml::Locale::toString(double f, char format = 'g', int precision = 6)
+ \overload
+ \since 6.5
+
+ Returns a string representing the floating-point number \a f.
+
+ The form of the representation is controlled by the optional \a format and
+ \a precision parameters.
+
+ See \l {QLocale::toString(double, char, int)} for more information.
+*/
+
+/*!
+ \qmlmethod string QtQml::Locale::toString(Date date, string format)
+ \overload
+ \since 6.5
+
+ Returns a localized string representation of the given \a date in the
+ specified \a format. If \c format is an empty string, an empty string is
+ returned.
+
+ \sa QLocale::toString(QDate, QStringView)
+*/
+
+/*!
+ \qmlmethod string QtQml::Locale::toString(Date date, FormatType format = LongFormat)
+ \overload
+ \since 6.5
+
+ Returns a localized string representation of the given \a date in the
+ specified \a format. If \c format is omitted, \c Locale.LongFormat is used.
+
+ \sa QLocale::toString(QDate, QLocale::FormatType)
+*/
+
+/*!
\qmlproperty Array<string> QtQml::Locale::uiLanguages
Returns an ordered list of locale names for translation purposes in
@@ -1044,10 +954,9 @@ ReturnedValue QQmlLocale::method_localeCompare(const QV4::FunctionObject *b, con
\qmlproperty enumeration QtQml::Locale::textDirection
Holds the text direction of the language:
- \list
- \li Qt.LeftToRight
- \li Qt.RightToLeft
- \endlist
+
+ \value Qt.LeftToRight Text normally begins at the left side.
+ \value Qt.RightToLeft Text normally begins at the right side.
*/
/*!
@@ -1066,11 +975,11 @@ ReturnedValue QQmlLocale::method_localeCompare(const QV4::FunctionObject *b, con
\qmlmethod string QtQml::Locale::currencySymbol(format)
Returns the currency symbol for the specified \a format:
- \list
- \li Locale.CurrencyIsoCode a ISO-4217 code of the currency.
- \li Locale.CurrencySymbol a currency symbol.
- \li Locale.CurrencyDisplayName a user readable name of the currency.
- \endlist
+
+ \value Locale.CurrencyIsoCode a ISO-4217 code of the currency.
+ \value Locale.CurrencySymbol a currency symbol.
+ \value Locale.CurrencyDisplayName a user readable name of the currency.
+
\sa Number::toLocaleCurrencyString()
*/
@@ -1080,11 +989,12 @@ ReturnedValue QQmlLocale::method_localeCompare(const QV4::FunctionObject *b, con
Holds a native name of the language for the locale. For example
"Schwiizertüütsch" for Swiss-German locale.
- \sa nativeCountryName
+ \sa nativeTerritoryName
*/
/*!
\qmlproperty string QtQml::Locale::nativeCountryName
+ \deprecated [6.4] Use nativeTerritoryName instead.
Holds a native name of the country for the locale. For example
"España" for Spanish/Spain locale.
@@ -1093,20 +1003,26 @@ ReturnedValue QQmlLocale::method_localeCompare(const QV4::FunctionObject *b, con
*/
/*!
+ \qmlproperty string QtQml::Locale::nativeTerritoryName
+
+ Holds a native name of the territory for the locale. For example
+ "España" for Spanish/Spain locale.
+
+ \sa nativeLanguageName
+*/
+
+/*!
\qmlproperty enumeration QtQml::Locale::measurementSystem
This property defines which units are used for measurement.
- \list
- \li Locale.MetricSystem This value indicates metric units, such as meters,
- centimeters and millimeters.
- \li Locale.ImperialUSSystem This value indicates imperial units, such as
- inches and miles as they are used in the United States.
- \li Locale.ImperialUKSystem This value indicates imperial units, such as
- inches and miles as they are used in the United Kingdom.
- \li Locale.ImperialSystem Provided for compatibility. The same as
- Locale.ImperialUSSystem.
- \endlist
+ \value Locale.MetricSystem This value indicates metric units, such as meters,
+ centimeters and millimeters.
+ \value Locale.ImperialUSSystem This value indicates imperial units, such as
+ inches and miles as they are used in the United States.
+ \value Locale.ImperialUKSystem This value indicates imperial units, such as
+ inches and miles as they are used in the United Kingdom.
+ \value Locale.ImperialSystem Provided for compatibility. The same as Locale.ImperialUSSystem.
*/
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmllocale_p.h b/src/qml/qml/qqmllocale_p.h
index 73eae259fb..5d26bf8a68 100644
--- a/src/qml/qml/qqmllocale_p.h
+++ b/src/qml/qml/qqmllocale_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLLOCALE_H
#define QQMLLOCALE_H
@@ -55,7 +19,7 @@
#include <QtCore/qlocale.h>
#include <QtCore/qobject.h>
-#include <private/qqmlglobal_p.h>
+#include <private/qtqmlglobal_p.h>
#include <private/qv4object_p.h>
QT_REQUIRE_CONFIG(qml_locale);
@@ -93,30 +57,11 @@ private:
namespace QQmlLocale
{
- Q_NAMESPACE
+ Q_NAMESPACE_EXPORT(Q_QML_EXPORT)
QML_NAMED_ELEMENT(Locale)
QML_ADDED_IN_VERSION(2, 2)
+ QML_NAMESPACE_EXTENDED(QLocale)
- enum MeasurementSystem {
- MetricSystem = QLocale::MetricSystem,
- ImperialSystem = QLocale::ImperialSystem,
- ImperialUSSystem = QLocale::ImperialUSSystem,
- ImperialUKSystem = QLocale::ImperialUKSystem
- };
- Q_ENUM_NS(MeasurementSystem)
-
- enum FormatType {
- LongFormat = QLocale::LongFormat,
- ShortFormat = QLocale::ShortFormat,
- NarrowFormat = QLocale::NarrowFormat
- };
- Q_ENUM_NS(FormatType)
- enum CurrencySymbolFormat {
- CurrencyIsoCode = QLocale::CurrencyIsoCode,
- CurrencySymbol = QLocale::CurrencySymbol,
- CurrencyDisplayName = QLocale::CurrencyDisplayName
- };
- Q_ENUM_NS(CurrencySymbolFormat)
// Qt defines Sunday as 7, but JS Date assigns Sunday 0
enum DayOfWeek {
Sunday = 0,
@@ -128,86 +73,173 @@ namespace QQmlLocale
Saturday = Qt::Saturday
};
Q_ENUM_NS(DayOfWeek)
- enum NumberOptions {
- DefaultNumberOptions = QLocale::DefaultNumberOptions,
- OmitGroupSeparator = QLocale::OmitGroupSeparator,
- RejectGroupSeparator = QLocale::RejectGroupSeparator,
- OmitLeadingZeroInExponent = QLocale::OmitLeadingZeroInExponent,
- RejectLeadingZeroInExponent = QLocale::RejectLeadingZeroInExponent,
- IncludeTrailingZeroesAfterDot = QLocale::IncludeTrailingZeroesAfterDot,
- RejectTrailingZeroesAfterDot = QLocale::RejectTrailingZeroesAfterDot
- };
- Q_ENUM_NS(NumberOptions)
- Q_QML_PRIVATE_EXPORT QV4::ReturnedValue locale(QV4::ExecutionEngine *engine, const QString &localeName);
- Q_QML_PRIVATE_EXPORT QV4::ReturnedValue wrap(QV4::ExecutionEngine *engine, const QLocale &locale);
- Q_QML_PRIVATE_EXPORT void registerStringLocaleCompare(QV4::ExecutionEngine *engine);
- Q_QML_PRIVATE_EXPORT QV4::ReturnedValue method_localeCompare(const QV4::FunctionObject *, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
+ Q_QML_EXPORT QV4::ReturnedValue locale(QV4::ExecutionEngine *engine, const QString &localeName);
+ Q_QML_EXPORT void registerStringLocaleCompare(QV4::ExecutionEngine *engine);
+ Q_QML_EXPORT QV4::ReturnedValue method_localeCompare(const QV4::FunctionObject *, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
};
-namespace QV4 {
+struct DayOfWeekList
+{
+ Q_GADGET
+ QML_ANONYMOUS
+ QML_FOREIGN(QList<QQmlLocale::DayOfWeek>)
+ QML_SEQUENTIAL_CONTAINER(QQmlLocale::DayOfWeek)
+};
-namespace Heap {
+class QQmlLocaleValueType
+{
+ QLocale locale;
+
+ Q_PROPERTY(QQmlLocale::DayOfWeek firstDayOfWeek READ firstDayOfWeek CONSTANT)
+ Q_PROPERTY(QLocale::MeasurementSystem measurementSystem READ measurementSystem CONSTANT)
+ Q_PROPERTY(Qt::LayoutDirection textDirection READ textDirection CONSTANT)
+ Q_PROPERTY(QList<QQmlLocale::DayOfWeek> weekDays READ weekDays CONSTANT)
+ Q_PROPERTY(QStringList uiLanguages READ uiLanguages CONSTANT)
+
+ Q_PROPERTY(QString name READ name CONSTANT)
+ Q_PROPERTY(QString nativeLanguageName READ nativeLanguageName CONSTANT)
+#if QT_DEPRECATED_SINCE(6, 6)
+ Q_PROPERTY(QString nativeCountryName READ nativeCountryName CONSTANT)
+#endif
+ Q_PROPERTY(QString nativeTerritoryName READ nativeTerritoryName CONSTANT)
+ Q_PROPERTY(QString decimalPoint READ decimalPoint CONSTANT)
+ Q_PROPERTY(QString groupSeparator READ groupSeparator CONSTANT)
+ Q_PROPERTY(QString percent READ percent CONSTANT)
+ Q_PROPERTY(QString zeroDigit READ zeroDigit CONSTANT)
+ Q_PROPERTY(QString negativeSign READ negativeSign CONSTANT)
+ Q_PROPERTY(QString positiveSign READ positiveSign CONSTANT)
+ Q_PROPERTY(QString exponential READ exponential CONSTANT)
+ Q_PROPERTY(QString amText READ amText CONSTANT)
+ Q_PROPERTY(QString pmText READ pmText CONSTANT)
+
+ Q_PROPERTY(QLocale::NumberOptions numberOptions READ numberOptions WRITE setNumberOptions)
+
+ Q_GADGET
+ QML_ANONYMOUS
+ QML_FOREIGN(QLocale)
+ QML_EXTENDED(QQmlLocaleValueType)
+ QML_CONSTRUCTIBLE_VALUE
-struct QQmlLocaleData : Object {
- inline void init() { locale = new QLocale; }
- void destroy() {
- delete locale;
- Object::destroy();
+public:
+ Q_INVOKABLE QQmlLocaleValueType(const QString &name) : locale(name) {}
+
+ Q_INVOKABLE QString currencySymbol(
+ QLocale::CurrencySymbolFormat format = QLocale::CurrencySymbol) const
+ {
+ return locale.currencySymbol(format);
}
- QLocale *locale;
-};
-}
+ Q_INVOKABLE QString dateTimeFormat(QLocale::FormatType format = QLocale::LongFormat) const
+ {
+ return locale.dateTimeFormat(format);
+ }
-struct QQmlLocaleData : public QV4::Object
-{
- V4_OBJECT2(QQmlLocaleData, Object)
- V4_NEEDS_DESTROY
-
- static QLocale *getThisLocale(QV4::Scope &scope, const QV4::Value *thisObject) {
- const QV4::Object *o = thisObject->as<Object>();
- const QQmlLocaleData *data = o ? o->as<QQmlLocaleData>() : nullptr;
- if (!data) {
- scope.engine->throwTypeError();
- return nullptr;
- }
- return data->d()->locale;
+ Q_INVOKABLE QString timeFormat(QLocale::FormatType format = QLocale::LongFormat) const
+ {
+ return locale.timeFormat(format);
}
- static QV4::ReturnedValue method_currencySymbol(const QV4::FunctionObject *, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
- static QV4::ReturnedValue method_dateTimeFormat(const QV4::FunctionObject *, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
- static QV4::ReturnedValue method_timeFormat(const QV4::FunctionObject *, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
- static QV4::ReturnedValue method_dateFormat(const QV4::FunctionObject *, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
- static QV4::ReturnedValue method_monthName(const QV4::FunctionObject *, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
- static QV4::ReturnedValue method_standaloneMonthName(const QV4::FunctionObject *, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
- static QV4::ReturnedValue method_dayName(const QV4::FunctionObject *, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
- static QV4::ReturnedValue method_standaloneDayName(const QV4::FunctionObject *, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
-
- static QV4::ReturnedValue method_get_firstDayOfWeek(const QV4::FunctionObject *, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
- static QV4::ReturnedValue method_get_measurementSystem(const QV4::FunctionObject *, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
- static QV4::ReturnedValue method_get_textDirection(const QV4::FunctionObject *, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
- static QV4::ReturnedValue method_get_weekDays(const QV4::FunctionObject *, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
- static QV4::ReturnedValue method_get_uiLanguages(const QV4::FunctionObject *, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
-
- static QV4::ReturnedValue method_get_name(const QV4::FunctionObject *, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
- static QV4::ReturnedValue method_get_nativeLanguageName(const QV4::FunctionObject *, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
- static QV4::ReturnedValue method_get_nativeCountryName(const QV4::FunctionObject *, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
- static QV4::ReturnedValue method_get_decimalPoint(const QV4::FunctionObject *, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
- static QV4::ReturnedValue method_get_groupSeparator(const QV4::FunctionObject *, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
- static QV4::ReturnedValue method_get_percent(const QV4::FunctionObject *, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
- static QV4::ReturnedValue method_get_zeroDigit(const QV4::FunctionObject *, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
- static QV4::ReturnedValue method_get_negativeSign(const QV4::FunctionObject *, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
- static QV4::ReturnedValue method_get_positiveSign(const QV4::FunctionObject *, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
- static QV4::ReturnedValue method_get_exponential(const QV4::FunctionObject *, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
- static QV4::ReturnedValue method_get_amText(const QV4::FunctionObject *, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
- static QV4::ReturnedValue method_get_pmText(const QV4::FunctionObject *, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
-
- static QV4::ReturnedValue method_get_numberOptions(const QV4::FunctionObject *, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
- static QV4::ReturnedValue method_set_numberOptions(const QV4::FunctionObject *, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
-};
+ Q_INVOKABLE QString dateFormat(QLocale::FormatType format = QLocale::LongFormat) const
+ {
+ return locale.dateFormat(format);
+ }
+
+ Q_INVOKABLE QString monthName(int index, QLocale::FormatType format = QLocale::LongFormat) const
+ {
+ // +1 added to idx because JS is 0-based, whereas QLocale months begin at 1.
+ return locale.monthName(index + 1, format);
+ }
-}
+ Q_INVOKABLE QString standaloneMonthName(
+ int index, QLocale::FormatType format = QLocale::LongFormat) const
+ {
+ // +1 added to idx because JS is 0-based, whereas QLocale months begin at 1.
+ return locale.standaloneMonthName(index + 1, format);
+ }
+
+ Q_INVOKABLE QString dayName(int index, QLocale::FormatType format = QLocale::LongFormat) const
+ {
+ // 0 -> 7 as Qt::Sunday is 7, but Sunday is 0 in JS Date
+ return locale.dayName(index == 0 ? 7 : index, format);
+ }
+
+ Q_INVOKABLE QString standaloneDayName(
+ int index, QLocale::FormatType format = QLocale::LongFormat) const
+ {
+ // 0 -> 7 as Qt::Sunday is 7, but Sunday is 0 in JS Date
+ return locale.standaloneDayName(index == 0 ? 7 : index, format);
+ }
+
+ Q_INVOKABLE void formattedDataSize(QQmlV4FunctionPtr args) const;
+ Q_INVOKABLE QString formattedDataSize(
+ double bytes, int precision = 2,
+ QLocale::DataSizeFormats format = QLocale::DataSizeIecFormat) const
+ {
+ return locale.formattedDataSize(
+ qint64(QV4::Value::toInteger(bytes)), precision, format);
+ }
+
+ Q_INVOKABLE void toString(QQmlV4FunctionPtr args) const;
+
+ // As a special (undocumented) case, when called with no arguments,
+ // just forward to QDebug. This makes it consistent with other types
+ // in JS that can be converted to a string via toString().
+ Q_INVOKABLE QString toString() const { return QDebug::toString(locale); }
+
+ Q_INVOKABLE QString toString(int i) const { return locale.toString(i); }
+ Q_INVOKABLE QString toString(double f) const
+ {
+ return QJSNumberCoercion::isInteger(f) ? toString(int(f)) : locale.toString(f);
+ }
+ Q_INVOKABLE QString toString(double f, const QString &format, int precision = 6) const
+ {
+ // Lacking a char type, we have to use QString here
+ return format.length() < 1
+ ? QString()
+ : locale.toString(f, format.at(0).toLatin1(), precision);
+ }
+ Q_INVOKABLE QString toString(const QDateTime &dateTime, const QString &format) const
+ {
+ return locale.toString(dateTime, format);
+ }
+ Q_INVOKABLE QString toString(
+ const QDateTime &dateTime, QLocale::FormatType format = QLocale::LongFormat) const
+ {
+ return locale.toString(dateTime, format);
+ }
+
+ QQmlLocale::DayOfWeek firstDayOfWeek() const;
+ QLocale::MeasurementSystem measurementSystem() const { return locale.measurementSystem(); }
+ Qt::LayoutDirection textDirection() const { return locale.textDirection(); }
+ QList<QQmlLocale::DayOfWeek> weekDays() const;
+ QStringList uiLanguages() const { return locale.uiLanguages(); }
+
+ QString name() const { return locale.name(); }
+ QString nativeLanguageName() const { return locale.nativeLanguageName(); }
+#if QT_DEPRECATED_SINCE(6, 6)
+ QString nativeCountryName() const
+ {
+ QT_IGNORE_DEPRECATIONS(return locale.nativeCountryName();)
+ }
+#endif
+ QString nativeTerritoryName() const { return locale.nativeTerritoryName(); }
+ QString decimalPoint() const { return locale.decimalPoint(); }
+ QString groupSeparator() const { return locale.groupSeparator(); }
+ QString percent() const { return locale.percent(); }
+ QString zeroDigit() const { return locale.zeroDigit(); }
+ QString negativeSign() const { return locale.negativeSign(); }
+ QString positiveSign() const { return locale.positiveSign(); }
+ QString exponential() const { return locale.exponential(); }
+ QString amText() const { return locale.amText(); }
+ QString pmText() const { return locale.pmText(); }
+
+ QLocale::NumberOptions numberOptions() const { return locale.numberOptions(); }
+ void setNumberOptions(const QLocale::NumberOptions &numberOptions)
+ {
+ locale.setNumberOptions(numberOptions);
+ }
+};
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlloggingcategory.cpp b/src/qml/qml/qqmlloggingcategory.cpp
index b59a26e17e..8d7fd6c04d 100644
--- a/src/qml/qml/qqmlloggingcategory.cpp
+++ b/src/qml/qml/qqmlloggingcategory.cpp
@@ -1,46 +1,12 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 Pelagicore AG
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 Pelagicore AG
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qqmlloggingcategory_p.h"
#include <QtQml/qqmlinfo.h>
+#include <memory>
+
/*!
\qmltype LoggingCategory
\ingroup qml-utility-elements
@@ -49,11 +15,11 @@
\since 5.8
A logging category can be passed to console.log() and friends as the first argument.
- If supplied to to the logger the LoggingCategory's name will be used as Logging Category
- otherwise the default logging category will be used.
+ If supplied to the logger the LoggingCategory's name will be used as logging category.
+ Otherwise the default logging category will be used.
\qml
- import QtQuick 2.8
+ import QtQuick
Item {
LoggingCategory {
@@ -63,11 +29,18 @@
}
Component.onCompleted: {
- console.log(category, "message");
+ console.log(category, "log message");
+ console.warn(category, "warning message");
}
}
\endqml
+ By default this outputs only \c{com.qt.category: warning message}. The
+ \c{log message} is suppressed due to the \l{defaultLogLevel}. You can,
+ however, configure log levels for QML logging categories the same way
+ you can configure them for
+ \l{QLoggingCategory#configuring-categories}{QLoggingCategory}.
+
\note As the creation of objects is expensive, it is encouraged to put the needed
LoggingCategory definitions into a singleton and import this where needed.
@@ -92,8 +65,21 @@
Holds the default log level of the logging category. By default it is
created with the LoggingCategory.Debug log level.
+ The following enumeration values are available:
+ \list
+ \li LoggingCategory.Debug
+ \li LoggingCategory.Info
+ \li LoggingCategory.Warning
+ \li LoggingCategory.Critical
+ \li LoggingCategory.Fatal
+ \endlist
+
+ They mirror the values of the \l{QtMsgType} enumeration.
+
\note This property needs to be set when declaring the LoggingCategory
and cannot be changed later.
+
+ \sa QtMsgType
*/
QQmlLoggingCategory::QQmlLoggingCategory(QObject *parent)
@@ -118,7 +104,7 @@ QQmlLoggingCategory::DefaultLogLevel QQmlLoggingCategory::defaultLogLevel() cons
QLoggingCategory *QQmlLoggingCategory::category() const
{
- return m_category.data();
+ return m_category.get();
}
void QQmlLoggingCategory::classBegin()
@@ -129,32 +115,39 @@ void QQmlLoggingCategory::componentComplete()
{
m_initialized = true;
if (m_name.isNull()) {
- qmlWarning(this) << QLatin1String("Declaring the name of the LoggingCategory is mandatory and cannot be changed later !");
+ qmlWarning(this) << QLatin1String("Declaring the name of a LoggingCategory is mandatory and cannot be changed later");
} else {
- QScopedPointer<QLoggingCategory> category(new QLoggingCategory(m_name.constData(), QtMsgType(m_defaultLogLevel)));
+ auto category = std::make_unique<QLoggingCategory>(m_name.constData(), QtMsgType(m_defaultLogLevel));
m_category.swap(category);
}
}
void QQmlLoggingCategory::setDefaultLogLevel(DefaultLogLevel defaultLogLevel)
{
+ if (m_defaultLogLevel == defaultLogLevel)
+ return;
+
if (m_initialized) {
- qmlWarning(this) << QLatin1String("The defaultLogLevel of a LoggingCategory cannot be changed after the Item is created");
+ qmlWarning(this) << QLatin1String("The defaultLogLevel of a LoggingCategory cannot be changed after the component is completed");
return;
}
m_defaultLogLevel = defaultLogLevel;
}
-
void QQmlLoggingCategory::setName(const QString &name)
{
+ const QByteArray newName = name.toUtf8();
+
+ if (m_name == newName)
+ return;
+
if (m_initialized) {
- qmlWarning(this) << QLatin1String("The name of a LoggingCategory cannot be changed after the Item is created");
+ qmlWarning(this) << QLatin1String("The name of a LoggingCategory cannot be changed after the component is completed");
return;
}
- m_name = name.toUtf8();
+ m_name = newName;
}
#include "moc_qqmlloggingcategory_p.cpp"
diff --git a/src/qml/qml/qqmlloggingcategory_p.h b/src/qml/qml/qqmlloggingcategory_p.h
index 9cee029a9b..4a27e7e1d7 100644
--- a/src/qml/qml/qqmlloggingcategory_p.h
+++ b/src/qml/qml/qqmlloggingcategory_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 Pelagicore AG
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 Pelagicore AG
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLLOGGINGCATEGORY_P_H
#define QQMLLOGGINGCATEGORY_P_H
@@ -57,6 +21,9 @@
#include <QtQml/qqmlparserstatus.h>
#include <QtQml/qqml.h>
+#include <QtCore/private/qglobal_p.h>
+
+#include <memory>
QT_BEGIN_NAMESPACE
@@ -95,7 +62,7 @@ public:
private:
QByteArray m_name;
- QScopedPointer<QLoggingCategory> m_category;
+ std::unique_ptr<QLoggingCategory> m_category;
DefaultLogLevel m_defaultLogLevel = Debug;
bool m_initialized;
};
diff --git a/src/qml/qml/qqmlmetamoduleregistration.cpp b/src/qml/qml/qqmlmetamoduleregistration.cpp
new file mode 100644
index 0000000000..8e55b62b3a
--- /dev/null
+++ b/src/qml/qml/qqmlmetamoduleregistration.cpp
@@ -0,0 +1,26 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include <private/qtqmlglobal_p.h>
+#include <qqmlmoduleregistration.h>
+#include <qqml.h>
+
+QT_BEGIN_NAMESPACE
+
+// Provide the type registration for QtQml here, in libQtQml.so.
+// This way we get a completely functional QtQml module and don't have to
+// rely on the plugin to be loaded.
+// In CMakeLists.txt we've specified NO_GENERATE_QMLTYPES to prevent
+// the generation of an extra type registration file.
+Q_QML_EXPORT void qml_register_types_QtQml()
+{
+ // ### Qt7: Handle version 6 like version 2.
+ qmlRegisterModule("QtQml", 2, 0);
+ qmlRegisterModule("QtQml", 2, 254);
+ qmlRegisterModule("QtQml", QT_VERSION_MAJOR, 0);
+ qmlRegisterModule("QtQml", QT_VERSION_MAJOR, QT_VERSION_MINOR);
+}
+
+static const QQmlModuleRegistration registration("QtQml", qml_register_types_QtQml);
+
+QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlmetaobject.cpp b/src/qml/qml/qqmlmetaobject.cpp
index 585920a99f..352db7bd69 100644
--- a/src/qml/qml/qqmlmetaobject.cpp
+++ b/src/qml/qml/qqmlmetaobject.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 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$
-**
-****************************************************************************/
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qqmlmetaobject_p.h"
@@ -44,28 +8,6 @@
QT_BEGIN_NAMESPACE
-// Returns true if \a from is assignable to a property of type \a to
-bool QQmlMetaObject::canConvert(const QQmlMetaObject &from, const QQmlMetaObject &to)
-{
- Q_ASSERT(!from.isNull() && !to.isNull());
-
- auto equal = [] (const QMetaObject *lhs, const QMetaObject *rhs) -> bool {
- return lhs == rhs || (lhs && rhs && lhs->d.stringdata == rhs->d.stringdata);
- };
-
- const QMetaObject *tom = to.metaObject();
- if (tom == &QObject::staticMetaObject) return true;
-
- const QMetaObject *fromm = from.metaObject();
- while (fromm) {
- if (equal(fromm, tom))
- return true;
- fromm = fromm->superClass();
- }
-
- return false;
-}
-
void QQmlMetaObject::resolveGadgetMethodOrPropertyIndex(QMetaObject::Call type, const QMetaObject **metaObject, int *index)
{
int offset;
@@ -106,7 +48,7 @@ QMetaType QQmlMetaObject::methodReturnType(const QQmlPropertyData &data, QByteAr
type = _m->method(data.coreIndex()).returnMetaType();
}
if (type.flags().testFlag(QMetaType::IsEnumeration))
- type = QMetaType::fromType<int>();
+ type = type.underlyingType();
if (type.isValid())
return type;
else if (unknownTypeError)
@@ -114,42 +56,4 @@ QMetaType QQmlMetaObject::methodReturnType(const QQmlPropertyData &data, QByteAr
return QMetaType();
}
-bool QQmlMetaObject::methodParameterTypes(int index, ArgTypeStorage *argStorage,
- QByteArray *unknownTypeError) const
-{
- Q_ASSERT(_m && index >= 0);
-
- QMetaMethod m = _m->method(index);
- return methodParameterTypes(m, argStorage, unknownTypeError);
-}
-
-bool QQmlMetaObject::constructorParameterTypes(int index, ArgTypeStorage *dummy,
- QByteArray *unknownTypeError) const
-{
- QMetaMethod m = _m->constructor(index);
- return methodParameterTypes(m, dummy, unknownTypeError);
-}
-
-bool QQmlMetaObject::methodParameterTypes(const QMetaMethod &m, ArgTypeStorage *argStorage,
- QByteArray *unknownTypeError) const
-{
- Q_ASSERT(argStorage);
-
- int argc = m.parameterCount();
- argStorage->resize(argc);
- for (int ii = 0; ii < argc; ++ii) {
- QMetaType type = m.parameterMetaType(ii);
- // we treat enumerations as int
- if (type.flags().testFlag(QMetaType::IsEnumeration))
- type = QMetaType::fromType<int>();
- if (!type.isValid()) {
- if (unknownTypeError)
- *unknownTypeError = m.parameterTypeName(ii);
- return false;
- }
- argStorage->operator[](ii) = type;
- }
- return true;
-}
-
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlmetaobject_p.h b/src/qml/qml/qqmlmetaobject_p.h
index 0cb440b38c..498c27884e 100644
--- a/src/qml/qml/qqmlmetaobject_p.h
+++ b/src/qml/qml/qqmlmetaobject_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 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$
-**
-****************************************************************************/
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLMETAOBJECT_P_H
#define QQMLMETAOBJECT_P_H
@@ -51,11 +15,9 @@
// We mean it.
//
-#include <QtQml/qtqmlglobal.h>
-
-#include <private/qflagpointer_p.h>
#include <private/qqmlpropertycache_p.h>
+#include <QtQml/qtqmlglobal.h>
#include <QtCore/qvarlengtharray.h>
#include <QtCore/qmetaobject.h>
@@ -72,12 +34,13 @@ class QQmlPropertyData;
class Q_QML_EXPORT QQmlMetaObject
{
public:
- typedef QVarLengthArray<QMetaType, 9> ArgTypeStorage;
+ template<qsizetype Prealloc>
+ using ArgTypeStorage = QVarLengthArray<QMetaType, Prealloc>;
inline QQmlMetaObject() = default;
inline QQmlMetaObject(const QObject *);
inline QQmlMetaObject(const QMetaObject *);
- inline QQmlMetaObject(QQmlPropertyCache *);
+ inline QQmlMetaObject(const QQmlPropertyCache::ConstPtr &);
inline QQmlMetaObject(const QQmlMetaObject &);
inline QQmlMetaObject &operator=(const QQmlMetaObject &);
@@ -90,31 +53,121 @@ public:
inline const QMetaObject *metaObject() const;
QMetaType methodReturnType(const QQmlPropertyData &data, QByteArray *unknownTypeError) const;
+
/*!
\internal
Returns false if one of the types is unknown. Otherwise, fills \a argstorage with the
metatypes of the function.
*/
- bool methodParameterTypes(int index, ArgTypeStorage *argStorage,
- QByteArray *unknownTypeError) const;
+ template<typename ArgTypeStorage>
+ bool methodParameterTypes(
+ int index, ArgTypeStorage *argStorage, QByteArray *unknownTypeError) const
+ {
+ Q_ASSERT(_m && index >= 0);
+
+ QMetaMethod m = _m->method(index);
+ return methodParameterTypes(m, argStorage, unknownTypeError);
+ }
+
/*!
\internal
Returns false if one of the types is unknown. Otherwise, fills \a argstorage with the
metatypes of the function.
*/
- bool constructorParameterTypes(int index, ArgTypeStorage *dummy, QByteArray *unknownTypeError) const;
+ template<typename ArgTypeStorage>
+ bool constructorParameterTypes(
+ int index, ArgTypeStorage *dummy, QByteArray *unknownTypeError) const
+ {
+ QMetaMethod m = _m->constructor(index);
+ return methodParameterTypes(m, dummy, unknownTypeError);
+ }
- static bool canConvert(const QQmlMetaObject &from, const QQmlMetaObject &to);
+ static bool canConvert(const QQmlMetaObject &from, const QQmlMetaObject &to)
+ {
+ Q_ASSERT(!from.isNull() && !to.isNull());
+ return from.metaObject()->inherits(to.metaObject());
+ }
// static_metacall (on Gadgets) doesn't call the base implementation and therefore
// we need a helper to find the correct meta object and property/method index.
- static void resolveGadgetMethodOrPropertyIndex(QMetaObject::Call type, const QMetaObject **metaObject, int *index);
+ static void resolveGadgetMethodOrPropertyIndex(
+ QMetaObject::Call type, const QMetaObject **metaObject, int *index);
+
+ template<typename ArgTypeStorage>
+ static bool methodParameterTypes(
+ const QMetaMethod &method, ArgTypeStorage *argStorage, QByteArray *unknownTypeError)
+ {
+ Q_ASSERT(argStorage);
+
+ const int argc = method.parameterCount();
+ argStorage->resize(argc);
+ for (int ii = 0; ii < argc; ++ii) {
+ if (!parameterType(method, ii, unknownTypeError, [argStorage](int ii, QMetaType &&type) {
+ argStorage->operator[](ii) = std::forward<QMetaType>(type);
+ })) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ template<typename ArgTypeStorage>
+ static bool methodReturnAndParameterTypes(
+ const QMetaMethod &method, ArgTypeStorage *argStorage, QByteArray *unknownTypeError)
+ {
+ Q_ASSERT(argStorage);
+
+ const int argc = method.parameterCount();
+ argStorage->resize(argc + 1);
+
+ QMetaType type = method.returnMetaType();
+ if (type.flags().testFlag(QMetaType::IsEnumeration))
+ type = type.underlyingType();
+
+ if (!type.isValid()) {
+ if (unknownTypeError)
+ *unknownTypeError = "return type";
+ return false;
+ }
+
+ argStorage->operator[](0) = type;
+
+ for (int ii = 0; ii < argc; ++ii) {
+ if (!parameterType(
+ method, ii, unknownTypeError, [argStorage](int ii, QMetaType &&type) {
+ argStorage->operator[](ii + 1) = std::forward<QMetaType>(type);
+ })) {
+ return false;
+ }
+ }
+
+ return true;
+ }
protected:
+ template<typename Store>
+ static bool parameterType(
+ const QMetaMethod &method, int ii, QByteArray *unknownTypeError, const Store &store)
+ {
+ QMetaType type = method.parameterMetaType(ii);
+
+ // we treat enumerations as their underlying type
+ if (type.flags().testFlag(QMetaType::IsEnumeration))
+ type = type.underlyingType();
+
+ if (!type.isValid()) {
+ if (unknownTypeError)
+ *unknownTypeError = method.parameterTypeName(ii);
+ return false;
+ }
+
+ store(ii, std::move(type));
+ return true;
+ }
+
+
const QMetaObject *_m = nullptr;
- bool methodParameterTypes(const QMetaMethod &method, ArgTypeStorage *argStorage,
- QByteArray *unknownTypeError) const;
};
@@ -129,7 +182,7 @@ QQmlMetaObject::QQmlMetaObject(const QMetaObject *m)
{
}
-QQmlMetaObject::QQmlMetaObject(QQmlPropertyCache *m)
+QQmlMetaObject::QQmlMetaObject(const QQmlPropertyCache::ConstPtr &m)
{
if (m)
_m = m->createMetaObject();
diff --git a/src/qml/qml/qqmlmetatype.cpp b/src/qml/qml/qqmlmetatype.cpp
index 71abce89b1..1175bde3db 100644
--- a/src/qml/qml/qqmlmetatype.cpp
+++ b/src/qml/qml/qqmlmetatype.cpp
@@ -1,56 +1,17 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qqmlmetatype_p.h"
+#include <private/qqmlextensionplugin_p.h>
#include <private/qqmlmetatypedata_p.h>
-#include <private/qqmltypemodule_p.h>
+#include <private/qqmlpropertycachecreator_p.h>
#include <private/qqmltype_p_p.h>
#include <private/qqmltypeloader_p.h>
-#include <private/qqmlextensionplugin_p.h>
+#include <private/qqmltypemodule_p.h>
#include <private/qqmlvaluetype_p.h>
#include <private/qv4executablecompilationunit_p.h>
-#if QT_CONFIG(qml_itemmodel)
-#include <private/qqmlmodelindexvaluetype_p.h>
-#endif
-
#include <QtCore/qcoreapplication.h>
#include <QtCore/qmutex.h>
#include <QtCore/qloggingcategory.h>
@@ -60,32 +21,6 @@ Q_LOGGING_CATEGORY(lcTypeRegistration, "qt.qml.typeregistration")
QT_BEGIN_NAMESPACE
-CompositeMetaTypeIds CompositeMetaTypeIds::fromCompositeName(const QByteArray &name)
-{
- auto ids = QQmlMetaType::registerInternalCompositeType(name);
- ids.refCount = new int;
- *ids.refCount = 1;
- return ids;
-}
-
-void CompositeMetaTypeIds::deref()
-{
- Q_ASSERT(refCount);
- --*refCount;
- if (!*refCount) {
- delete refCount;
- QQmlMetaType::unregisterInternalCompositeType(*this);
- refCount = nullptr;
- }
-}
-
-CompositeMetaTypeIds::~CompositeMetaTypeIds()
-{
- if (refCount)
- deref();
-}
-
-
struct LockedData : private QQmlMetaTypeData
{
friend class QQmlMetaTypeDataPtr;
@@ -126,18 +61,19 @@ static QQmlTypePrivate *createQQmlType(QQmlMetaTypeData *data,
const QQmlPrivate::RegisterInterface &type)
{
auto *d = new QQmlTypePrivate(QQmlType::InterfaceType);
- d->iid = type.iid;
+ d->extraData.interfaceTypeData = type.iid;
d->typeId = type.typeId;
d->listId = type.listId;
- d->isSetup.storeRelease(true);
d->module = QString::fromUtf8(type.uri);
d->version = type.version;
data->registerType(d);
return d;
}
-static QQmlTypePrivate *createQQmlType(QQmlMetaTypeData *data, const QString &elementName,
- const QQmlPrivate::RegisterSingletonType &type)
+static QQmlTypePrivate *createQQmlType(
+ QQmlMetaTypeData *data, const QString &elementName,
+ const QQmlPrivate::RegisterSingletonType &type,
+ const QQmlType::SingletonInstanceInfo::ConstPtr &siinfo)
{
auto *d = new QQmlTypePrivate(QQmlType::SingletonType);
data->registerType(d);
@@ -151,14 +87,9 @@ static QQmlTypePrivate *createQQmlType(QQmlMetaTypeData *data, const QString &el
d->revision = type.revision;
}
- d->extraData.sd->singletonInstanceInfo = new QQmlType::SingletonInstanceInfo;
- d->extraData.sd->singletonInstanceInfo->scriptCallback = type.scriptApi;
- d->extraData.sd->singletonInstanceInfo->qobjectCallback = type.qObjectApi;
- d->extraData.sd->singletonInstanceInfo->typeName = QString::fromUtf8(type.typeName);
- d->extraData.sd->singletonInstanceInfo->instanceMetaObject
- = type.qObjectApi ? type.instanceMetaObject : nullptr;
- d->extraData.sd->extFunc = type.extensionObjectCreate;
- d->extraData.sd->extMetaObject = type.extensionMetaObject;
+ d->extraData.singletonTypeData->singletonInstanceInfo = siinfo;
+ d->extraData.singletonTypeData->extFunc = type.extensionObjectCreate;
+ d->extraData.singletonTypeData->extMetaObject = type.extensionMetaObject;
return d;
}
@@ -174,66 +105,107 @@ static QQmlTypePrivate *createQQmlType(QQmlMetaTypeData *data, const QString &el
d->revision = type.revision;
d->typeId = type.typeId;
d->listId = type.listId;
- d->extraData.cd->allocationSize = type.objectSize;
- d->extraData.cd->userdata = type.userdata;
- d->extraData.cd->newFunc = type.create;
- d->extraData.cd->noCreationReason = type.noCreationReason;
- d->extraData.cd->createValueTypeFunc = type.createValueType;
+ d->extraData.cppTypeData->allocationSize = type.objectSize;
+ d->extraData.cppTypeData->userdata = type.userdata;
+ d->extraData.cppTypeData->newFunc = type.create;
+ d->extraData.cppTypeData->noCreationReason = type.noCreationReason;
+ d->extraData.cppTypeData->createValueTypeFunc = type.createValueType;
d->baseMetaObject = type.metaObject;
- d->extraData.cd->attachedPropertiesFunc = type.attachedPropertiesFunction;
- d->extraData.cd->attachedPropertiesType = type.attachedPropertiesMetaObject;
- d->extraData.cd->parserStatusCast = type.parserStatusCast;
- d->extraData.cd->propertyValueSourceCast = type.valueSourceCast;
- d->extraData.cd->propertyValueInterceptorCast = type.valueInterceptorCast;
- d->extraData.cd->extFunc = type.extensionObjectCreate;
- d->extraData.cd->customParser = reinterpret_cast<QQmlCustomParser *>(type.customParser);
- d->extraData.cd->registerEnumClassesUnscoped = true;
+ d->extraData.cppTypeData->attachedPropertiesFunc = type.attachedPropertiesFunction;
+ d->extraData.cppTypeData->attachedPropertiesType = type.attachedPropertiesMetaObject;
+ d->extraData.cppTypeData->parserStatusCast = type.parserStatusCast;
+ d->extraData.cppTypeData->propertyValueSourceCast = type.valueSourceCast;
+ d->extraData.cppTypeData->propertyValueInterceptorCast = type.valueInterceptorCast;
+ d->extraData.cppTypeData->finalizerCast = type.has(QQmlPrivate::RegisterType::FinalizerCast)
+ ? type.finalizerCast
+ : -1;
+ d->extraData.cppTypeData->extFunc = type.extensionObjectCreate;
+ d->extraData.cppTypeData->customParser = reinterpret_cast<QQmlCustomParser *>(type.customParser);
+ d->extraData.cppTypeData->registerEnumClassesUnscoped = true;
+ d->extraData.cppTypeData->registerEnumsFromRelatedTypes = true;
+ d->extraData.cppTypeData->constructValueType = type.has(QQmlPrivate::RegisterType::CreationMethod)
+ && type.creationMethod != QQmlPrivate::ValueTypeCreationMethod::None;
+ d->extraData.cppTypeData->populateValueType = type.has(QQmlPrivate::RegisterType::CreationMethod)
+ && type.creationMethod == QQmlPrivate::ValueTypeCreationMethod::Structured;
if (type.extensionMetaObject)
- d->extraData.cd->extMetaObject = type.extensionMetaObject;
+ d->extraData.cppTypeData->extMetaObject = type.extensionMetaObject;
// Check if the user wants only scoped enum classes
if (d->baseMetaObject) {
- auto indexOfClassInfo = d->baseMetaObject->indexOfClassInfo("RegisterEnumClassesUnscoped");
- if (indexOfClassInfo != -1 && QString::fromUtf8(d->baseMetaObject->classInfo(indexOfClassInfo).value()) == QLatin1String("false"))
- d->extraData.cd->registerEnumClassesUnscoped = false;
+ auto indexOfUnscoped = d->baseMetaObject->indexOfClassInfo("RegisterEnumClassesUnscoped");
+ if (indexOfUnscoped != -1
+ && qstrcmp(d->baseMetaObject->classInfo(indexOfUnscoped).value(), "false") == 0) {
+ d->extraData.cppTypeData->registerEnumClassesUnscoped = false;
+ }
+
+ auto indexOfRelated = d->baseMetaObject->indexOfClassInfo("RegisterEnumsFromRelatedTypes");
+ if (indexOfRelated != -1
+ && qstrcmp(d->baseMetaObject->classInfo(indexOfRelated).value(), "false") == 0) {
+ d->extraData.cppTypeData->registerEnumsFromRelatedTypes = false;
+ }
}
return d;
}
+static void addQQmlMetaTypeInterfaces(QQmlTypePrivate *priv, const QByteArray &className)
+{
+ Q_ASSERT(!className.isEmpty());
+ QByteArray ptr = className + '*';
+ QByteArray lst = "QQmlListProperty<" + className + '>';
+
+ QMetaType ptr_type(new QQmlMetaTypeInterface(ptr));
+ QMetaType lst_type(new QQmlListMetaTypeInterface(lst, ptr_type.iface()));
+
+ // Retrieve the IDs once, so that the types are added to QMetaType's custom type registry.
+ ptr_type.id();
+ lst_type.id();
+
+ priv->typeId = ptr_type;
+ priv->listId = lst_type;
+}
+
static QQmlTypePrivate *createQQmlType(QQmlMetaTypeData *data, const QString &elementName,
const QQmlPrivate::RegisterCompositeType &type)
{
+ // This is a procedurally registered composite type. It's evil. It doesn't get any metatypes
+ // because we never want to find it in the compositeTypes. Otherwise we might mix it up with an
+ // actually compiled version of the same type.
+
auto *d = new QQmlTypePrivate(QQmlType::CompositeType);
data->registerType(d);
d->setName(QString::fromUtf8(type.uri), elementName);
d->version = type.version;
-
- d->extraData.fd->url = QQmlTypeLoader::normalize(type.url);
+ d->extraData.compositeTypeData = QQmlTypeLoader::normalize(type.url);
return d;
}
-static QQmlTypePrivate *createQQmlType(QQmlMetaTypeData *data, const QString &elementName,
- const QQmlPrivate::RegisterCompositeSingletonType &type)
+static QQmlTypePrivate *createQQmlType(
+ QQmlMetaTypeData *data, const QString &elementName,
+ const QQmlPrivate::RegisterCompositeSingletonType &type,
+ const QQmlType::SingletonInstanceInfo::ConstPtr &siinfo)
{
+ // This is a procedurally registered composite singleton. It's evil. It doesn't get any
+ // metatypes because we never want to find it in the compositeTypes. Otherwise we might mix it
+ // up with an actually compiled version of the same type.
+
auto *d = new QQmlTypePrivate(QQmlType::CompositeSingletonType);
data->registerType(d);
d->setName(QString::fromUtf8(type.uri), elementName);
d->version = type.version;
- d->extraData.sd->singletonInstanceInfo = new QQmlType::SingletonInstanceInfo;
- d->extraData.sd->singletonInstanceInfo->url = QQmlTypeLoader::normalize(type.url);
- d->extraData.sd->singletonInstanceInfo->typeName = QString::fromUtf8(type.typeName);
+ d->extraData.singletonTypeData->singletonInstanceInfo = siinfo;
return d;
}
void QQmlMetaType::clone(QMetaObjectBuilder &builder, const QMetaObject *mo,
- const QMetaObject *ignoreStart, const QMetaObject *ignoreEnd)
+ const QMetaObject *ignoreStart, const QMetaObject *ignoreEnd,
+ QQmlMetaType::ClonePolicy policy)
{
// Set classname
- builder.setClassName(ignoreEnd->className());
+ builder.setClassName(mo->className());
// Clone Q_CLASSINFO
for (int ii = mo->classInfoOffset(); ii < mo->classInfoCount(); ++ii) {
@@ -247,44 +219,45 @@ void QQmlMetaType::clone(QMetaObjectBuilder &builder, const QMetaObject *mo,
}
}
- // Clone Q_PROPERTY
- for (int ii = mo->propertyOffset(); ii < mo->propertyCount(); ++ii) {
- QMetaProperty property = mo->property(ii);
+ if (policy != QQmlMetaType::CloneEnumsOnly) {
+ // Clone Q_METHODS - do this first to avoid duplicating the notify signals.
+ for (int ii = mo->methodOffset(); ii < mo->methodCount(); ++ii) {
+ QMetaMethod method = mo->method(ii);
- int otherIndex = ignoreEnd->indexOfProperty(property.name());
- if (otherIndex >= ignoreStart->propertyOffset() + ignoreStart->propertyCount()) {
- builder.addProperty(QByteArray("__qml_ignore__") + property.name(), QByteArray("void"));
- // Skip
- } else {
- builder.addProperty(property);
- }
- }
+ // More complex - need to search name
+ QByteArray name = method.name();
- // Clone Q_METHODS
- for (int ii = mo->methodOffset(); ii < mo->methodCount(); ++ii) {
- QMetaMethod method = mo->method(ii);
+ bool found = false;
- // More complex - need to search name
- QByteArray name = method.name();
+ for (int ii = ignoreStart->methodOffset() + ignoreStart->methodCount();
+ !found && ii < ignoreEnd->methodOffset() + ignoreEnd->methodCount(); ++ii) {
+ QMetaMethod other = ignoreEnd->method(ii);
- bool found = false;
+ found = name == other.name();
+ }
- for (int ii = ignoreStart->methodOffset() + ignoreStart->methodCount();
- !found && ii < ignoreEnd->methodOffset() + ignoreEnd->methodCount();
- ++ii) {
+ QMetaMethodBuilder m = builder.addMethod(method);
+ if (found) // SKIP
+ m.setAccess(QMetaMethod::Private);
+ }
- QMetaMethod other = ignoreEnd->method(ii);
+ // Clone Q_PROPERTY
+ for (int ii = mo->propertyOffset(); ii < mo->propertyCount(); ++ii) {
+ QMetaProperty property = mo->property(ii);
- found = name == other.name();
+ int otherIndex = ignoreEnd->indexOfProperty(property.name());
+ if (otherIndex >= ignoreStart->propertyOffset() + ignoreStart->propertyCount()) {
+ builder.addProperty(QByteArray("__qml_ignore__") + property.name(),
+ QByteArray("void"));
+ // Skip
+ } else {
+ builder.addProperty(property);
+ }
}
-
- QMetaMethodBuilder m = builder.addMethod(method);
- if (found) // SKIP
- m.setAccess(QMetaMethod::Private);
}
- // Clone Q_ENUMS
+ // Clone enums registered with the metatype system
for (int ii = mo->enumeratorOffset(); ii < mo->enumeratorCount(); ++ii) {
QMetaEnum enumerator = mo->enumerator(ii);
@@ -325,17 +298,6 @@ bool QQmlMetaType::qmlRegisterModuleTypes(const QString &uri)
return data->registerModuleTypes(uri);
}
-/*!
- \internal
- Method is only used to in tst_qqmlenginecleanup.cpp to test whether all
- types have been removed from qmlLists after shutdown of QQmlEngine
- */
-int QQmlMetaType::qmlRegisteredListTypeCount()
-{
- QQmlMetaTypeDataPtr data;
- return data->qmlLists.count();
-}
-
void QQmlMetaType::clearTypeRegistrations()
{
//Only cleans global static, assumed no running engine
@@ -350,18 +312,32 @@ void QQmlMetaType::clearTypeRegistrations()
data->urlToNonFileImportType.clear();
data->metaObjectToType.clear();
data->undeletableTypes.clear();
+ data->propertyCaches.clear();
+ data->inlineComponentTypes.clear();
+
+ // Avoid deletion recursion (via QQmlTypePrivate dtor) by moving them out of the way first.
+ QQmlMetaTypeData::CompositeTypes emptyComposites;
+ emptyComposites.swap(data->compositeTypes);
+}
+
+void QQmlMetaType::registerTypeAlias(int typeIndex, const QString &name)
+{
+ QQmlMetaTypeDataPtr data;
+ const QQmlType type = data->types.value(typeIndex);
+ const QQmlTypePrivate *priv = type.priv();
+ data->nameToType.insert(name, priv);
}
int QQmlMetaType::registerAutoParentFunction(const QQmlPrivate::RegisterAutoParent &function)
{
- if (function.structVersion > 0)
+ if (function.structVersion > 1)
qFatal("qmlRegisterType(): Cannot mix incompatible QML versions.");
QQmlMetaTypeDataPtr data;
data->parentFunctions.append(function.function);
- return data->parentFunctions.count() - 1;
+ return data->parentFunctions.size() - 1;
}
void QQmlMetaType::unregisterAutoParentFunction(const QQmlPrivate::AutoParentFunction &function)
@@ -372,7 +348,7 @@ void QQmlMetaType::unregisterAutoParentFunction(const QQmlPrivate::AutoParentFun
QQmlType QQmlMetaType::registerInterface(const QQmlPrivate::RegisterInterface &type)
{
- if (type.structVersion > 0)
+ if (type.structVersion > 1)
qFatal("qmlRegisterType(): Cannot mix incompatible QML versions.");
QQmlMetaTypeDataPtr data;
@@ -388,7 +364,7 @@ QQmlType QQmlMetaType::registerInterface(const QQmlPrivate::RegisterInterface &t
return QQmlType(priv);
}
-QString registrationTypeString(QQmlType::RegistrationType typeType)
+static QString registrationTypeString(QQmlType::RegistrationType typeType)
{
QString typeStr;
if (typeType == QQmlType::CppType)
@@ -405,14 +381,14 @@ QString registrationTypeString(QQmlType::RegistrationType typeType)
}
// NOTE: caller must hold a QMutexLocker on "data"
-bool checkRegistration(QQmlType::RegistrationType typeType, QQmlMetaTypeData *data,
- const char *uri, const QString &typeName, QTypeRevision version,
- QMetaType::TypeFlags flags)
+static bool checkRegistration(
+ QQmlType::RegistrationType typeType, QQmlMetaTypeData *data, const char *uri,
+ const QString &typeName, QTypeRevision version, QMetaType::TypeFlags flags)
{
if (!typeName.isEmpty()) {
if (typeName.at(0).isLower() && (flags & QMetaType::PointerToQObject)) {
QString failure(QCoreApplication::translate("qmlRegisterType", "Invalid QML %1 name \"%2\"; type names must begin with an uppercase letter"));
- data->recordTypeRegFailure(failure.arg(registrationTypeString(typeType)).arg(typeName));
+ data->recordTypeRegFailure(failure.arg(registrationTypeString(typeType), typeName));
return false;
}
@@ -423,17 +399,17 @@ bool checkRegistration(QQmlType::RegistrationType typeType, QQmlMetaTypeData *da
"qmlRegisterType",
"Invalid QML %1 name \"%2\"; "
"value type names should begin with a lowercase letter")
- .arg(registrationTypeString(typeType)).arg(typeName);
+ .arg(registrationTypeString(typeType), typeName);
}
// There can also be types that aren't even gadgets, and there can be types for namespaces.
// We cannot check those, but namespaces should be uppercase.
- int typeNameLen = typeName.length();
+ int typeNameLen = typeName.size();
for (int ii = 0; ii < typeNameLen; ++ii) {
if (!(typeName.at(ii).isLetterOrNumber() || typeName.at(ii) == u'_')) {
QString failure(QCoreApplication::translate("qmlRegisterType", "Invalid QML %1 name \"%2\""));
- data->recordTypeRegFailure(failure.arg(registrationTypeString(typeType)).arg(typeName));
+ data->recordTypeRegFailure(failure.arg(registrationTypeString(typeType), typeName));
return false;
}
}
@@ -442,12 +418,12 @@ bool checkRegistration(QQmlType::RegistrationType typeType, QQmlMetaTypeData *da
if (uri && !typeName.isEmpty()) {
QString nameSpace = QString::fromUtf8(uri);
QQmlTypeModule *qqtm = data->findTypeModule(nameSpace, version);
- if (qqtm && qqtm->isLocked()) {
+ if (qqtm && qqtm->lockLevel() != QQmlTypeModule::LockLevel::Open) {
QString failure(QCoreApplication::translate(
"qmlRegisterType",
"Cannot install %1 '%2' into protected module '%3' version '%4'"));
- data->recordTypeRegFailure(failure.arg(registrationTypeString(typeType))
- .arg(typeName).arg(nameSpace)
+ data->recordTypeRegFailure(failure
+ .arg(registrationTypeString(typeType), typeName, nameSpace)
.arg(version.majorVersion()));
return false;
}
@@ -457,7 +433,8 @@ bool checkRegistration(QQmlType::RegistrationType typeType, QQmlMetaTypeData *da
}
// NOTE: caller must hold a QMutexLocker on "data"
-QQmlTypeModule *getTypeModule(const QHashedString &uri, QTypeRevision version, QQmlMetaTypeData *data)
+static QQmlTypeModule *getTypeModule(
+ const QHashedString &uri, QTypeRevision version, QQmlMetaTypeData *data)
{
if (QQmlTypeModule *module = data->findTypeModule(uri, version))
return module;
@@ -465,7 +442,7 @@ QQmlTypeModule *getTypeModule(const QHashedString &uri, QTypeRevision version, Q
}
// NOTE: caller must hold a QMutexLocker on "data"
-void addTypeToData(QQmlTypePrivate *type, QQmlMetaTypeData *data)
+static void addTypeToData(QQmlTypePrivate *type, QQmlMetaTypeData *data)
{
Q_ASSERT(type);
@@ -475,12 +452,15 @@ void addTypeToData(QQmlTypePrivate *type, QQmlMetaTypeData *data)
if (type->baseMetaObject)
data->metaObjectToType.insert(type->baseMetaObject, type);
- if (type->typeId.isValid()) {
- data->idToType.insert(type->typeId.id(), type);
- }
+ if (type->regType == QQmlType::SequentialContainerType) {
+ if (type->listId.isValid())
+ data->idToType.insert(type->listId.id(), type);
+ } else {
+ if (type->typeId.isValid())
+ data->idToType.insert(type->typeId.id(), type);
- if (type->listId.isValid()) {
- data->idToType.insert(type->listId.id(), type);
+ if (type->listId.flags().testFlag(QMetaType::IsQmlList))
+ data->idToType.insert(type->listId.id(), type);
}
if (!type->module.isEmpty()) {
@@ -494,7 +474,7 @@ void addTypeToData(QQmlTypePrivate *type, QQmlMetaTypeData *data)
QQmlType QQmlMetaType::registerType(const QQmlPrivate::RegisterType &type)
{
- if (type.structVersion > 0)
+ if (type.structVersion > int(QQmlPrivate::RegisterType::CurrentVersion))
qFatal("qmlRegisterType(): Cannot mix incompatible QML versions.");
QQmlMetaTypeDataPtr data;
@@ -511,9 +491,11 @@ QQmlType QQmlMetaType::registerType(const QQmlPrivate::RegisterType &type)
return QQmlType(priv);
}
-QQmlType QQmlMetaType::registerSingletonType(const QQmlPrivate::RegisterSingletonType &type)
+QQmlType QQmlMetaType::registerSingletonType(
+ const QQmlPrivate::RegisterSingletonType &type,
+ const QQmlType::SingletonInstanceInfo::ConstPtr &siinfo)
{
- if (type.structVersion > 0)
+ if (type.structVersion > 1)
qFatal("qmlRegisterType(): Cannot mix incompatible QML versions.");
QQmlMetaTypeDataPtr data;
@@ -524,16 +506,18 @@ QQmlType QQmlMetaType::registerSingletonType(const QQmlPrivate::RegisterSingleto
return QQmlType();
}
- QQmlTypePrivate *priv = createQQmlType(data, typeName, type);
+ QQmlTypePrivate *priv = createQQmlType(data, typeName, type, siinfo);
addTypeToData(priv, data);
return QQmlType(priv);
}
-QQmlType QQmlMetaType::registerCompositeSingletonType(const QQmlPrivate::RegisterCompositeSingletonType &type)
+QQmlType QQmlMetaType::registerCompositeSingletonType(
+ const QQmlPrivate::RegisterCompositeSingletonType &type,
+ const QQmlType::SingletonInstanceInfo::ConstPtr &siinfo)
{
- if (type.structVersion > 0)
+ if (type.structVersion > 1)
qFatal("qmlRegisterType(): Cannot mix incompatible QML versions.");
// Assumes URL is absolute and valid. Checking of user input should happen before the URL enters type.
@@ -548,18 +532,18 @@ QQmlType QQmlMetaType::registerCompositeSingletonType(const QQmlPrivate::Registe
return QQmlType();
}
- QQmlTypePrivate *priv = createQQmlType(data, typeName, type);
+ QQmlTypePrivate *priv = createQQmlType(data, typeName, type, siinfo);
addTypeToData(priv, data);
QQmlMetaTypeData::Files *files = fileImport ? &(data->urlToType) : &(data->urlToNonFileImportType);
- files->insert(QQmlTypeLoader::normalize(type.url), priv);
+ files->insert(siinfo->url, priv);
return QQmlType(priv);
}
QQmlType QQmlMetaType::registerCompositeType(const QQmlPrivate::RegisterCompositeType &type)
{
- if (type.structVersion > 0)
+ if (type.structVersion > 1)
qFatal("qmlRegisterType(): Cannot mix incompatible QML versions.");
// Assumes URL is absolute and valid. Checking of user input should happen before the URL enters type.
@@ -583,78 +567,195 @@ QQmlType QQmlMetaType::registerCompositeType(const QQmlPrivate::RegisterComposit
return QQmlType(priv);
}
+class QQmlMetaTypeRegistrationFailureRecorder
+{
+ Q_DISABLE_COPY_MOVE(QQmlMetaTypeRegistrationFailureRecorder)
+public:
+ QQmlMetaTypeRegistrationFailureRecorder(QQmlMetaTypeData *data, QStringList *failures)
+ : data(data)
+ {
+ data->setTypeRegistrationFailures(failures);
+ }
+ ~QQmlMetaTypeRegistrationFailureRecorder()
+ {
+ data->setTypeRegistrationFailures(nullptr);
+ }
-struct QQmlMetaTypeInterface : QtPrivate::QMetaTypeInterface
-{
- const QByteArray name;
- template <typename T>
- QQmlMetaTypeInterface(const QByteArray &name, T *)
- : QMetaTypeInterface {
- /*.revision=*/ 0,
- /*.alignment=*/ alignof(T),
- /*.size=*/ sizeof(T),
- /*.flags=*/ QtPrivate::QMetaTypeTypeFlags<T>::Flags,
- /*.typeId=*/ 0,
- /*.metaObject=*/ nullptr,//QtPrivate::MetaObjectForType<T>::value(),
- /*.name=*/ name.constData(),
- /*.defaultCtr=*/ [](const QMetaTypeInterface *, void *addr) { new (addr) T(); },
- /*.copyCtr=*/ [](const QMetaTypeInterface *, void *addr, const void *other) {
- new (addr) T(*reinterpret_cast<const T *>(other));
- },
- /*.moveCtr=*/ [](const QMetaTypeInterface *, void *addr, void *other) {
- new (addr) T(std::move(*reinterpret_cast<T *>(other)));
- },
- /*.dtor=*/ [](const QMetaTypeInterface *, void *addr) {
- reinterpret_cast<T *>(addr)->~T();
- },
- /*.equals*/ nullptr,
- /*.lessThan*/ nullptr,
- /*.debugStream=*/ nullptr,
- /*.dataStreamOut=*/ nullptr,
- /*.dataStreamIn=*/ nullptr,
- /*.legacyRegisterOp=*/ nullptr
- }
- , name(name) { }
+ QQmlMetaTypeData *data = nullptr;
};
-CompositeMetaTypeIds QQmlMetaType::registerInternalCompositeType(const QByteArray &className)
+
+static QQmlType createTypeForUrl(
+ QQmlMetaTypeData *data, const QUrl &url, const QHashedStringRef &qualifiedType,
+ QQmlMetaType::CompositeTypeLookupMode mode, QList<QQmlError> *errors, QTypeRevision version)
{
- QByteArray ptr = className + '*';
- QByteArray lst = "QQmlListProperty<" + className + '>';
+ const int dot = qualifiedType.indexOf(QLatin1Char('.'));
+ const QString typeName = dot < 0
+ ? qualifiedType.toString()
+ : QString(qualifiedType.constData() + dot + 1, qualifiedType.length() - dot - 1);
+
+ QStringList failures;
+ QQmlMetaTypeRegistrationFailureRecorder failureRecorder(data, &failures);
+
+ // Register the type. Note that the URI parameters here are empty; for
+ // file type imports, we do not place them in a URI as we don't
+ // necessarily have a good and unique one (picture a library import,
+ // which may be found in multiple plugin locations on disk), but there
+ // are other reasons for this too.
+ //
+ // By not putting them in a URI, we prevent the types from being
+ // registered on a QQmlTypeModule; this is important, as once types are
+ // placed on there, they cannot be easily removed, meaning if the
+ // developer subsequently loads a different import (meaning different
+ // types) with the same URI (using, say, a different plugin path), it is
+ // very undesirable that we continue to associate the types from the
+ // "old" URI with that new module.
+ //
+ // Not having URIs also means that the types cannot be found by name
+ // etc, the only way to look them up is through QQmlImports -- for
+ // better or worse.
+ const QQmlType::RegistrationType registrationType = mode == QQmlMetaType::Singleton
+ ? QQmlType::CompositeSingletonType
+ : QQmlType::CompositeType;
+ if (checkRegistration(registrationType, data, nullptr, typeName, version, {})) {
+
+ // TODO: Ideally we should defer most of this work using some lazy/atomic mechanism
+ // that creates the details on first use. We must not observably modify
+ // QQmlTypePrivate after it has been created since it is supposed to be immutable
+ // and shared across threads.
+
+ auto *priv = new QQmlTypePrivate(registrationType);
+ addQQmlMetaTypeInterfaces(priv, QQmlPropertyCacheCreatorBase::createClassNameTypeByUrl(url));
- QMetaType ptr_type(new QQmlMetaTypeInterface(ptr, (QObject **)nullptr));
- QMetaType lst_type(new QQmlMetaTypeInterface(lst, (QQmlListProperty<QObject> *)nullptr));
+ priv->setName(QString(), typeName);
+ priv->version = version;
+
+ if (mode == QQmlMetaType::Singleton) {
+ QQmlType::SingletonInstanceInfo::Ptr siinfo = QQmlType::SingletonInstanceInfo::create();
+ siinfo->url = url;
+ siinfo->typeName = typeName.toUtf8();
+ priv->extraData.singletonTypeData->singletonInstanceInfo =
+ QQmlType::SingletonInstanceInfo::ConstPtr(
+ siinfo.take(), QQmlType::SingletonInstanceInfo::ConstPtr::Adopt);
+ } else {
+ priv->extraData.compositeTypeData = url;
+ }
+
+ data->registerType(priv);
+ addTypeToData(priv, data);
+ return QQmlType(priv);
+ }
+ // This means that the type couldn't be found by URL, but could not be
+ // registered either, meaning we most likely were passed some kind of bad
+ // data.
+ if (errors) {
+ QQmlError error;
+ error.setDescription(failures.join(u'\n'));
+ errors->prepend(error);
+ } else {
+ qWarning("%s", failures.join(u'\n').toLatin1().constData());
+ }
+ return QQmlType();
+}
+
+QQmlType QQmlMetaType::findCompositeType(
+ const QUrl &url, const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &compilationUnit,
+ CompositeTypeLookupMode mode)
+{
+ const QUrl normalized = QQmlTypeLoader::normalize(url);
QQmlMetaTypeDataPtr data;
- data->qmlLists.insert(lst_type.id(), ptr_type.id());
- return {ptr_type, lst_type};
+ bool urlExists = true;
+ auto found = data->urlToType.constFind(normalized);
+ if (found == data->urlToType.cend()) {
+ found = data->urlToNonFileImportType.constFind(normalized);
+ if (found == data->urlToNonFileImportType.cend())
+ urlExists = false;
+ }
+
+ if (const QtPrivate::QMetaTypeInterface *iface = urlExists
+ ? found.value()->typeId.iface()
+ : nullptr) {
+ if (compilationUnit.isNull())
+ return QQmlType(*found);
+
+ const auto composite = data->compositeTypes.constFind(iface);
+ if (composite == data->compositeTypes.constEnd() || composite.value() == compilationUnit)
+ return QQmlType(*found);
+ }
+
+ const QQmlType type = createTypeForUrl(
+ data, normalized, QHashedStringRef(), mode, nullptr, QTypeRevision());
+
+ if (!urlExists && type.isValid())
+ data->urlToType.insert(normalized, type.priv());
+
+ return type;
}
-void QQmlMetaType::unregisterInternalCompositeType(const CompositeMetaTypeIds &typeIds)
+static QQmlType doRegisterInlineComponentType(QQmlMetaTypeData *data, const QUrl &url)
{
- QMetaType metaType(typeIds.id);
- QMetaType listMetaType(typeIds.listId);
+ QQmlTypePrivate *priv = new QQmlTypePrivate(QQmlType::InlineComponentType);
+ priv->setName(QString(), url.fragment());
+
+ priv->extraData.inlineComponentTypeData = url;
+
+ const QByteArray className
+ = QQmlPropertyCacheCreatorBase::createClassNameForInlineComponent(url, url.fragment());
+
+ addQQmlMetaTypeInterfaces(priv, className);
+ const QQmlType result(priv);
+ priv->release();
+ data->inlineComponentTypes.insert(url, result);
+
+ return result;
+}
+
+QQmlType QQmlMetaType::findInlineComponentType(
+ const QUrl &url, const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &compilationUnit)
+{
QQmlMetaTypeDataPtr data;
- if (QQmlValueType *vt = data->metaTypeToValueType.take(metaType.id()))
- delete vt;
- if (QQmlValueType *vt = data->metaTypeToValueType.take(listMetaType.id()))
- delete vt;
+ // If there is an "unclaimed" inline component type, we can "claim" it now. Otherwise
+ // we have to create a new one.
+ const auto it = data->inlineComponentTypes.constFind(url);
+ if (it != data->inlineComponentTypes.constEnd()) {
+ const auto jt = data->compositeTypes.constFind(it->typeId().iface());
+ if (jt == data->compositeTypes.constEnd() || *jt == compilationUnit)
+ return *it;
+ }
+
+ return doRegisterInlineComponentType(data, url);
+}
+
+void QQmlMetaType::unregisterInternalCompositeType(QMetaType metaType, QMetaType listMetaType)
+{
+ // This may be called from delayed dtors on shutdown when the data is already gone.
+ QQmlMetaTypeDataPtr data;
+ if (data.isValid()) {
+ if (QQmlValueType *vt = data->metaTypeToValueType.take(metaType.id()))
+ delete vt;
+ if (QQmlValueType *vt = data->metaTypeToValueType.take(listMetaType.id()))
+ delete vt;
+
+ auto it = data->compositeTypes.constFind(metaType.iface());
+ if (it != data->compositeTypes.constEnd())
+ data->compositeTypes.erase(it);
+ }
- data->qmlLists.remove(listMetaType.id());
QMetaType::unregisterMetaType(metaType);
QMetaType::unregisterMetaType(listMetaType);
delete static_cast<const QQmlMetaTypeInterface *>(metaType.iface());
- delete static_cast<const QQmlMetaTypeInterface *>(listMetaType.iface());
+ delete static_cast<const QQmlListMetaTypeInterface *>(listMetaType.iface());
}
int QQmlMetaType::registerUnitCacheHook(
const QQmlPrivate::RegisterQmlUnitCacheHook &hookRegistration)
{
- if (hookRegistration.structVersion > 0)
+ if (hookRegistration.structVersion > 1)
qFatal("qmlRegisterType(): Cannot mix incompatible QML versions.");
QQmlMetaTypeDataPtr data;
@@ -665,13 +766,12 @@ int QQmlMetaType::registerUnitCacheHook(
QQmlType QQmlMetaType::registerSequentialContainer(
const QQmlPrivate::RegisterSequentialContainer &container)
{
- if (container.structVersion > 0)
+ if (container.structVersion > 1)
qFatal("qmlRegisterSequenceContainer(): Cannot mix incompatible QML versions.");
QQmlMetaTypeDataPtr data;
- const QString typeName = QString::fromUtf8(container.typeName);
- if (!checkRegistration(QQmlType::SequentialContainerType, data, container.uri, typeName,
+ if (!checkRegistration(QQmlType::SequentialContainerType, data, container.uri, QString(),
container.version, {})) {
return QQmlType();
}
@@ -679,11 +779,12 @@ QQmlType QQmlMetaType::registerSequentialContainer(
QQmlTypePrivate *priv = new QQmlTypePrivate(QQmlType::SequentialContainerType);
data->registerType(priv);
- priv->setName(QString::fromUtf8(container.uri), typeName);
+ priv->setName(QString::fromUtf8(container.uri), QString());
priv->version = container.version;
priv->revision = container.revision;
- priv->typeId = container.typeId;
- *priv->extraData.ld = container.metaSequence;
+ priv->typeId = container.metaSequence.valueMetaType();
+ priv->listId = container.typeId;
+ priv->extraData.sequentialContainerTypeData = container.metaSequence;
addTypeToData(priv, data);
@@ -695,18 +796,19 @@ void QQmlMetaType::unregisterSequentialContainer(int id)
unregisterType(id);
}
-bool QQmlMetaType::protectModule(const QString &uri, QTypeRevision version, bool protectAllVersions)
+bool QQmlMetaType::protectModule(const QString &uri, QTypeRevision version,
+ bool weakProtectAllVersions)
{
QQmlMetaTypeDataPtr data;
if (version.hasMajorVersion()) {
- if (QQmlTypeModule *module = data->findTypeModule(uri, version)) {
- if (!protectAllVersions) {
- module->lock();
- return true;
+ if (QQmlTypeModule *module = data->findTypeModule(uri, version)) {
+ if (!weakProtectAllVersions) {
+ module->setLockLevel(QQmlTypeModule::LockLevel::Strong);
+ return true;
+ }
+ } else {
+ return false;
}
- } else {
- return false;
- }
}
const auto range = std::equal_range(
@@ -714,7 +816,7 @@ bool QQmlMetaType::protectModule(const QString &uri, QTypeRevision version, bool
std::less<ModuleUri>());
for (auto it = range.first; it != range.second; ++it)
- (*it)->lock();
+ (*it)->setLockLevel(QQmlTypeModule::LockLevel::Weak);
return range.first != range.second;
}
@@ -727,11 +829,6 @@ void QQmlMetaType::registerModuleImport(const QString &uri, QTypeRevision module
data->moduleImports.insert(QQmlMetaTypeData::VersionedUri(uri, moduleVersion), import);
}
-static bool operator==(const QQmlDirParser::Import &a, const QQmlDirParser::Import &b)
-{
- return a.module == b.module && a.version == b.version && a.flags == b.flags;
-}
-
void QQmlMetaType::unregisterModuleImport(const QString &uri, QTypeRevision moduleVersion,
const QQmlDirParser::Import &import)
{
@@ -743,13 +840,20 @@ QList<QQmlDirParser::Import> QQmlMetaType::moduleImports(
const QString &uri, QTypeRevision version)
{
QQmlMetaTypeDataPtr data;
+ QList<QQmlDirParser::Import> result;
const auto unrevisioned = data->moduleImports.equal_range(
QQmlMetaTypeData::VersionedUri(uri, QTypeRevision()));
+ for (auto it = unrevisioned.second; it != unrevisioned.first;)
+ result.append(*(--it));
- QList<QQmlDirParser::Import> result(unrevisioned.first, unrevisioned.second);
- if (version.hasMajorVersion())
- return result + data->moduleImports.values(QQmlMetaTypeData::VersionedUri(uri, version));
+ if (version.hasMajorVersion()) {
+ const auto revisioned = data->moduleImports.equal_range(
+ QQmlMetaTypeData::VersionedUri(uri, version));
+ for (auto it = revisioned.second; it != revisioned.first;)
+ result.append(*(--it));
+ return result;
+ }
// Use latest module available with that URI.
const auto begin = data->moduleImports.begin();
@@ -813,25 +917,6 @@ static bool namespaceContainsRegistrations(const QQmlMetaTypeData *data, const Q
return false;
}
-class QQmlMetaTypeRegistrationFailureRecorder
-{
- Q_DISABLE_COPY_MOVE(QQmlMetaTypeRegistrationFailureRecorder)
-public:
- QQmlMetaTypeRegistrationFailureRecorder(QQmlMetaTypeData *data, QStringList *failures)
- : data(data)
- {
- data->setTypeRegistrationFailures(failures);
- }
-
- ~QQmlMetaTypeRegistrationFailureRecorder()
- {
- data->setTypeRegistrationFailures(nullptr);
- }
-
- QQmlMetaTypeData *data = nullptr;
-};
-
-
QQmlMetaType::RegistrationResult QQmlMetaType::registerPluginTypes(
QObject *instance, const QString &basePath, const QString &uri,
const QString &typeNamespace, QTypeRevision version, QList<QQmlError> *errors)
@@ -843,7 +928,7 @@ QQmlMetaType::RegistrationResult QQmlMetaType::registerPluginTypes(
QQmlError error;
error.setDescription(
QStringLiteral("Module namespace '%1' does not match import URI '%2'")
- .arg(typeNamespace).arg(uri));
+ .arg(typeNamespace, uri));
errors->prepend(error);
}
return RegistrationResult::Failure;
@@ -886,11 +971,15 @@ QQmlMetaType::RegistrationResult QQmlMetaType::registerPluginTypes(
return RegistrationResult::Failure;
}
+#if QT_DEPRECATED_SINCE(6, 3)
if (auto *plugin = qobject_cast<QQmlExtensionPlugin *>(instance)) {
// basepath should point to the directory of the module, not the plugin file itself:
QQmlExtensionPluginPrivate::get(plugin)->baseUrl
= QQmlImports::urlFromLocalFileOrQrcOrUrl(basePath);
}
+#else
+ Q_UNUSED(basePath)
+#endif
const QByteArray bytes = uri.toUtf8();
const char *moduleId = bytes.constData();
@@ -902,7 +991,7 @@ QQmlMetaType::RegistrationResult QQmlMetaType::registerPluginTypes(
if (!failures.isEmpty()) {
if (errors) {
- for (const QString &failure : qAsConst(failures)) {
+ for (const QString &failure : std::as_const(failures)) {
QQmlError error;
error.setDescription(failure);
errors->prepend(error);
@@ -928,7 +1017,7 @@ QQmlMetaType::RegistrationResult QQmlMetaType::registerPluginTypes(
*/
QQmlType QQmlMetaType::typeForUrl(const QString &urlString,
const QHashedStringRef &qualifiedType,
- bool isCompositeSingleton, QList<QQmlError> *errors,
+ CompositeTypeLookupMode mode, QList<QQmlError> *errors,
QTypeRevision version)
{
// ### unfortunate (costly) conversion
@@ -946,69 +1035,10 @@ QQmlType QQmlMetaType::typeForUrl(const QString &urlString,
return ret;
}
- const int dot = qualifiedType.indexOf(QLatin1Char('.'));
- const QString typeName = dot < 0
- ? qualifiedType.toString()
- : QString(qualifiedType.constData() + dot + 1, qualifiedType.length() - dot - 1);
-
- QStringList failures;
- QQmlMetaTypeRegistrationFailureRecorder failureRecorder(data, &failures);
-
- // Register the type. Note that the URI parameters here are empty; for
- // file type imports, we do not place them in a URI as we don't
- // necessarily have a good and unique one (picture a library import,
- // which may be found in multiple plugin locations on disk), but there
- // are other reasons for this too.
- //
- // By not putting them in a URI, we prevent the types from being
- // registered on a QQmlTypeModule; this is important, as once types are
- // placed on there, they cannot be easily removed, meaning if the
- // developer subsequently loads a different import (meaning different
- // types) with the same URI (using, say, a different plugin path), it is
- // very undesirable that we continue to associate the types from the
- // "old" URI with that new module.
- //
- // Not having URIs also means that the types cannot be found by name
- // etc, the only way to look them up is through QQmlImports -- for
- // better or worse.
- const QQmlType::RegistrationType registrationType = isCompositeSingleton
- ? QQmlType::CompositeSingletonType
- : QQmlType::CompositeType;
- if (checkRegistration(registrationType, data, nullptr, typeName, version, {})) {
- auto *priv = new QQmlTypePrivate(registrationType);
- priv->setName(QString(), typeName);
- priv->version = version;
-
- if (isCompositeSingleton) {
- priv->extraData.sd->singletonInstanceInfo = new QQmlType::SingletonInstanceInfo;
- priv->extraData.sd->singletonInstanceInfo->url = url;
- priv->extraData.sd->singletonInstanceInfo->typeName = typeName;
- } else {
- priv->extraData.fd->url = url;
- }
-
- data->registerType(priv);
- addTypeToData(priv, data);
- data->urlToType.insert(url, priv);
- return QQmlType(priv);
- }
-
- // This means that the type couldn't be found by URL, but could not be
- // registered either, meaning we most likely were passed some kind of bad
- // data.
- if (errors) {
- QQmlError error;
- error.setDescription(failures.join(u'\n'));
- errors->prepend(error);
- } else {
- qWarning("%s", failures.join(u'\n').toLatin1().constData());
- }
- return QQmlType();
-}
-
-QRecursiveMutex *QQmlMetaType::typeRegistrationLock()
-{
- return metaTypeDataLock();
+ const QQmlType type = createTypeForUrl(
+ data, url, qualifiedType, mode, errors, version);
+ data->urlToType.insert(url, type.priv());
+ return type;
}
/*
@@ -1031,12 +1061,12 @@ QTypeRevision QQmlMetaType::latestModuleVersion(const QString &uri)
/*
Returns true if a module \a uri of this version is installed and locked;
*/
-bool QQmlMetaType::isLockedModule(const QString &uri, QTypeRevision version)
+bool QQmlMetaType::isStronglyLockedModule(const QString &uri, QTypeRevision version)
{
QQmlMetaTypeDataPtr data;
if (QQmlTypeModule* qqtm = data->findTypeModule(uri, version))
- return qqtm->isLocked();
+ return qqtm->lockLevel() == QQmlTypeModule::LockLevel::Strong;
return false;
}
@@ -1102,17 +1132,24 @@ QObject *QQmlMetaType::toQObject(const QVariant &v, bool *ok)
/*
Returns the item type for a list of type \a id.
*/
-int QQmlMetaType::listType(int id)
-{
+QMetaType QQmlMetaType::listValueType(QMetaType metaType)
+{
+ if (isList(metaType)) {
+ const auto iface = metaType.iface();
+ if (iface && iface->metaObjectFn == &dynamicQmlListMarker)
+ return QMetaType(static_cast<const QQmlListMetaTypeInterface *>(iface)->valueType);
+ } else if (metaType.flags() & QMetaType::PointerToQObject) {
+ return QMetaType();
+ }
+
QQmlMetaTypeDataPtr data;
- QHash<int, int>::ConstIterator iter = data->qmlLists.constFind(id);
- if (iter != data->qmlLists.cend())
- return *iter;
- QQmlTypePrivate *type = data->idToType.value(id);
- if (type && type->listId.id() == id)
- return type->typeId.id();
+ Q_ASSERT(data);
+ QQmlTypePrivate *type = data->idToType.value(metaType.id());
+
+ if (type && type->listId == metaType)
+ return type->typeId;
else
- return 0;
+ return QMetaType {};
}
QQmlAttachedPropertiesFunc QQmlMetaType::attachedPropertiesFunc(QQmlEnginePrivate *engine,
@@ -1179,70 +1216,25 @@ QMetaMethod QQmlMetaType::defaultMethod(QObject *obj)
/*!
See qmlRegisterInterface() for information about when this will return true.
*/
-bool QQmlMetaType::isInterface(int userType)
+bool QQmlMetaType::isInterface(QMetaType type)
{
const QQmlMetaTypeDataPtr data;
- return data->interfaces.contains(userType);
+ return data->interfaces.contains(type.id());
}
-const char *QQmlMetaType::interfaceIId(int userType)
+const char *QQmlMetaType::interfaceIId(QMetaType metaType)
{
-
- QQmlTypePrivate *typePrivate = nullptr;
- {
- QQmlMetaTypeDataPtr data;
- typePrivate = data->idToType.value(userType);
- }
-
- QQmlType type(typePrivate);
- if (type.isInterface() && type.typeId().id() == userType)
- return type.interfaceIId();
- else
- return nullptr;
+ const QQmlMetaTypeDataPtr data;
+ const QQmlType type(data->idToType.value(metaType.id()));
+ return (type.isInterface() && type.typeId() == metaType) ? type.interfaceIId() : nullptr;
}
-bool QQmlMetaType::isList(int userType)
+bool QQmlMetaType::isList(QMetaType type)
{
- QMetaType type(userType);
if (type.flags().testFlag(QMetaType::IsQmlList))
return true;
- QQmlMetaTypeDataPtr data;
- if (data->qmlLists.contains(userType))
- return true;
- return false;
-}
-
-/*!
- A custom string convertor allows you to specify a function pointer that
- returns a variant of \a type. For example, if you have written your own icon
- class that you want to support as an object property assignable in QML:
-
- \code
- int type = qRegisterMetaType<SuperIcon>("SuperIcon");
- QML::addCustomStringConvertor(type, &SuperIcon::pixmapFromString);
- \endcode
-
- The function pointer must be of the form:
- \code
- QVariant (*StringConverter)(const QString &);
- \endcode
- */
-void QQmlMetaType::registerCustomStringConverter(int type, StringConverter converter)
-{
- QQmlMetaTypeDataPtr data;
- if (data->stringConverters.contains(type))
- return;
- data->stringConverters.insert(type, converter);
-}
-
-/*!
- Return the custom string converter for \a type, previously installed through
- registerCustomStringConverter()
- */
-QQmlMetaType::StringConverter QQmlMetaType::customStringConverter(int type)
-{
- const QQmlMetaTypeDataPtr data;
- return data->stringConverters.value(type);
+ else
+ return false;
}
/*!
@@ -1256,14 +1248,18 @@ QQmlType QQmlMetaType::qmlType(const QString &qualifiedName, QTypeRevision versi
return QQmlType();
QHashedStringRef module(qualifiedName.constData(), slash);
- QHashedStringRef name(qualifiedName.constData() + slash + 1, qualifiedName.length() - slash - 1);
+ QHashedStringRef name(qualifiedName.constData() + slash + 1, qualifiedName.size() - slash - 1);
return qmlType(name, module, version);
}
/*!
- Returns the type (if any) of \a name in \a module and version specified
- by \a version_major and \a version_minor.
+ \internal
+ Returns the type (if any) of \a name in \a module and the specified \a version.
+
+ If \a version has no major version, accept any version.
+ If \a version has no minor version, accept any minor version.
+ If \a module is empty, search in all modules and accept any version.
*/
QQmlType QQmlMetaType::qmlType(const QHashedStringRef &name, const QHashedStringRef &module,
QTypeRevision version)
@@ -1283,8 +1279,8 @@ QQmlType QQmlMetaType::qmlType(const QHashedStringRef &name, const QHashedString
}
/*!
- Returns the type (if any) that corresponds to the \a metaObject. Returns null if no
- type is registered.
+ Returns the type (if any) that corresponds to the \a metaObject. Returns an invalid type if no
+ such type is registered.
*/
QQmlType QQmlMetaType::qmlType(const QMetaObject *metaObject)
{
@@ -1302,39 +1298,48 @@ QQmlType QQmlMetaType::qmlType(const QMetaObject *metaObject, const QHashedStrin
{
const QQmlMetaTypeDataPtr data;
- QQmlMetaTypeData::MetaObjects::const_iterator it = data->metaObjectToType.constFind(metaObject);
- while (it != data->metaObjectToType.cend() && it.key() == metaObject) {
+ const auto range = data->metaObjectToType.equal_range(metaObject);
+ for (auto it = range.first; it != range.second; ++it) {
QQmlType t(*it);
if (module.isEmpty() || t.availableInVersion(module, version))
return t;
- ++it;
}
return QQmlType();
}
/*!
- Returns the type (if any) that corresponds to \a typeId. Depending on \a category, the
- \a typeId is interpreted either as QVariant::Type or as QML type id returned by one of the
- qml type registration functions. Returns null if no type is registered.
+ Returns the type (if any) that corresponds to \a qmlTypeId.
+ Returns an invalid QQmlType if no such type is registered.
*/
-QQmlType QQmlMetaType::qmlType(int typeId, TypeIdCategory category)
+QQmlType QQmlMetaType::qmlTypeById(int qmlTypeId)
{
const QQmlMetaTypeDataPtr data;
-
- if (category == TypeIdCategory::MetaType) {
- QQmlTypePrivate *type = data->idToType.value(typeId);
- if (type && type->typeId.id() == typeId)
- return QQmlType(type);
- } else if (category == TypeIdCategory::QmlType) {
- QQmlType type = data->types.value(typeId);
- if (type.isValid())
- return type;
- }
+ QQmlType type = data->types.value(qmlTypeId);
+ if (type.isValid())
+ return type;
return QQmlType();
}
/*!
+ Returns the type (if any) that corresponds to \a metaType.
+ Returns an invalid QQmlType if no such type is registered.
+*/
+QQmlType QQmlMetaType::qmlType(QMetaType metaType)
+{
+ const QQmlMetaTypeDataPtr data;
+ QQmlTypePrivate *type = data->idToType.value(metaType.id());
+ return (type && type->typeId == metaType) ? QQmlType(type) : QQmlType();
+}
+
+QQmlType QQmlMetaType::qmlListType(QMetaType metaType)
+{
+ const QQmlMetaTypeDataPtr data;
+ QQmlTypePrivate *type = data->idToType.value(metaType.id());
+ return (type && type->listId == metaType) ? QQmlType(type) : QQmlType();
+}
+
+/*!
Returns the type (if any) that corresponds to the given \a url in the set of
composite types added through file imports.
@@ -1355,27 +1360,158 @@ QQmlType QQmlMetaType::qmlType(const QUrl &unNormalizedUrl, bool includeNonFileI
return QQmlType();
}
-QQmlPropertyCache *QQmlMetaType::propertyCache(const QMetaObject *metaObject, QTypeRevision version, bool doRef)
+QQmlType QQmlMetaType::fetchOrCreateInlineComponentTypeForUrl(const QUrl &url)
+{
+ QQmlMetaTypeDataPtr data;
+ const auto it = data->inlineComponentTypes.constFind(url);
+ if (it != data->inlineComponentTypes.constEnd())
+ return *it;
+
+ return doRegisterInlineComponentType(data, url);
+}
+
+/*!
+Returns a QQmlPropertyCache for \a obj if one is available.
+
+If \a obj is null, being deleted or contains a dynamic meta object,
+nullptr is returned.
+*/
+QQmlPropertyCache::ConstPtr QQmlMetaType::propertyCache(QObject *obj, QTypeRevision version)
+{
+ if (!obj || QObjectPrivate::get(obj)->metaObject || QObjectPrivate::get(obj)->wasDeleted)
+ return QQmlPropertyCache::ConstPtr();
+ return QQmlMetaType::propertyCache(obj->metaObject(), version);
+}
+
+QQmlPropertyCache::ConstPtr QQmlMetaType::propertyCache(
+ const QMetaObject *metaObject, QTypeRevision version)
{
QQmlMetaTypeDataPtr data; // not const: the cache is created on demand
- auto ret = data->propertyCache(metaObject, version);
- if (doRef)
- return ret.take();
- else
- return ret.data();
+ return data->propertyCache(metaObject, version);
}
-QQmlPropertyCache *QQmlMetaType::propertyCache(const QQmlType &type, QTypeRevision version)
+QQmlPropertyCache::ConstPtr QQmlMetaType::propertyCache(
+ const QQmlType &type, QTypeRevision version)
{
QQmlMetaTypeDataPtr data; // not const: the cache is created on demand
return data->propertyCache(type, version);
}
+/*!
+ * \internal
+ *
+ * Look up by type's baseMetaObject.
+ */
+QQmlMetaObject QQmlMetaType::rawMetaObjectForType(QMetaType metaType)
+{
+ const QQmlMetaTypeDataPtr data;
+ if (auto composite = data->findPropertyCacheInCompositeTypes(metaType))
+ return QQmlMetaObject(composite);
+
+ const QQmlTypePrivate *type = data->idToType.value(metaType.id());
+ return (type && type->typeId == metaType) ? type->baseMetaObject : nullptr;
+}
+
+/*!
+ * \internal
+ *
+ * Look up by type's metaObject.
+ */
+QQmlMetaObject QQmlMetaType::metaObjectForType(QMetaType metaType)
+{
+ const QQmlMetaTypeDataPtr data;
+ if (auto composite = data->findPropertyCacheInCompositeTypes(metaType))
+ return QQmlMetaObject(composite);
+
+ const QQmlTypePrivate *type = data->idToType.value(metaType.id());
+ return (type && type->typeId == metaType)
+ ? QQmlType(type).metaObject()
+ : nullptr;
+}
+
+/*!
+ * \internal
+ *
+ * Look up by type's metaObject and version.
+ */
+QQmlPropertyCache::ConstPtr QQmlMetaType::propertyCacheForType(QMetaType metaType)
+{
+ QQmlMetaTypeDataPtr data;
+ if (auto composite = data->findPropertyCacheInCompositeTypes(metaType))
+ return composite;
+
+ const QQmlTypePrivate *type = data->idToType.value(metaType.id());
+ if (type && type->typeId == metaType) {
+ if (const QMetaObject *mo = QQmlType(type).metaObject())
+ return data->propertyCache(mo, type->version);
+ }
+
+ return QQmlPropertyCache::ConstPtr();
+}
+
+/*!
+ * \internal
+ *
+ * Look up by type's baseMetaObject and unspecified/any version.
+ * TODO: Is this correct? Passing a plain QTypeRevision() rather than QTypeRevision::zero() or
+ * the actual type's version seems strange. The behavior has been in place for a while.
+ */
+QQmlPropertyCache::ConstPtr QQmlMetaType::rawPropertyCacheForType(QMetaType metaType)
+{
+ QQmlMetaTypeDataPtr data;
+ if (auto composite = QQmlMetaType::findPropertyCacheInCompositeTypes(metaType))
+ return composite;
+
+ const QQmlTypePrivate *type = data->idToType.value(metaType.id());
+ if (!type || type->typeId != metaType)
+ return QQmlPropertyCache::ConstPtr();
+
+ const QMetaObject *metaObject = type->isValueType()
+ ? type->metaObjectForValueType()
+ : type->baseMetaObject;
+
+ return metaObject
+ ? data->propertyCache(metaObject, QTypeRevision())
+ : QQmlPropertyCache::ConstPtr();
+}
+
+/*!
+ * \internal
+ *
+ * Look up by QQmlType and version. We only fall back to lookup by metaobject if the type
+ * has no revisiononed attributes here. Unspecified versions are interpreted as "any".
+ */
+QQmlPropertyCache::ConstPtr QQmlMetaType::rawPropertyCacheForType(
+ QMetaType metaType, QTypeRevision version)
+{
+ QQmlMetaTypeDataPtr data;
+ if (auto composite = data->findPropertyCacheInCompositeTypes(metaType))
+ return composite;
+
+ const QQmlTypePrivate *typePriv = data->idToType.value(metaType.id());
+ if (!typePriv || typePriv->typeId != metaType)
+ return QQmlPropertyCache::ConstPtr();
+
+ const QQmlType type(typePriv);
+ if (type.containsRevisionedAttributes()) {
+ // It can only have (revisioned) properties or methods if it has a metaobject
+ Q_ASSERT(type.metaObject());
+ return data->propertyCache(type, version);
+ }
+
+ if (const QMetaObject *metaObject = type.metaObject())
+ return data->propertyCache(metaObject, version);
+
+ return QQmlPropertyCache::ConstPtr();
+}
+
void QQmlMetaType::unregisterType(int typeIndex)
{
QQmlMetaTypeDataPtr data;
const QQmlType type = data->types.value(typeIndex);
if (const QQmlTypePrivate *d = type.priv()) {
+ if (d->regType == QQmlType::CompositeType || d->regType == QQmlType::CompositeSingletonType)
+ removeFromInlineComponents(data->inlineComponentTypes, d);
removeQQmlTypePrivate(data->idToType, d);
removeQQmlTypePrivate(data->nameToType, d);
removeQQmlTypePrivate(data->urlToType, d);
@@ -1389,6 +1525,49 @@ void QQmlMetaType::unregisterType(int typeIndex)
}
}
+void QQmlMetaType::registerMetaObjectForType(const QMetaObject *metaobject, QQmlTypePrivate *type)
+{
+ Q_ASSERT(type);
+
+ QQmlMetaTypeDataPtr data;
+ data->metaObjectToType.insert(metaobject, type);
+}
+
+static bool hasActiveInlineComponents(const QQmlMetaTypeData *data, const QQmlTypePrivate *d)
+{
+ for (auto it = data->inlineComponentTypes.begin(), end = data->inlineComponentTypes.end();
+ it != end; ++it) {
+ if (!QQmlMetaType::equalBaseUrls(it.key(), d->sourceUrl()))
+ continue;
+
+ const QQmlTypePrivate *icPriv = it->priv();
+ if (icPriv && icPriv->count() > 1)
+ return true;
+ }
+ return false;
+}
+
+static int doCountInternalCompositeTypeSelfReferences(
+ QQmlMetaTypeData *data,
+ const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &compilationUnit)
+{
+ int result = 0;
+ auto doCheck = [&](const QtPrivate::QMetaTypeInterface *iface) {
+ if (!iface)
+ return;
+
+ const auto it = data->compositeTypes.constFind(iface);
+ if (it != data->compositeTypes.constEnd() && *it == compilationUnit)
+ ++result;
+ };
+
+ doCheck(compilationUnit->metaType().iface());
+ for (auto &&inlineData: compilationUnit->inlineComponentData)
+ doCheck(inlineData.qmlType.typeId().iface());
+
+ return result;
+}
+
void QQmlMetaType::freeUnusedTypesAndCaches()
{
QQmlMetaTypeDataPtr data;
@@ -1397,15 +1576,33 @@ void QQmlMetaType::freeUnusedTypesAndCaches()
if (!data.isValid())
return;
+ bool droppedAtLeastOneComposite;
+ do {
+ droppedAtLeastOneComposite = false;
+ auto it = data->compositeTypes.begin();
+ while (it != data->compositeTypes.end()) {
+ if ((*it)->count() <= doCountInternalCompositeTypeSelfReferences(data, *it)) {
+ it = data->compositeTypes.erase(it);
+ droppedAtLeastOneComposite = true;
+ } else {
+ ++it;
+ }
+ }
+ } while (droppedAtLeastOneComposite);
+
bool deletedAtLeastOneType;
do {
deletedAtLeastOneType = false;
QList<QQmlType>::Iterator it = data->types.begin();
while (it != data->types.end()) {
const QQmlTypePrivate *d = (*it).priv();
- if (d && d->count() == 1) {
+ if (d && d->count() == 1 && !hasActiveInlineComponents(data, d)) {
deletedAtLeastOneType = true;
+ if (d->regType == QQmlType::CompositeType
+ || d->regType == QQmlType::CompositeSingletonType) {
+ removeFromInlineComponents(data->inlineComponentTypes, d);
+ }
removeQQmlTypePrivate(data->idToType, d);
removeQQmlTypePrivate(data->nameToType, d);
removeQQmlTypePrivate(data->urlToType, d);
@@ -1426,14 +1623,10 @@ void QQmlMetaType::freeUnusedTypesAndCaches()
bool deletedAtLeastOneCache;
do {
deletedAtLeastOneCache = false;
- QHash<const QMetaObject *, QQmlPropertyCache *>::Iterator it = data->propertyCaches.begin();
+ auto it = data->propertyCaches.begin();
while (it != data->propertyCaches.end()) {
-
if ((*it)->count() == 1) {
- QQmlPropertyCache *pc = nullptr;
- qSwap(pc, *it);
it = data->propertyCaches.erase(it);
- pc->release();
deletedAtLeastOneCache = true;
} else {
++it;
@@ -1450,7 +1643,7 @@ QList<QString> QQmlMetaType::qmlTypeNames()
const QQmlMetaTypeDataPtr data;
QList<QString> names;
- names.reserve(data->nameToType.count());
+ names.reserve(data->nameToType.size());
QQmlMetaTypeData::Names::ConstIterator it = data->nameToType.cbegin();
while (it != data->nameToType.cend()) {
QQmlType t(*it);
@@ -1469,7 +1662,7 @@ QList<QQmlType> QQmlMetaType::qmlTypes()
const QQmlMetaTypeDataPtr data;
QList<QQmlType> types;
- for (QQmlTypePrivate *t : data->nameToType)
+ for (const QQmlTypePrivate *t : data->nameToType)
types.append(QQmlType(t));
return types;
@@ -1492,7 +1685,7 @@ QList<QQmlType> QQmlMetaType::qmlSingletonTypes()
const QQmlMetaTypeDataPtr data;
QList<QQmlType> retn;
- for (const auto t : qAsConst(data->nameToType)) {
+ for (const auto t : std::as_const(data->nameToType)) {
QQmlType type(t);
if (type.isSingleton())
retn.append(type);
@@ -1500,19 +1693,44 @@ QList<QQmlType> QQmlMetaType::qmlSingletonTypes()
return retn;
}
-const QQmlPrivate::CachedQmlUnit *QQmlMetaType::findCachedCompilationUnit(const QUrl &uri, CachedUnitLookupError *status)
+static bool isFullyTyped(const QQmlPrivate::CachedQmlUnit *unit)
{
+ quint32 numTypedFunctions = 0;
+ for (const QQmlPrivate::AOTCompiledFunction *function = unit->aotCompiledFunctions;
+ function; ++function) {
+ if (function->functionPtr)
+ ++numTypedFunctions;
+ else
+ return false;
+ }
+ return numTypedFunctions == unit->qmlData->functionTableSize;
+}
+
+const QQmlPrivate::CachedQmlUnit *QQmlMetaType::findCachedCompilationUnit(
+ const QUrl &uri, QQmlMetaType::CacheMode mode, CachedUnitLookupError *status)
+{
+ Q_ASSERT(mode != RejectAll);
const QQmlMetaTypeDataPtr data;
- for (const auto lookup : qAsConst(data->lookupCachedQmlUnit)) {
+ for (const auto lookup : std::as_const(data->lookupCachedQmlUnit)) {
if (const QQmlPrivate::CachedQmlUnit *unit = lookup(uri)) {
QString error;
- if (!QV4::ExecutableCompilationUnit::verifyHeader(unit->qmlData, QDateTime(), &error)) {
+ if (!unit->qmlData->verifyHeader(QDateTime(), &error)) {
qCDebug(DBG_DISK_CACHE) << "Error loading pre-compiled file " << uri << ":" << error;
if (status)
*status = CachedUnitLookupError::VersionMismatch;
return nullptr;
}
+
+ if (mode == RequireFullyTyped && !isFullyTyped(unit)) {
+ qCDebug(DBG_DISK_CACHE)
+ << "Error loading pre-compiled file " << uri
+ << ": compilation unit contains functions not compiled to native code.";
+ if (status)
+ *status = CachedUnitLookupError::NotFullyTyped;
+ return nullptr;
+ }
+
if (status)
*status = CachedUnitLookupError::NoError;
return unit;
@@ -1564,7 +1782,7 @@ QString QQmlMetaType::prettyTypeName(const QObject *object)
marker = typeName.indexOf(QLatin1String("_QML_"));
if (marker != -1) {
typeName = QStringView{typeName}.left(marker) + QLatin1Char('*');
- type = QQmlMetaType::qmlType(QMetaType::fromName(typeName.toLatin1()).id());
+ type = QQmlMetaType::qmlType(QMetaType::fromName(typeName.toUtf8()));
if (type.isValid()) {
QString qmlTypeName = type.qmlTypeName();
const int lastSlash = qmlTypeName.lastIndexOf(QLatin1Char('/'));
@@ -1586,17 +1804,19 @@ QList<QQmlProxyMetaObject::ProxyData> QQmlMetaType::proxyData(const QMetaObject
QList<QQmlProxyMetaObject::ProxyData> metaObjects;
mo = mo->d.superdata;
- const QQmlMetaTypeDataPtr data;
+ if (!mo)
+ return metaObjects;
- auto createProxyMetaObject = [&](const QMetaObject *superdataBaseMetaObject,
+ auto createProxyMetaObject = [&](QQmlTypePrivate *This,
+ const QMetaObject *superdataBaseMetaObject,
const QMetaObject *extMetaObject,
QObject *(*extFunc)(QObject *)) {
if (!extMetaObject)
return;
QMetaObjectBuilder builder;
- clone(builder, extMetaObject, superdataBaseMetaObject, baseMetaObject);
- builder.setFlags(MetaObjectFlag::DynamicMetaObject);
+ clone(builder, extMetaObject, superdataBaseMetaObject, baseMetaObject,
+ extFunc ? QQmlMetaType::CloneAll : QQmlMetaType::CloneEnumsOnly);
QMetaObject *mmo = builder.toMetaObject();
mmo->d.superdata = baseMetaObject;
if (!metaObjects.isEmpty())
@@ -1605,26 +1825,33 @@ QList<QQmlProxyMetaObject::ProxyData> QQmlMetaType::proxyData(const QMetaObject
lastMetaObject->d.superdata = mmo;
QQmlProxyMetaObject::ProxyData data = { mmo, extFunc, 0, 0 };
metaObjects << data;
+ registerMetaObjectForType(mmo, This);
};
- while (mo) {
- QQmlTypePrivate *t = data->metaObjectToType.value(mo);
- if (t) {
+ for (const QQmlMetaTypeDataPtr data; mo; mo = mo->d.superdata) {
+ // TODO: There can in fact be multiple QQmlTypePrivate* for a single QMetaObject*.
+ // This algorithm only accounts for the most recently inserted one. That's pretty
+ // random. However, the availability of types depends on what documents you have
+ // loaded before. Just adding all possible extensions would also be pretty random.
+ // The right way to do this would be to take the relations between the QML modules
+ // into account. For this we would need proper module dependency information.
+ if (QQmlTypePrivate *t = data->metaObjectToType.value(mo)) {
if (t->regType == QQmlType::CppType) {
- createProxyMetaObject(t->baseMetaObject, t->extraData.cd->extMetaObject,
- t->extraData.cd->extFunc);
+ createProxyMetaObject(
+ t, t->baseMetaObject, t->extraData.cppTypeData->extMetaObject,
+ t->extraData.cppTypeData->extFunc);
} else if (t->regType == QQmlType::SingletonType) {
- createProxyMetaObject(t->baseMetaObject, t->extraData.sd->extMetaObject,
- t->extraData.sd->extFunc);
+ createProxyMetaObject(
+ t, t->baseMetaObject, t->extraData.singletonTypeData->extMetaObject,
+ t->extraData.singletonTypeData->extFunc);
}
}
- mo = mo->d.superdata;
- }
+ };
return metaObjects;
}
-bool isInternalType(int idx)
+static bool isInternalType(int idx)
{
// Qt internal types
switch (idx) {
@@ -1651,10 +1878,9 @@ bool QQmlMetaType::isValueType(QMetaType type)
return valueType(type) != nullptr;
}
-const QMetaObject *QQmlMetaType::metaObjectForMetaType(QMetaType metaType)
+const QMetaObject *QQmlMetaType::metaObjectForValueType(QMetaType metaType)
{
- const int t = metaType.id();
- switch (t) {
+ switch (metaType.id()) {
case QMetaType::QPoint:
return &QQmlPointValueType::staticMetaObject;
case QMetaType::QPointF:
@@ -1671,19 +1897,7 @@ const QMetaObject *QQmlMetaType::metaObjectForMetaType(QMetaType metaType)
case QMetaType::QEasingCurve:
return &QQmlEasingValueType::staticMetaObject;
#endif
-#if QT_CONFIG(qml_itemmodel)
- case QMetaType::QModelIndex:
- return &QQmlModelIndexValueType::staticMetaObject;
- case QMetaType::QPersistentModelIndex:
- return &QQmlPersistentModelIndexValueType::staticMetaObject;
-#endif
default:
-#if QT_CONFIG(qml_itemmodel)
- if (metaType == QMetaType::fromType<QItemSelectionRange>())
- return &QQmlItemSelectionRangeValueType::staticMetaObject;
-#endif
- if (metaType == QMetaType::fromType<QQmlProperty>())
- return &QQmlPropertyValueType::staticMetaObject;
break;
}
@@ -1691,15 +1905,12 @@ const QMetaObject *QQmlMetaType::metaObjectForMetaType(QMetaType metaType)
// call QObject pointers value types. Explicitly registered types also override
// the implicit use of gadgets.
if (!(metaType.flags() & QMetaType::PointerToQObject)) {
- const QQmlType qmlType = QQmlMetaType::qmlType(t, QQmlMetaType::TypeIdCategory::MetaType);
-
- // Prefer the extension meta object.
- // Extensions allow registration of non-gadget value types.
- if (const QMetaObject *extensionMetaObject = qmlType.extensionMetaObject())
- return extensionMetaObject;
-
- if (const QMetaObject *qmlTypeMetaObject = qmlType.metaObject())
- return qmlTypeMetaObject;
+ const QQmlMetaTypeDataPtr data;
+ const QQmlTypePrivate *type = data->idToType.value(metaType.id());
+ if (type && type->regType == QQmlType::CppType && type->typeId == metaType) {
+ if (const QMetaObject *mo = type->metaObjectForValueType())
+ return mo;
+ }
}
// If it _is_ a gadget, we can just use it.
@@ -1711,16 +1922,93 @@ const QMetaObject *QQmlMetaType::metaObjectForMetaType(QMetaType metaType)
QQmlValueType *QQmlMetaType::valueType(QMetaType type)
{
- const int idx = type.id();
QQmlMetaTypeDataPtr data;
- const auto it = data->metaTypeToValueType.constFind(idx);
+ const auto it = data->metaTypeToValueType.constFind(type.id());
if (it != data->metaTypeToValueType.constEnd())
return *it;
- if (const QMetaObject *mo = metaObjectForMetaType(type))
- return *data->metaTypeToValueType.insert(idx, new QQmlValueType(idx, mo));
- return *data->metaTypeToValueType.insert(idx, nullptr);
+ if (const QMetaObject *mo = metaObjectForValueType(type))
+ return *data->metaTypeToValueType.insert(type.id(), new QQmlValueType(type, mo));
+ return *data->metaTypeToValueType.insert(type.id(), nullptr);
+}
+
+QQmlPropertyCache::ConstPtr QQmlMetaType::findPropertyCacheInCompositeTypes(QMetaType t)
+{
+ const QQmlMetaTypeDataPtr data;
+ return data->findPropertyCacheInCompositeTypes(t);
+}
+
+void QQmlMetaType::registerInternalCompositeType(
+ const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &compilationUnit)
+{
+ QQmlMetaTypeDataPtr data;
+
+ auto doInsert = [&data, &compilationUnit](const QtPrivate::QMetaTypeInterface *iface) {
+ Q_ASSERT(iface);
+ Q_ASSERT(compilationUnit);
+
+ // We can't assert on anything else here. We may get a completely new type as exposed
+ // by the qmldiskcache test that changes a QML file in place during the execution
+ // of the test.
+ data->compositeTypes.insert(iface, compilationUnit);
+ };
+
+ doInsert(compilationUnit->metaType().iface());
+ for (auto &&inlineData: compilationUnit->inlineComponentData)
+ doInsert(inlineData.qmlType.typeId().iface());
+}
+
+void QQmlMetaType::unregisterInternalCompositeType(
+ const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &compilationUnit)
+{
+ QQmlMetaTypeDataPtr data;
+
+ auto doRemove = [&](const QtPrivate::QMetaTypeInterface *iface) {
+ if (!iface)
+ return;
+
+ const auto it = data->compositeTypes.constFind(iface);
+ if (it != data->compositeTypes.constEnd() && *it == compilationUnit)
+ data->compositeTypes.erase(it);
+ };
+
+ doRemove(compilationUnit->metaType().iface());
+ for (auto &&inlineData: compilationUnit->inlineComponentData)
+ doRemove(inlineData.qmlType.typeId().iface());
+}
+
+int QQmlMetaType::countInternalCompositeTypeSelfReferences(
+ const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &compilationUnit)
+{
+ QQmlMetaTypeDataPtr data;
+ return doCountInternalCompositeTypeSelfReferences(data, compilationUnit);
+}
+
+QQmlRefPointer<QV4::CompiledData::CompilationUnit> QQmlMetaType::obtainCompilationUnit(
+ QMetaType type)
+{
+ const QQmlMetaTypeDataPtr data;
+ return data->compositeTypes.value(type.iface());
+}
+
+QQmlRefPointer<QV4::CompiledData::CompilationUnit> QQmlMetaType::obtainCompilationUnit(
+ const QUrl &url)
+{
+ const QUrl normalized = QQmlTypeLoader::normalize(url);
+ QQmlMetaTypeDataPtr data;
+
+ auto found = data->urlToType.constFind(normalized);
+ if (found == data->urlToType.constEnd()) {
+ found = data->urlToNonFileImportType.constFind(normalized);
+ if (found == data->urlToNonFileImportType.constEnd())
+ return QQmlRefPointer<QV4::CompiledData::CompilationUnit>();
+ }
+
+ const auto composite = data->compositeTypes.constFind(found.value()->typeId.iface());
+ return composite == data->compositeTypes.constEnd()
+ ? QQmlRefPointer<QV4::CompiledData::CompilationUnit>()
+ : composite.value();
}
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlmetatype_p.h b/src/qml/qml/qqmlmetatype_p.h
index d1735902f5..f4870d9db1 100644
--- a/src/qml/qml/qqmlmetatype_p.h
+++ b/src/qml/qml/qqmlmetatype_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLMETATYPE_P_H
#define QQMLMETATYPE_P_H
@@ -51,10 +15,11 @@
// We mean it.
//
-#include <private/qtqmlglobal_p.h>
-#include <private/qqmltype_p.h>
-#include <private/qqmlproxymetaobject_p.h>
#include <private/qqmldirparser_p.h>
+#include <private/qqmlmetaobject_p.h>
+#include <private/qqmlproxymetaobject_p.h>
+#include <private/qqmltype_p.h>
+#include <private/qtqmlglobal_p.h>
QT_BEGIN_NAMESPACE
@@ -63,91 +28,96 @@ class QRecursiveMutex;
class QQmlError;
class QQmlValueType;
-namespace QV4 { class ExecutableCompilationUnit; }
+namespace QV4 {
+namespace CompiledData {
+struct CompilationUnit;
+}
+}
-struct CompositeMetaTypeIds
+class Q_QML_EXPORT QQmlMetaType
{
-private:
- int *refCount = nullptr;
- void deref();
- void ref()
- {
- Q_ASSERT(refCount);
- ++*refCount;
- }
-public:
- CompositeMetaTypeIds() = default;
- CompositeMetaTypeIds(QMetaType id, QMetaType listId) : id(id), listId(listId) {}
- CompositeMetaTypeIds(const CompositeMetaTypeIds &other)
- : refCount(other.refCount), id(other.id), listId(other.listId)
- {
- if (refCount)
- ref();
- }
- CompositeMetaTypeIds(CompositeMetaTypeIds &&other)
- : refCount(other.refCount), id(other.id), listId(other.listId)
- {
- other.refCount = nullptr;
- }
- CompositeMetaTypeIds &operator=(const CompositeMetaTypeIds &other)
- {
- if (refCount)
- deref();
- refCount = other.refCount;
- id = other.id;
- listId = other.listId;
- if (refCount)
- ref();
- return *this;
- }
- CompositeMetaTypeIds &operator=(CompositeMetaTypeIds &&other)
- {
- if (refCount)
- deref();
- refCount = other.refCount;
- id = other.id;
- listId = other.listId;
- other.refCount = nullptr;
- return *this;
- }
- ~CompositeMetaTypeIds();
- static CompositeMetaTypeIds fromCompositeName(const QByteArray &name);
-public:
- QMetaType id;
- QMetaType listId;
- bool isValid() const { return id.isValid() && listId.isValid(); }
-};
-
-class Q_QML_PRIVATE_EXPORT QQmlMetaType
-{
- friend struct CompositeMetaTypeIds;
- static CompositeMetaTypeIds registerInternalCompositeType(const QByteArray &className);
- static void unregisterInternalCompositeType(const CompositeMetaTypeIds &typeIds);
+ friend class QQmlDesignerMetaObject;
public:
+
enum class RegistrationResult {
Success,
Failure,
NoRegistrationFunction
};
+ static QUrl inlineComponentUrl(const QUrl &baseUrl, const QString &name)
+ {
+ QUrl icUrl = baseUrl;
+ icUrl.setFragment(name);
+ return icUrl;
+ }
+
+ static bool equalBaseUrls(const QUrl &aUrl, const QUrl &bUrl)
+ {
+ // Everything but fragment has to match
+ return aUrl.port() == bUrl.port()
+ && aUrl.scheme() == bUrl.scheme()
+ && aUrl.userName() == bUrl.userName()
+ && aUrl.password() == bUrl.password()
+ && aUrl.host() == bUrl.host()
+ && aUrl.path() == bUrl.path()
+ && aUrl.query() == bUrl.query();
+ }
+
+ enum CompositeTypeLookupMode {
+ NonSingleton,
+ Singleton,
+ };
+
+ static QQmlType findCompositeType(
+ const QUrl &url,
+ const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &compilationUnit,
+ CompositeTypeLookupMode mode = NonSingleton);
+ static QQmlType findInlineComponentType(
+ const QUrl &url,
+ const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &compilationUnit);
+ static QQmlType findInlineComponentType(
+ const QUrl &baseUrl, const QString &name,
+ const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &compilationUnit)
+ {
+ return findInlineComponentType(inlineComponentUrl(baseUrl, name), compilationUnit);
+ }
+
+ static void unregisterInternalCompositeType(QMetaType metaType, QMetaType listMetaType);
static QQmlType registerType(const QQmlPrivate::RegisterType &type);
static QQmlType registerInterface(const QQmlPrivate::RegisterInterface &type);
- static QQmlType registerSingletonType(const QQmlPrivate::RegisterSingletonType &type);
- static QQmlType registerCompositeSingletonType(const QQmlPrivate::RegisterCompositeSingletonType &type);
+ static QQmlType registerSingletonType(
+ const QQmlPrivate::RegisterSingletonType &type,
+ const QQmlType::SingletonInstanceInfo::ConstPtr &siinfo);
+ static QQmlType registerCompositeSingletonType(
+ const QQmlPrivate::RegisterCompositeSingletonType &type,
+ const QQmlType::SingletonInstanceInfo::ConstPtr &siinfo);
static QQmlType registerCompositeType(const QQmlPrivate::RegisterCompositeType &type);
static RegistrationResult registerPluginTypes(QObject *instance, const QString &basePath,
const QString &uri, const QString &typeNamespace,
QTypeRevision version, QList<QQmlError> *errors);
+
static QQmlType typeForUrl(const QString &urlString, const QHashedStringRef& typeName,
- bool isCompositeSingleton, QList<QQmlError> *errors,
+ CompositeTypeLookupMode mode, QList<QQmlError> *errors,
QTypeRevision version = QTypeRevision());
+ static QQmlType fetchOrCreateInlineComponentTypeForUrl(const QUrl &url);
+ static QQmlType inlineComponentType(const QQmlType &outerType, const QString &name)
+ {
+ return outerType.isComposite()
+ ? fetchOrCreateInlineComponentTypeForUrl(
+ inlineComponentUrl(outerType.sourceUrl(), name))
+ : QQmlType();
+ }
+
static void unregisterType(int type);
+ static void registerMetaObjectForType(const QMetaObject *metaobject, QQmlTypePrivate *type);
+
static void registerModule(const char *uri, QTypeRevision version);
static bool protectModule(const QString &uri, QTypeRevision version,
- bool protectAllVersions = false);
+ bool weakProtectAllVersions = false);
static void registerModuleImport(const QString &uri, QTypeRevision version,
const QQmlDirParser::Import &import);
@@ -164,21 +134,31 @@ public:
static QList<QQmlType> qmlSingletonTypes();
static QList<QQmlType> qmlAllTypes();
- enum class TypeIdCategory {
- MetaType,
- QmlType
- };
-
static QQmlType qmlType(const QString &qualifiedName, QTypeRevision version);
static QQmlType qmlType(const QHashedStringRef &name, const QHashedStringRef &module, QTypeRevision version);
static QQmlType qmlType(const QMetaObject *);
static QQmlType qmlType(const QMetaObject *metaObject, const QHashedStringRef &module, QTypeRevision version);
- static QQmlType qmlType(int typeId, TypeIdCategory category = TypeIdCategory::MetaType);
+ static QQmlType qmlTypeById(int qmlTypeId);
+
+ static QQmlType qmlType(QMetaType metaType);
+ static QQmlType qmlListType(QMetaType metaType);
+
static QQmlType qmlType(const QUrl &unNormalizedUrl, bool includeNonFileImports = false);
- static QQmlPropertyCache *propertyCache(const QMetaObject *metaObject,
- QTypeRevision version = QTypeRevision(), bool doRef = false);
- static QQmlPropertyCache *propertyCache(const QQmlType &type, QTypeRevision version);
+ static QQmlPropertyCache::ConstPtr propertyCache(
+ QObject *object, QTypeRevision version = QTypeRevision());
+ static QQmlPropertyCache::ConstPtr propertyCache(
+ const QMetaObject *metaObject, QTypeRevision version = QTypeRevision());
+ static QQmlPropertyCache::ConstPtr propertyCache(
+ const QQmlType &type, QTypeRevision version);
+
+ // These methods may be called from the loader thread
+ static QQmlMetaObject rawMetaObjectForType(QMetaType metaType);
+ static QQmlMetaObject metaObjectForType(QMetaType metaType);
+ static QQmlPropertyCache::ConstPtr propertyCacheForType(QMetaType metaType);
+ static QQmlPropertyCache::ConstPtr rawPropertyCacheForType(QMetaType metaType);
+ static QQmlPropertyCache::ConstPtr rawPropertyCacheForType(
+ QMetaType metaType, QTypeRevision version);
static void freeUnusedTypesAndCaches();
@@ -189,19 +169,15 @@ public:
static QObject *toQObject(const QVariant &, bool *ok = nullptr);
- static int listType(int);
+ static QMetaType listValueType(QMetaType type);
static QQmlAttachedPropertiesFunc attachedPropertiesFunc(QQmlEnginePrivate *,
const QMetaObject *);
- static bool isInterface(int);
- static const char *interfaceIId(int);
- static bool isList(int);
-
- typedef QVariant (*StringConverter)(const QString &);
- static void registerCustomStringConverter(int, StringConverter);
- static StringConverter customStringConverter(int);
+ static bool isInterface(QMetaType type);
+ static const char *interfaceIId(QMetaType type);
+ static bool isList(QMetaType type);
static QTypeRevision latestModuleVersion(const QString &uri);
- static bool isLockedModule(const QString &uri, QTypeRevision version);
+ static bool isStronglyLockedModule(const QString &uri, QTypeRevision version);
static QTypeRevision matchingModuleVersion(const QString &module, QTypeRevision version);
static QQmlTypeModule *typeModule(const QString &uri, QTypeRevision version);
@@ -210,17 +186,18 @@ public:
enum class CachedUnitLookupError {
NoError,
NoUnitFound,
- VersionMismatch
+ VersionMismatch,
+ NotFullyTyped
};
- static const QQmlPrivate::CachedQmlUnit *findCachedCompilationUnit(const QUrl &uri, CachedUnitLookupError *status);
+ enum CacheMode { RejectAll, AcceptUntyped, RequireFullyTyped };
+ static const QQmlPrivate::CachedQmlUnit *findCachedCompilationUnit(
+ const QUrl &uri, CacheMode mode, CachedUnitLookupError *status);
// used by tst_qqmlcachegen.cpp
static void prependCachedUnitLookupFunction(QQmlPrivate::QmlUnitCacheLookupFunction handler);
static void removeCachedUnitLookupFunction(QQmlPrivate::QmlUnitCacheLookupFunction handler);
- static QRecursiveMutex *typeRegistrationLock();
-
static QString prettyTypeName(const QObject *object);
template <typename QQmlTypeContainer>
@@ -235,6 +212,21 @@ public:
}
}
+ template <typename InlineComponentContainer>
+ static void removeFromInlineComponents(
+ InlineComponentContainer &container, const QQmlTypePrivate *reference)
+ {
+ const QUrl referenceUrl = QQmlType(reference).sourceUrl();
+ for (auto it = container.begin(), end = container.end(); it != end;) {
+ if (equalBaseUrls(it.key(), referenceUrl))
+ it = container.erase(it);
+ else
+ ++it;
+ }
+ }
+
+ static void registerTypeAlias(int typeId, const QString &name);
+
static int registerAutoParentFunction(const QQmlPrivate::RegisterAutoParent &autoparent);
static void unregisterAutoParentFunction(const QQmlPrivate::AutoParentFunction &function);
@@ -249,23 +241,119 @@ public:
const QMetaObject *baseMetaObject,
QMetaObject *lastMetaObject);
+ enum ClonePolicy {
+ CloneAll, // default
+ CloneEnumsOnly, // skip properties and methods
+ };
static void clone(QMetaObjectBuilder &builder, const QMetaObject *mo,
- const QMetaObject *ignoreStart, const QMetaObject *ignoreEnd);
+ const QMetaObject *ignoreStart, const QMetaObject *ignoreEnd,
+ ClonePolicy policy);
static void qmlInsertModuleRegistration(const QString &uri, void (*registerFunction)());
static void qmlRemoveModuleRegistration(const QString &uri);
static bool qmlRegisterModuleTypes(const QString &uri);
- static int qmlRegisteredListTypeCount();
-
static bool isValueType(QMetaType type);
static QQmlValueType *valueType(QMetaType metaType);
- static const QMetaObject *metaObjectForMetaType(QMetaType type);
+ static const QMetaObject *metaObjectForValueType(QMetaType type);
+
+ static QQmlPropertyCache::ConstPtr findPropertyCacheInCompositeTypes(QMetaType t);
+ static void registerInternalCompositeType(
+ const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &compilationUnit);
+ static void unregisterInternalCompositeType(
+ const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &compilationUnit);
+ static int countInternalCompositeTypeSelfReferences(
+ const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &compilationUnit);
+ static QQmlRefPointer<QV4::CompiledData::CompilationUnit> obtainCompilationUnit(
+ QMetaType type);
+ static QQmlRefPointer<QV4::CompiledData::CompilationUnit> obtainCompilationUnit(
+ const QUrl &url);
};
Q_DECLARE_TYPEINFO(QQmlMetaType, Q_RELOCATABLE_TYPE);
+// used in QQmlListMetaType to tag the metatpye
+inline const QMetaObject *dynamicQmlListMarker(const QtPrivate::QMetaTypeInterface *) {
+ return nullptr;
+};
+
+inline const QMetaObject *dynamicQmlMetaObject(const QtPrivate::QMetaTypeInterface *iface) {
+ return QQmlMetaType::metaObjectForType(QMetaType(iface)).metaObject();
+};
+
+// metatype interface for composite QML types
+struct QQmlMetaTypeInterface : QtPrivate::QMetaTypeInterface
+{
+ const QByteArray name;
+ QQmlMetaTypeInterface(const QByteArray &name)
+ : QMetaTypeInterface {
+ /*.revision=*/ QMetaTypeInterface::CurrentRevision,
+ /*.alignment=*/ alignof(QObject *),
+ /*.size=*/ sizeof(QObject *),
+ /*.flags=*/ QtPrivate::QMetaTypeTypeFlags<QObject *>::Flags,
+ /*.typeId=*/ 0,
+ /*.metaObjectFn=*/ &dynamicQmlMetaObject,
+ /*.name=*/ name.constData(),
+ /*.defaultCtr=*/ [](const QMetaTypeInterface *, void *addr) {
+ *static_cast<QObject **>(addr) = nullptr;
+ },
+ /*.copyCtr=*/ [](const QMetaTypeInterface *, void *addr, const void *other) {
+ *static_cast<QObject **>(addr) = *static_cast<QObject *const *>(other);
+ },
+ /*.moveCtr=*/ [](const QMetaTypeInterface *, void *addr, void *other) {
+ *static_cast<QObject **>(addr) = *static_cast<QObject **>(other);
+ },
+ /*.dtor=*/ [](const QMetaTypeInterface *, void *) {},
+ /*.equals*/ nullptr,
+ /*.lessThan*/ nullptr,
+ /*.debugStream=*/ nullptr,
+ /*.dataStreamOut=*/ nullptr,
+ /*.dataStreamIn=*/ nullptr,
+ /*.legacyRegisterOp=*/ nullptr
+ }
+ , name(name) { }
+};
+
+// metatype for qml list types
+struct QQmlListMetaTypeInterface : QtPrivate::QMetaTypeInterface
+{
+ const QByteArray name;
+ // if this interface is for list<type>; valueType stores the interface for type
+ const QtPrivate::QMetaTypeInterface *valueType;
+ QQmlListMetaTypeInterface(const QByteArray &name, const QtPrivate::QMetaTypeInterface *valueType)
+ : QMetaTypeInterface {
+ /*.revision=*/ QMetaTypeInterface::CurrentRevision,
+ /*.alignment=*/ alignof(QQmlListProperty<QObject>),
+ /*.size=*/ sizeof(QQmlListProperty<QObject>),
+ /*.flags=*/ QtPrivate::QMetaTypeTypeFlags<QQmlListProperty<QObject>>::Flags,
+ /*.typeId=*/ 0,
+ /*.metaObjectFn=*/ &dynamicQmlListMarker,
+ /*.name=*/ name.constData(),
+ /*.defaultCtr=*/ [](const QMetaTypeInterface *, void *addr) {
+ new (addr) QQmlListProperty<QObject> ();
+ },
+ /*.copyCtr=*/ [](const QMetaTypeInterface *, void *addr, const void *other) {
+ new (addr) QQmlListProperty<QObject>(
+ *static_cast<const QQmlListProperty<QObject> *>(other));
+ },
+ /*.moveCtr=*/ [](const QMetaTypeInterface *, void *addr, void *other) {
+ new (addr) QQmlListProperty<QObject>(
+ std::move(*static_cast<QQmlListProperty<QObject> *>(other)));
+ },
+ /*.dtor=*/ [](const QMetaTypeInterface *, void *addr) {
+ static_cast<QQmlListProperty<QObject> *>(addr)->~QQmlListProperty<QObject>();
+ },
+ /*.equals*/ nullptr,
+ /*.lessThan*/ nullptr,
+ /*.debugStream=*/ nullptr,
+ /*.dataStreamOut=*/ nullptr,
+ /*.dataStreamIn=*/ nullptr,
+ /*.legacyRegisterOp=*/ nullptr
+ }
+ , name(name), valueType(valueType) { }
+};
+
QT_END_NAMESPACE
#endif // QQMLMETATYPE_P_H
diff --git a/src/qml/qml/qqmlmetatypedata.cpp b/src/qml/qml/qqmlmetatypedata.cpp
index 4be26acdc6..bc7e762e53 100644
--- a/src/qml/qml/qqmlmetatypedata.cpp
+++ b/src/qml/qml/qqmlmetatypedata.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 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$
-**
-****************************************************************************/
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qqmlmetatypedata_p.h"
@@ -51,9 +15,14 @@ QQmlMetaTypeData::QQmlMetaTypeData()
QQmlMetaTypeData::~QQmlMetaTypeData()
{
- for (auto it = propertyCaches.begin(), end = propertyCaches.end(); it != end; ++it)
- (*it)->release();
+ {
+ // Unregister all remaining composite types.
+ // Avoid deletion recursion (via QQmlTypePrivate dtor) by moving them out of the way first.
+ CompositeTypes emptyComposites;
+ emptyComposites.swap(compositeTypes);
+ }
+ propertyCaches.clear();
// Do this before the attached properties disappear.
types.clear();
undeletableTypes.clear();
@@ -63,7 +32,7 @@ QQmlMetaTypeData::~QQmlMetaTypeData()
// This expects a "fresh" QQmlTypePrivate and adopts its reference.
void QQmlMetaTypeData::registerType(QQmlTypePrivate *priv)
{
- for (int i = 0; i < types.count(); ++i) {
+ for (int i = 0; i < types.size(); ++i) {
if (!types.at(i).isValid()) {
types[i] = QQmlType(priv);
priv->index = i;
@@ -72,7 +41,7 @@ void QQmlMetaTypeData::registerType(QQmlTypePrivate *priv)
}
}
types.append(QQmlType(priv));
- priv->index = types.count() - 1;
+ priv->index = types.size() - 1;
priv->release();
}
@@ -118,48 +87,53 @@ bool QQmlMetaTypeData::registerModuleTypes(const QString &uri)
return false;
}
-QQmlPropertyCache *QQmlMetaTypeData::propertyCacheForVersion(int index, QTypeRevision version) const
+QQmlPropertyCache::ConstPtr QQmlMetaTypeData::propertyCacheForVersion(
+ int index, QTypeRevision version) const
{
- return (index < typePropertyCaches.length())
- ? typePropertyCaches.at(index).value(version).data()
- : nullptr;
+ return (index < typePropertyCaches.size())
+ ? typePropertyCaches.at(index).value(version)
+ : QQmlPropertyCache::ConstPtr();
}
void QQmlMetaTypeData::setPropertyCacheForVersion(int index, QTypeRevision version,
- QQmlPropertyCache *cache)
+ const QQmlPropertyCache::ConstPtr &cache)
{
- if (index >= typePropertyCaches.length())
+ if (index >= typePropertyCaches.size())
typePropertyCaches.resize(index + 1);
typePropertyCaches[index][version] = cache;
}
void QQmlMetaTypeData::clearPropertyCachesForVersion(int index)
{
- if (index < typePropertyCaches.length())
+ if (index < typePropertyCaches.size())
typePropertyCaches[index].clear();
}
-QQmlRefPointer<QQmlPropertyCache> QQmlMetaTypeData::propertyCache(const QMetaObject *metaObject, QTypeRevision version)
+QQmlPropertyCache::ConstPtr QQmlMetaTypeData::propertyCache(
+ const QMetaObject *metaObject, QTypeRevision version)
{
- if (QQmlPropertyCache *rv = propertyCaches.value(metaObject))
+ if (QQmlPropertyCache::ConstPtr rv = propertyCaches.value(metaObject))
return rv;
- if (!metaObject->superClass()) {
- QQmlPropertyCache *rv = new QQmlPropertyCache(metaObject);
+ QQmlPropertyCache::ConstPtr rv;
+ if (const QMetaObject *superMeta = metaObject->superClass())
+ rv = propertyCache(superMeta, version)->copyAndAppend(metaObject, version);
+ else
+ rv = QQmlPropertyCache::createStandalone(metaObject);
+
+ const auto *mop = reinterpret_cast<const QMetaObjectPrivate *>(metaObject->d.data);
+ if (!(mop->flags & DynamicMetaObject))
propertyCaches.insert(metaObject, rv);
- return rv;
- }
- auto super = propertyCache(metaObject->superClass(), version);
- QQmlPropertyCache *rv = super->copyAndAppend(metaObject, version);
- propertyCaches.insert(metaObject, rv);
+
return rv;
}
-QQmlPropertyCache *QQmlMetaTypeData::propertyCache(const QQmlType &type, QTypeRevision version)
+QQmlPropertyCache::ConstPtr QQmlMetaTypeData::propertyCache(
+ const QQmlType &type, QTypeRevision version)
{
Q_ASSERT(type.isValid());
- if (QQmlPropertyCache *pc = propertyCacheForVersion(type.index(), version))
+ if (auto pc = propertyCacheForVersion(type.index(), version))
return pc;
QVector<QQmlType> types;
@@ -167,13 +141,14 @@ QQmlPropertyCache *QQmlMetaTypeData::propertyCache(const QQmlType &type, QTypeRe
quint8 maxMinorVersion = 0;
const QMetaObject *metaObject = type.metaObject();
+ Q_ASSERT(metaObject);
const QTypeRevision combinedVersion = version.hasMajorVersion()
? version
: (version.hasMinorVersion()
? QTypeRevision::fromVersion(type.version().majorVersion(),
version.minorVersion())
- : type.version());
+ : QTypeRevision::fromMajorVersion(type.version().majorVersion()));
while (metaObject) {
QQmlType t = QQmlMetaType::qmlType(metaObject, type.module(), combinedVersion);
@@ -189,32 +164,28 @@ QQmlPropertyCache *QQmlMetaTypeData::propertyCache(const QQmlType &type, QTypeRe
const QTypeRevision maxVersion = QTypeRevision::fromVersion(combinedVersion.majorVersion(),
maxMinorVersion);
- if (QQmlPropertyCache *pc = propertyCacheForVersion(type.index(), maxVersion)) {
+ if (auto pc = propertyCacheForVersion(type.index(), maxVersion)) {
setPropertyCacheForVersion(type.index(), maxVersion, pc);
return pc;
}
- QQmlPropertyCache *raw = propertyCache(type.metaObject(), combinedVersion).data();
-
- bool hasCopied = false;
+ QQmlPropertyCache::ConstPtr raw = propertyCache(type.metaObject(), combinedVersion);
+ QQmlPropertyCache::Ptr copied;
- for (int ii = 0; ii < types.count(); ++ii) {
+ for (int ii = 0; ii < types.size(); ++ii) {
const QQmlType &currentType = types.at(ii);
if (!currentType.isValid())
continue;
QTypeRevision rev = currentType.metaObjectRevision();
- int moIndex = types.count() - 1 - ii;
+ int moIndex = types.size() - 1 - ii;
if (raw->allowedRevision(moIndex) != rev) {
- if (!hasCopied) {
- // TODO: The copy should be mutable, and the original should be const
- // Considering this, the setAllowedRevision() below does not violate
- // the immutability of already published property caches.
- raw = raw->copy();
- hasCopied = true;
+ if (copied.isNull()) {
+ copied = raw->copy();
+ raw = copied;
}
- raw->setAllowedRevision(moIndex, rev);
+ copied->setAllowedRevision(moIndex, rev);
}
}
@@ -240,12 +211,12 @@ QQmlPropertyCache *QQmlMetaTypeData::propertyCache(const QQmlType &type, QTypeRe
!overloadError && iter != raw->stringCache.end();
++iter) {
- QQmlPropertyData *d = *iter;
+ const QQmlPropertyData *d = *iter;
if (raw->isAllowedInRevision(d))
continue; // Not excluded - no problems
// check that a regular "name" overload isn't happening
- QQmlPropertyData *current = d;
+ const QQmlPropertyData *current = d;
while (!overloadError && current) {
current = d->overrideData(current);
if (current && raw->isAllowedInRevision(current))
@@ -263,13 +234,29 @@ QQmlPropertyCache *QQmlMetaTypeData::propertyCache(const QQmlType &type, QTypeRe
setPropertyCacheForVersion(type.index(), version, raw);
- if (hasCopied)
- raw->release();
-
if (version != maxVersion)
setPropertyCacheForVersion(type.index(), maxVersion, raw);
return raw;
}
+static QQmlPropertyCache::ConstPtr propertyCacheForPotentialInlineComponentType(
+ QMetaType t, const QQmlMetaTypeData::CompositeTypes::const_iterator &iter) {
+ if (t != (*iter)->metaType()) {
+ // this is an inline component, and what we have in the iterator is currently the parent compilation unit
+ for (auto &&icDatum: (*iter)->inlineComponentData)
+ if (icDatum.qmlType.typeId() == t)
+ return (*iter)->propertyCaches.at(icDatum.objectIndex);
+ }
+ return (*iter)->rootPropertyCache();
+}
+
+QQmlPropertyCache::ConstPtr QQmlMetaTypeData::findPropertyCacheInCompositeTypes(QMetaType t) const
+{
+ auto iter = compositeTypes.constFind(t.iface());
+ return (iter == compositeTypes.constEnd())
+ ? QQmlPropertyCache::ConstPtr()
+ : propertyCacheForPotentialInlineComponentType(t, iter);
+}
+
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlmetatypedata_p.h b/src/qml/qml/qqmlmetatypedata_p.h
index 9719ec1bb4..8863bd1089 100644
--- a/src/qml/qml/qqmlmetatypedata_p.h
+++ b/src/qml/qml/qqmlmetatypedata_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 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$
-**
-****************************************************************************/
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLMETATYPEDATA_P_H
#define QQMLMETATYPEDATA_P_H
@@ -72,10 +36,10 @@ struct QQmlMetaTypeData
typedef QHash<int, QQmlTypePrivate *> Ids;
Ids idToType;
- using Names = QMultiHash<QHashedString, QQmlTypePrivate *>;
+ using Names = QMultiHash<QHashedString, const QQmlTypePrivate *>;
Names nameToType;
- typedef QHash<QUrl, QQmlTypePrivate *> Files; //For file imported composite types only
+ typedef QHash<QUrl, const QQmlTypePrivate *> Files; //For file imported composite types only
Files urlToType;
Files urlToNonFileImportType; // For non-file imported composite and composite
// singleton types. This way we can locate any
@@ -83,11 +47,14 @@ struct QQmlMetaTypeData
// a module via QQmlPrivate::RegisterCompositeType
typedef QMultiHash<const QMetaObject *, QQmlTypePrivate *> MetaObjects;
MetaObjects metaObjectToType;
- typedef QHash<int, QQmlMetaType::StringConverter> StringConverters;
- StringConverters stringConverters;
- QVector<QHash<QTypeRevision, QQmlRefPointer<QQmlPropertyCache>>> typePropertyCaches;
+ QVector<QHash<QTypeRevision, QQmlPropertyCache::ConstPtr>> typePropertyCaches;
QHash<int, QQmlValueType *> metaTypeToValueType;
+ using CompositeTypes = QHash<const QtPrivate::QMetaTypeInterface *,
+ QQmlRefPointer<QV4::CompiledData::CompilationUnit>>;
+ CompositeTypes compositeTypes;
+ QHash<QUrl, QQmlType> inlineComponentTypes;
+
struct VersionedUri {
VersionedUri() = default;
VersionedUri(const QString &uri, QTypeRevision version)
@@ -131,16 +98,16 @@ struct QQmlMetaTypeData
QList<QQmlPrivate::AutoParentFunction> parentFunctions;
QVector<QQmlPrivate::QmlUnitCacheLookupFunction> lookupCachedQmlUnit;
- QHash<int, int> qmlLists;
-
- QHash<const QMetaObject *, QQmlPropertyCache *> propertyCaches;
+ QHash<const QMetaObject *, QQmlPropertyCache::ConstPtr> propertyCaches;
- QQmlPropertyCache *propertyCacheForVersion(int index, QTypeRevision version) const;
- void setPropertyCacheForVersion(int index, QTypeRevision version, QQmlPropertyCache *cache);
+ QQmlPropertyCache::ConstPtr propertyCacheForVersion(int index, QTypeRevision version) const;
+ void setPropertyCacheForVersion(
+ int index, QTypeRevision version, const QQmlPropertyCache::ConstPtr &cache);
void clearPropertyCachesForVersion(int index);
- QQmlRefPointer<QQmlPropertyCache> propertyCache(const QMetaObject *metaObject, QTypeRevision version);
- QQmlPropertyCache *propertyCache(const QQmlType &type, QTypeRevision version);
+ QQmlPropertyCache::ConstPtr propertyCache(const QMetaObject *metaObject, QTypeRevision version);
+ QQmlPropertyCache::ConstPtr propertyCache(const QQmlType &type, QTypeRevision version);
+ QQmlPropertyCache::ConstPtr findPropertyCacheInCompositeTypes(QMetaType t) const;
void setTypeRegistrationFailures(QStringList *failures)
{
diff --git a/src/qml/qml/qqmlmoduleregistration.cpp b/src/qml/qml/qqmlmoduleregistration.cpp
index 422a5c0551..a6d7e879b3 100644
--- a/src/qml/qml/qqmlmoduleregistration.cpp
+++ b/src/qml/qml/qqmlmoduleregistration.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 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$
-**
-****************************************************************************/
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <QtQml/private/qqmlmetatype_p.h>
#include <QtQml/qqmlmoduleregistration.h>
diff --git a/src/qml/qml/qqmlmoduleregistration.h b/src/qml/qml/qqmlmoduleregistration.h
index 3db535faa0..b7a0da9cb9 100644
--- a/src/qml/qml/qqmlmoduleregistration.h
+++ b/src/qml/qml/qqmlmoduleregistration.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 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$
-**
-****************************************************************************/
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLMODULEREGISTRATION_H
#define QQMLMODULEREGISTRATION_H
diff --git a/src/qml/qml/qqmlnetworkaccessmanagerfactory.cpp b/src/qml/qml/qqmlnetworkaccessmanagerfactory.cpp
index c14a91c1fa..ed4fd34073 100644
--- a/src/qml/qml/qqmlnetworkaccessmanagerfactory.cpp
+++ b/src/qml/qml/qqmlnetworkaccessmanagerfactory.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qqmlnetworkaccessmanagerfactory.h"
@@ -54,9 +18,20 @@ QT_BEGIN_NAMESPACE
with custom QNetworkAccessManager instances with specialized caching,
proxy and cookies support.
+ \list
+ \li The QNetworkDiskCache can be used as a request cache with \l {QNetworkDiskCache}.
+ \li Using \l {QNetworkProxy}, traffic sent by the QNetworkAccessManager can be tunnelled through a proxy.
+ \li Cookies can be saved for future requests by adding a \l {QNetworkCookieJar}.
+ \endlist
+
To implement a factory, subclass QQmlNetworkAccessManagerFactory and
implement the virtual create() method, then assign it to the relevant QML
- engine using QQmlEngine::setNetworkAccessManagerFactory().
+ engine using QQmlEngine::setNetworkAccessManagerFactory(). For instance, the QNetworkAccessManager
+ objects created by the following snippet will cache requests.
+ \snippet code/src_network_access_qnetworkaccessmanager.cpp 0
+
+ The factory can then be passed to the QML engine so it can instantiate the QNetworkAccessManager with the custom behavior.
+ \snippet code/src_network_access_qnetworkaccessmanager.cpp 1
Note the QML engine may create QNetworkAccessManager instances
from multiple threads. Because of this, the implementation of the create()
@@ -80,7 +55,7 @@ QT_BEGIN_NAMESPACE
For more information about signals and threads, see
\l {Threads and QObjects} and \l {Signals and Slots Across Threads}.
- \sa {C++ Extensions: Network Access Manager Factory Example}{Network Access Manager Factory Example}
+ \sa QNetworkDiskCache
*/
/*!
diff --git a/src/qml/qml/qqmlnetworkaccessmanagerfactory.h b/src/qml/qml/qqmlnetworkaccessmanagerfactory.h
index 57dec1da29..ea3a410ef6 100644
--- a/src/qml/qml/qqmlnetworkaccessmanagerfactory.h
+++ b/src/qml/qml/qqmlnetworkaccessmanagerfactory.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLNETWORKACCESSMANAGERFACTORY_H
#define QQMLNETWORKACCESSMANAGERFACTORY_H
diff --git a/src/qml/qml/qqmlnotifier.cpp b/src/qml/qml/qqmlnotifier.cpp
index df3731684a..e7b8799f82 100644
--- a/src/qml/qml/qqmlnotifier.cpp
+++ b/src/qml/qml/qqmlnotifier.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qqmlnotifier_p.h"
#include "qqmlproperty_p.h"
@@ -49,12 +13,14 @@ typedef void (*Callback)(QQmlNotifierEndpoint *, void **);
void QQmlBoundSignal_callback(QQmlNotifierEndpoint *, void **);
void QQmlJavaScriptExpressionGuard_callback(QQmlNotifierEndpoint *, void **);
void QQmlVMEMetaObjectEndpoint_callback(QQmlNotifierEndpoint *, void **);
+void QQmlPropertyGuard_callback(QQmlNotifierEndpoint *, void **);
static Callback QQmlNotifier_callbacks[] = {
nullptr,
QQmlBoundSignal_callback,
QQmlJavaScriptExpressionGuard_callback,
- QQmlVMEMetaObjectEndpoint_callback
+ QQmlVMEMetaObjectEndpoint_callback,
+ QQmlPropertyGuard_callback
};
namespace {
@@ -123,10 +89,10 @@ void QQmlNotifierEndpoint::connect(QObject *source, int sourceSignal, QQmlEngine
QString sourceName;
QDebug(&sourceName) << source;
- sourceName = sourceName.left(sourceName.length() - 1);
+ sourceName = sourceName.left(sourceName.size() - 1);
QString engineName;
QDebug(&engineName).nospace() << engine;
- engineName = engineName.left(engineName.length() - 1);
+ engineName = engineName.left(engineName.size() - 1);
qFatal("QQmlEngine: Illegal attempt to connect to %s that is in"
" a different thread than the QML engine %s.", qPrintable(sourceName),
diff --git a/src/qml/qml/qqmlnotifier_p.h b/src/qml/qml/qqmlnotifier_p.h
index 67d80a9d86..0ec7d5fef2 100644
--- a/src/qml/qml/qqmlnotifier_p.h
+++ b/src/qml/qml/qqmlnotifier_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLNOTIFIER_P_H
#define QQMLNOTIFIER_P_H
@@ -51,14 +15,15 @@
// We mean it.
//
-#include "qqmldata_p.h"
#include <QtCore/qmetaobject.h>
#include <private/qmetaobject_p.h>
+#include <private/qtqmlglobal_p.h>
QT_BEGIN_NAMESPACE
class QQmlNotifierEndpoint;
-class Q_QML_PRIVATE_EXPORT QQmlNotifier
+class QQmlData;
+class Q_QML_EXPORT QQmlNotifier
{
public:
inline QQmlNotifier();
@@ -90,7 +55,8 @@ public:
None = 0,
QQmlBoundSignal = 1,
QQmlJavaScriptExpressionGuard = 2,
- QQmlVMEMetaObjectEndpoint = 3
+ QQmlVMEMetaObjectEndpoint = 3,
+ QQmlPropertyGuard = 4,
};
inline QQmlNotifierEndpoint(Callback callback);
@@ -206,12 +172,15 @@ void QQmlNotifierEndpoint::disconnect()
if (next) next->prev = prev;
if (prev) *prev = next;
- if (sourceSignal != -1) {
+ if (sourceSignal != -1 && needsConnectNotify) {
QObject * const obj = senderAsObject();
Q_ASSERT(obj);
QObjectPrivate * const priv = QObjectPrivate::get(obj);
- if (needsConnectNotify)
- priv->disconnectNotify(QMetaObjectPrivate::signal(obj->metaObject(), sourceSignal));
+
+ // In some degenerate cases an object being destructed might be unable
+ // to produce a metaObject(). Therefore we check here.
+ if (const QMetaObject *mo = obj->metaObject())
+ priv->disconnectNotify(QMetaObjectPrivate::signal(mo, sourceSignal));
}
setSender(0x0);
diff --git a/src/qml/qml/qqmlobjectcreator.cpp b/src/qml/qml/qqmlobjectcreator.cpp
index 10b1304b67..a9b9140390 100644
--- a/src/qml/qml/qqmlobjectcreator.cpp
+++ b/src/qml/qml/qqmlobjectcreator.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the tools applications 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qqmlobjectcreator_p.h"
@@ -61,6 +25,8 @@
#include <private/qv4generatorobject_p.h>
#include <private/qv4resolvedtypereference_p.h>
#include <private/qqmlpropertybinding_p.h>
+#include <private/qqmlanybinding_p.h>
+#include <QtQml/private/qqmlvme_p.h>
#include <QScopedValueRollback>
@@ -72,6 +38,19 @@ Q_LOGGING_CATEGORY(lcQmlDefaultMethod, "qt.qml.defaultmethod")
QT_USE_NAMESPACE
+Q_TRACE_PREFIX(qtqml,
+"namespace QV4 {" \
+"struct ExecutionEngine;" \
+"class ExecutableCompilationUnit;" \
+"namespace CompiledData {" \
+"struct Object;" \
+"}}" \
+"class QQmlEngine;"
+)
+
+Q_TRACE_POINT(qtqml, QQmlObjectCreator_createInstance_entry, const QV4::ExecutableCompilationUnit *compilationUnit, const QV4::CompiledData::Object *object, const QUrl &url)
+Q_TRACE_POINT(qtqml, QQmlObjectCreator_createInstance_exit, const QString &typeName)
+
QQmlObjectCreator::QQmlObjectCreator(
QQmlRefPointer<QQmlContextData> parentContext,
const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit,
@@ -79,9 +58,10 @@ QQmlObjectCreator::QQmlObjectCreator(
QQmlIncubatorPrivate *incubator)
: phase(Startup)
, compilationUnit(compilationUnit)
- , propertyCaches(&compilationUnit->propertyCaches)
- , sharedState(new QQmlObjectCreatorSharedState)
+ , propertyCaches(compilationUnit->propertyCachesPtr())
+ , sharedState(new QQmlObjectCreatorSharedState, QQmlRefPointer<QQmlObjectCreatorSharedState>::Adopt)
, topLevelCreator(true)
+ , isContextObject(true)
, incubator(incubator)
{
init(std::move(parentContext));
@@ -90,10 +70,10 @@ QQmlObjectCreator::QQmlObjectCreator(
sharedState->allCreatedBindings.allocate(compilationUnit->totalBindingsCount());
sharedState->allParserStatusCallbacks.allocate(compilationUnit->totalParserStatusCount());
sharedState->allCreatedObjects.allocate(compilationUnit->totalObjectCount());
- sharedState->allJavaScriptObjects = nullptr;
+ sharedState->allJavaScriptObjects = ObjectInCreationGCAnchorList();
sharedState->creationContext = creationContext;
- sharedState->rootContext = nullptr;
- sharedState->hadRequiredProperties = false;
+ sharedState->rootContext.reset();
+ sharedState->hadTopLevelRequiredProperties = false;
if (auto profiler = QQmlEnginePrivate::get(engine)->profiler) {
Q_QML_PROFILE_IF_ENABLED(QQmlProfilerDefinitions::ProfileCreating, profiler,
@@ -103,15 +83,15 @@ QQmlObjectCreator::QQmlObjectCreator(
}
}
-QQmlObjectCreator::QQmlObjectCreator(
- QQmlRefPointer<QQmlContextData> parentContext,
+QQmlObjectCreator::QQmlObjectCreator(QQmlRefPointer<QQmlContextData> parentContext,
const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit,
- QQmlObjectCreatorSharedState *inheritedSharedState)
+ QQmlObjectCreatorSharedState *inheritedSharedState, bool isContextObject)
: phase(Startup)
, compilationUnit(compilationUnit)
- , propertyCaches(&compilationUnit->propertyCaches)
+ , propertyCaches(compilationUnit->propertyCachesPtr())
, sharedState(inheritedSharedState)
, topLevelCreator(false)
+ , isContextObject(isContextObject)
, incubator(nullptr)
{
init(std::move(parentContext));
@@ -123,11 +103,12 @@ void QQmlObjectCreator::init(QQmlRefPointer<QQmlContextData> providedParentConte
engine = parentContext->engine();
v4 = engine->handle();
- if (compilationUnit && !compilationUnit->engine)
- compilationUnit->linkToEngine(v4);
+ Q_ASSERT(compilationUnit);
+ Q_ASSERT(compilationUnit->engine == v4);
+ if (!compilationUnit->runtimeStrings)
+ compilationUnit->populate();
qmlUnit = compilationUnit->unitData();
- context = nullptr;
_qobject = nullptr;
_scopeObject = nullptr;
_bindingTarget = nullptr;
@@ -135,7 +116,6 @@ void QQmlObjectCreator::init(QQmlRefPointer<QQmlContextData> providedParentConte
_compiledObject = nullptr;
_compiledObjectIndex = -1;
_ddata = nullptr;
- _propertyCache = nullptr;
_vmeMetaObject = nullptr;
_qmlContext = nullptr;
}
@@ -168,24 +148,38 @@ QObject *QQmlObjectCreator::create(int subComponentIndex, QObject *parent, QQmlI
phase = CreatingObjects;
int objectToCreate;
+ bool isComponentRoot = false; // either a "real" component of or an inline component
if (subComponentIndex == -1) {
objectToCreate = /*root object*/0;
+ isComponentRoot = true;
} else {
Q_ASSERT(subComponentIndex >= 0);
if (flags & CreationFlags::InlineComponent) {
+ if (compilationUnit->componentsAreBound()
+ && compilationUnit != parentContext->typeCompilationUnit()) {
+ recordError({}, tr("Cannot instantiate bound inline component in different file"));
+ phase = ObjectsCreated;
+ return nullptr;
+ }
objectToCreate = subComponentIndex;
+ isComponentRoot = true;
} else {
Q_ASSERT(flags & CreationFlags::NormalObject);
+ if (compilationUnit->componentsAreBound()
+ && sharedState->creationContext != parentContext) {
+ recordError({}, tr("Cannot instantiate bound component "
+ "outside its creation context"));
+ phase = ObjectsCreated;
+ return nullptr;
+ }
const QV4::CompiledData::Object *compObj = compilationUnit->objectAt(subComponentIndex);
objectToCreate = compObj->bindingTable()->value.objectIndex;
}
}
- context = QQmlContextData::createRefCounted(parentContext);
- context->setInternal(true);
- context->setImports(compilationUnit->typeNameCache);
- context->initFromTypeCompilationUnit(compilationUnit, subComponentIndex);
+ context = QQmlEnginePrivate::get(engine)->createInternalContext(
+ compilationUnit, parentContext, subComponentIndex, isComponentRoot);
if (!sharedState->rootContext) {
sharedState->rootContext = context;
@@ -195,19 +189,12 @@ QObject *QQmlObjectCreator::create(int subComponentIndex, QObject *parent, QQmlI
QV4::Scope scope(v4);
- Q_ASSERT(sharedState->allJavaScriptObjects || topLevelCreator);
+ Q_ASSERT(sharedState->allJavaScriptObjects.canTrack() || topLevelCreator);
if (topLevelCreator)
- sharedState->allJavaScriptObjects = scope.alloc(compilationUnit->totalObjectCount());
-
- if (subComponentIndex == -1 && compilationUnit->dependentScripts.count()) {
- QV4::ScopedObject scripts(scope, v4->newArrayObject(compilationUnit->dependentScripts.count()));
- context->setImportedScripts(QV4::PersistentValue(v4, scripts.asReturnedValue()));
- QV4::ScopedValue v(scope);
- for (int i = 0; i < compilationUnit->dependentScripts.count(); ++i) {
- QQmlRefPointer<QQmlScriptData> s = compilationUnit->dependentScripts.at(i);
- scripts->put(i, (v = s->scriptValueForContext(context)));
- }
- } else if (sharedState->creationContext) {
+ sharedState->allJavaScriptObjects = ObjectInCreationGCAnchorList(scope, compilationUnit->totalObjectCount());
+
+ if (!isComponentRoot && sharedState->creationContext) {
+ // otherwise QQmlEnginePrivate::createInternalContext() handles it
context->setImportedScripts(sharedState->creationContext->importedScripts());
}
@@ -219,7 +206,7 @@ QObject *QQmlObjectCreator::create(int subComponentIndex, QObject *parent, QQmlI
}
if (topLevelCreator)
- sharedState->allJavaScriptObjects = nullptr;
+ sharedState->allJavaScriptObjects = ObjectInCreationGCAnchorList();
phase = CreatingObjectsPhase2;
@@ -248,56 +235,27 @@ void QQmlObjectCreator::beginPopulateDeferred(const QQmlRefPointer<QQmlContextDa
sharedState->rootContext = newContext;
Q_ASSERT(topLevelCreator);
- Q_ASSERT(!sharedState->allJavaScriptObjects);
+ Q_ASSERT(!sharedState->allJavaScriptObjects.canTrack());
+ // FIXME (QTBUG-122956): allocating from the short lived scope does not make any sense
QV4::Scope valueScope(v4);
- sharedState->allJavaScriptObjects = valueScope.alloc(compilationUnit->totalObjectCount());
+ sharedState->allJavaScriptObjects = ObjectInCreationGCAnchorList(valueScope, compilationUnit->totalObjectCount());
}
void QQmlObjectCreator::populateDeferred(QObject *instance, int deferredIndex,
const QQmlPropertyPrivate *qmlProperty,
const QV4::CompiledData::Binding *binding)
{
- QQmlData *declarativeData = QQmlData::get(instance);
- QObject *bindingTarget = instance;
-
- QQmlRefPointer<QQmlPropertyCache> cache = declarativeData->propertyCache;
- QQmlVMEMetaObject *vmeMetaObject = QQmlVMEMetaObject::get(instance);
-
- QObject *scopeObject = instance;
- qSwap(_scopeObject, scopeObject);
-
- QV4::Scope valueScope(v4);
- QScopedValueRollback<QV4::Value*> jsObjectGuard(sharedState->allJavaScriptObjects,
- valueScope.alloc(compilationUnit->totalObjectCount()));
-
- Q_ASSERT(topLevelCreator);
- QV4::QmlContext *qmlContext = static_cast<QV4::QmlContext *>(valueScope.alloc());
-
- qSwap(_qmlContext, qmlContext);
-
- qSwap(_propertyCache, cache);
- qSwap(_qobject, instance);
-
- int objectIndex = deferredIndex;
- qSwap(_compiledObjectIndex, objectIndex);
-
- const QV4::CompiledData::Object *obj = compilationUnit->objectAt(_compiledObjectIndex);
- qSwap(_compiledObject, obj);
- qSwap(_ddata, declarativeData);
- qSwap(_bindingTarget, bindingTarget);
- qSwap(_vmeMetaObject, vmeMetaObject);
-
- if (binding) {
+ doPopulateDeferred(instance, deferredIndex, [this, qmlProperty, binding]() {
Q_ASSERT(qmlProperty);
- Q_ASSERT(binding->flags & QV4::CompiledData::Binding::IsDeferredBinding);
+ Q_ASSERT(binding->hasFlag(QV4::CompiledData::Binding::IsDeferredBinding));
QQmlListProperty<void> savedList;
qSwap(_currentList, savedList);
const QQmlPropertyData &property = qmlProperty->core;
- if (property.isQList()) {
+ if (property.propType().flags().testFlag(QMetaType::IsQmlList)) {
void *argv[1] = { (void*)&_currentList };
QMetaObject::metacall(_qobject, QMetaObject::ReadProperty, property.coreIndex(), argv);
} else if (_currentList.object) {
@@ -307,20 +265,12 @@ void QQmlObjectCreator::populateDeferred(QObject *instance, int deferredIndex,
setPropertyBinding(&property, binding);
qSwap(_currentList, savedList);
- } else {
- setupBindings(/*applyDeferredBindings=*/true);
- }
-
- qSwap(_vmeMetaObject, vmeMetaObject);
- qSwap(_bindingTarget, bindingTarget);
- qSwap(_ddata, declarativeData);
- qSwap(_compiledObject, obj);
- qSwap(_compiledObjectIndex, objectIndex);
- qSwap(_qobject, instance);
- qSwap(_propertyCache, cache);
+ });
+}
- qSwap(_qmlContext, qmlContext);
- qSwap(_scopeObject, scopeObject);
+void QQmlObjectCreator::populateDeferred(QObject *instance, int deferredIndex)
+{
+ doPopulateDeferred(instance, deferredIndex, [this]() { setupBindings(ApplyDeferred); });
}
bool QQmlObjectCreator::populateDeferredProperties(QObject *instance,
@@ -335,8 +285,22 @@ bool QQmlObjectCreator::populateDeferredProperties(QObject *instance,
void QQmlObjectCreator::populateDeferredBinding(const QQmlProperty &qmlProperty, int deferredIndex,
const QV4::CompiledData::Binding *binding)
{
- populateDeferred(qmlProperty.object(), deferredIndex, QQmlPropertyPrivate::get(qmlProperty),
- binding);
+ if (binding) {
+ populateDeferred(qmlProperty.object(), deferredIndex, QQmlPropertyPrivate::get(qmlProperty),
+ binding);
+ } else {
+ populateDeferred(qmlProperty.object(), deferredIndex);
+ }
+}
+
+void QQmlObjectCreator::populateDeferredInstance(
+ QObject *outerObject, int deferredIndex, int index, QObject *instance,
+ QObject *bindingTarget, const QQmlPropertyData *valueTypeProperty,
+ const QV4::CompiledData::Binding *binding)
+{
+ doPopulateDeferred(outerObject, deferredIndex, [&]() {
+ populateInstance(index, instance, bindingTarget, valueTypeProperty, binding);
+ });
}
void QQmlObjectCreator::finalizePopulateDeferred()
@@ -349,11 +313,14 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const
QQmlPropertyData::WriteFlags propertyWriteFlags = QQmlPropertyData::BypassInterceptor | QQmlPropertyData::RemoveBindingOnAliasWrite;
QV4::Scope scope(v4);
- int propertyType = property->propType().id();
+ QMetaType propertyType = property->propType();
if (property->isEnum()) {
- if (binding->flags & QV4::CompiledData::Binding::IsResolvedEnum) {
- propertyType = QMetaType::Int;
+ if (binding->hasFlag(QV4::CompiledData::Binding::IsResolvedEnum) ||
+ // TODO: For historical reasons you can assign any number to an enum property alias
+ // This can be fixed with an opt-out mechanism, for example a pragma.
+ (property->isAlias() && binding->isNumberBinding())) {
+ propertyType = property->propType().underlyingType();
} else {
// ### This should be resolved earlier at compile time and the binding value should be changed accordingly.
QVariant value = compilationUnit->bindingValueAsString(binding);
@@ -366,18 +333,18 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const
auto assertOrNull = [&](bool ok)
{
- Q_ASSERT(ok || binding->type == QV4::CompiledData::Binding::Type_Null);
+ Q_ASSERT(ok || binding->type() == QV4::CompiledData::Binding::Type_Null);
Q_UNUSED(ok);
};
- auto assertType = [&](QV4::CompiledData::Binding::ValueType type)
+ auto assertType = [&](QV4::CompiledData::Binding::Type type)
{
- Q_ASSERT(binding->type == type || binding->type == QV4::CompiledData::Binding::Type_Null);
+ Q_ASSERT(binding->type()== type || binding->type() == QV4::CompiledData::Binding::Type_Null);
Q_UNUSED(type);
};
if (property->isQObject()) {
- if (binding->type == QV4::CompiledData::Binding::Type_Null) {
+ if (binding->type() == QV4::CompiledData::Binding::Type_Null) {
QObject *value = nullptr;
const bool ok = property->writeProperty(_qobject, &value, propertyWriteFlags);
Q_ASSERT(ok);
@@ -386,9 +353,9 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const
}
}
- switch (propertyType) {
+ switch (propertyType.id()) {
case QMetaType::QVariant: {
- if (binding->type == QV4::CompiledData::Binding::Type_Number) {
+ if (binding->type() == QV4::CompiledData::Binding::Type_Number) {
double n = compilationUnit->bindingValueAsNumber(binding);
if (double(int(n)) == n) {
if (property->isVarProperty()) {
@@ -406,14 +373,14 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const
property->writeProperty(_qobject, &value, propertyWriteFlags);
}
}
- } else if (binding->type == QV4::CompiledData::Binding::Type_Boolean) {
+ } else if (binding->type() == QV4::CompiledData::Binding::Type_Boolean) {
if (property->isVarProperty()) {
_vmeMetaObject->setVMEProperty(property->coreIndex(), QV4::Value::fromBoolean(binding->valueAsBoolean()));
} else {
QVariant value(binding->valueAsBoolean());
property->writeProperty(_qobject, &value, propertyWriteFlags);
}
- } else if (binding->type == QV4::CompiledData::Binding::Type_Null) {
+ } else if (binding->type() == QV4::CompiledData::Binding::Type_Null) {
if (property->isVarProperty()) {
_vmeMetaObject->setVMEProperty(property->coreIndex(), QV4::Value::nullValue());
} else {
@@ -453,7 +420,9 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const
case QMetaType::QUrl: {
assertType(QV4::CompiledData::Binding::Type_String);
const QString string = compilationUnit->bindingValueAsString(binding);
- QUrl value(string);
+ QUrl value = (!string.isEmpty() && QQmlPropertyPrivate::resolveUrlsOnAssignment())
+ ? compilationUnit->finalUrl().resolved(QUrl(string))
+ : QUrl(string);
property->writeProperty(_qobject, &value, propertyWriteFlags);
}
break;
@@ -473,6 +442,49 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const
break;
}
break;
+ case QMetaType::SChar: {
+ assertType(QV4::CompiledData::Binding::Type_Number);
+ double d = compilationUnit->bindingValueAsNumber(binding);
+ qint8 value = qint8(d);
+ property->writeProperty(_qobject, &value, propertyWriteFlags);
+ break;
+ }
+ case QMetaType::UChar: {
+ assertType(QV4::CompiledData::Binding::Type_Number);
+ double d = compilationUnit->bindingValueAsNumber(binding);
+ quint8 value = quint8(d);
+ property->writeProperty(_qobject, &value, propertyWriteFlags);
+ break;
+ }
+ case QMetaType::Short: {
+ assertType(QV4::CompiledData::Binding::Type_Number);
+ double d = compilationUnit->bindingValueAsNumber(binding);
+ qint16 value = qint16(d);
+ property->writeProperty(_qobject, &value, propertyWriteFlags);
+ break;
+ }
+ case QMetaType::UShort: {
+ assertType(QV4::CompiledData::Binding::Type_Number);
+ double d = compilationUnit->bindingValueAsNumber(binding);
+ quint16 value = quint16(d);
+ property->writeProperty(_qobject, &value, propertyWriteFlags);
+ break;
+ }
+ case QMetaType::LongLong: {
+ assertType(QV4::CompiledData::Binding::Type_Number);
+ double d = compilationUnit->bindingValueAsNumber(binding);
+ qint64 value = qint64(d);
+ property->writeProperty(_qobject, &value, propertyWriteFlags);
+ break;
+ }
+ case QMetaType::ULongLong: {
+ assertType(QV4::CompiledData::Binding::Type_Number);
+ double d = compilationUnit->bindingValueAsNumber(binding);
+ quint64 value = quint64(d);
+ property->writeProperty(_qobject, &value, propertyWriteFlags);
+ break;
+ }
+ break;
case QMetaType::Float: {
assertType(QV4::CompiledData::Binding::Type_Number);
float value = float(compilationUnit->bindingValueAsNumber(binding));
@@ -486,9 +498,9 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const
}
break;
case QMetaType::QColor: {
- QVariant data;
- if (QQml_valueTypeProvider()->createValueType(
- QMetaType::QColor, compilationUnit->bindingValueAsString(binding), data)) {
+ QVariant data = QQmlValueTypeProvider::createValueType(
+ compilationUnit->bindingValueAsString(binding), propertyType);
+ if (data.isValid()) {
property->writeProperty(_qobject, data.data(), propertyWriteFlags);
}
}
@@ -569,78 +581,108 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const
case QMetaType::QVector3D:
case QMetaType::QVector4D:
case QMetaType::QQuaternion: {
- QVariant result;
- bool ok = QQml_valueTypeProvider()->createValueType(
- propertyType, compilationUnit->bindingValueAsString(binding), result);
- assertOrNull(ok);
- Q_UNUSED(ok);
+ QVariant result = QQmlValueTypeProvider::createValueType(
+ compilationUnit->bindingValueAsString(binding), propertyType);
+ assertOrNull(result.isValid());
property->writeProperty(_qobject, result.data(), propertyWriteFlags);
break;
}
default: {
// generate single literal value assignment to a list property if required
- if (propertyType == qMetaTypeId<QList<qreal> >()) {
+ if (propertyType == QMetaType::fromType<QList<qreal>>()) {
assertType(QV4::CompiledData::Binding::Type_Number);
QList<qreal> value;
value.append(compilationUnit->bindingValueAsNumber(binding));
property->writeProperty(_qobject, &value, propertyWriteFlags);
break;
- } else if (propertyType == qMetaTypeId<QList<int> >()) {
+ } else if (propertyType == QMetaType::fromType<QList<int>>()) {
assertType(QV4::CompiledData::Binding::Type_Number);
double n = compilationUnit->bindingValueAsNumber(binding);
QList<int> value;
value.append(int(n));
property->writeProperty(_qobject, &value, propertyWriteFlags);
break;
- } else if (propertyType == qMetaTypeId<QList<bool> >()) {
+ } else if (propertyType == QMetaType::fromType<QList<bool>>()) {
assertType(QV4::CompiledData::Binding::Type_Boolean);
QList<bool> value;
value.append(binding->valueAsBoolean());
property->writeProperty(_qobject, &value, propertyWriteFlags);
break;
- } else if (propertyType == qMetaTypeId<QList<QUrl> >()) {
+ } else if (propertyType == QMetaType::fromType<QList<QUrl>>()) {
assertType(QV4::CompiledData::Binding::Type_String);
- QList<QUrl> value { QUrl(compilationUnit->bindingValueAsString(binding)) };
+ const QUrl url(compilationUnit->bindingValueAsString(binding));
+ QList<QUrl> value {
+ QQmlPropertyPrivate::resolveUrlsOnAssignment()
+ ? compilationUnit->finalUrl().resolved(url)
+ : url
+ };
property->writeProperty(_qobject, &value, propertyWriteFlags);
break;
- } else if (propertyType == qMetaTypeId<QList<QString> >()) {
+ } else if (propertyType == QMetaType::fromType<QList<QString>>()) {
assertOrNull(binding->evaluatesToString());
QList<QString> value;
value.append(compilationUnit->bindingValueAsString(binding));
property->writeProperty(_qobject, &value, propertyWriteFlags);
break;
- } else if (propertyType == qMetaTypeId<QJSValue>()) {
+ } else if (propertyType == QMetaType::fromType<QJSValue>()) {
QJSValue value;
- if (binding->type == QV4::CompiledData::Binding::Type_Boolean) {
+ switch (binding->type()) {
+ case QV4::CompiledData::Binding::Type_Boolean:
value = QJSValue(binding->valueAsBoolean());
- } else if (binding->type == QV4::CompiledData::Binding::Type_Number) {
- double n = compilationUnit->bindingValueAsNumber(binding);
- if (double(int(n)) == n) {
+ break;
+ case QV4::CompiledData::Binding::Type_Number: {
+ const double n = compilationUnit->bindingValueAsNumber(binding);
+ if (double(int(n)) == n)
value = QJSValue(int(n));
- } else
+ else
value = QJSValue(n);
- } else if (binding->type == QV4::CompiledData::Binding::Type_Null) {
+ break;
+ }
+ case QV4::CompiledData::Binding::Type_Null:
value = QJSValue::NullValue;
- } else {
+ break;
+ default:
value = QJSValue(compilationUnit->bindingValueAsString(binding));
+ break;
}
property->writeProperty(_qobject, &value, propertyWriteFlags);
break;
+ } else {
+ QVariant source;
+ switch (binding->type()) {
+ case QV4::CompiledData::Binding::Type_Boolean:
+ source = binding->valueAsBoolean();
+ break;
+ case QV4::CompiledData::Binding::Type_Number: {
+ const double n = compilationUnit->bindingValueAsNumber(binding);
+ if (double(int(n)) == n)
+ source = int(n);
+ else
+ source = n;
+ break;
+ }
+ case QV4::CompiledData::Binding::Type_Null:
+ source = QVariant::fromValue<std::nullptr_t>(nullptr);
+ break;
+ case QV4::CompiledData::Binding::Type_Invalid:
+ break;
+ default:
+ source = compilationUnit->bindingValueAsString(binding);
+ break;
+ }
+
+ QVariant target = QQmlValueTypeProvider::createValueType(source, propertyType);
+ if (target.isValid()) {
+ property->writeProperty(_qobject, target.data(), propertyWriteFlags);
+ break;
+ }
}
- // otherwise, try a custom type assignment
+ // string converters are not exposed, so ending up here indicates an error
QString stringValue = compilationUnit->bindingValueAsString(binding);
- QQmlMetaType::StringConverter converter = QQmlMetaType::customStringConverter(property->propType().id());
- Q_ASSERT(converter);
- QVariant value = (*converter)(stringValue);
-
QMetaProperty metaProperty = _qobject->metaObject()->property(property->coreIndex());
- if (value.isNull() || metaProperty.metaType() != property->propType()) {
- recordError(binding->location, tr("Cannot assign value %1 to property %2").arg(stringValue).arg(QString::fromUtf8(metaProperty.name())));
- break;
- }
-
- property->writeProperty(_qobject, value.data(), propertyWriteFlags);
+ recordError(binding->location, tr("Cannot assign value %1 to property"
+" %2").arg(stringValue, QString::fromUtf8(metaProperty.name())));
}
break;
}
@@ -657,23 +699,25 @@ static QQmlType qmlTypeForObject(QObject *object)
return type;
}
-void QQmlObjectCreator::setupBindings(bool applyDeferredBindings)
+void QQmlObjectCreator::setupBindings(BindingSetupFlags mode)
{
QQmlListProperty<void> savedList;
qSwap(_currentList, savedList);
- const QV4::BindingPropertyData &propertyData = compilationUnit->bindingPropertyDataPerObject.at(_compiledObjectIndex);
+ const QV4::CompiledData::BindingPropertyData *propertyData
+ = compilationUnit->bindingPropertyDataPerObjectAt(_compiledObjectIndex);
if (_compiledObject->idNameIndex) {
- const QQmlPropertyData *idProperty = propertyData.last();
+ const QQmlPropertyData *idProperty = propertyData->last();
Q_ASSERT(!idProperty || !idProperty->isValid() || idProperty->name(_qobject) == QLatin1String("id"));
if (idProperty && idProperty->isValid() && idProperty->isWritable() && idProperty->propType().id() == QMetaType::QString) {
QV4::CompiledData::Binding idBinding;
idBinding.propertyNameIndex = 0; // Not used
- idBinding.flags = 0;
- idBinding.type = QV4::CompiledData::Binding::Type_String;
+ idBinding.clearFlags();
+ idBinding.setType(QV4::CompiledData::Binding::Type_String);
idBinding.stringIndex = _compiledObject->idNameIndex;
idBinding.location = _compiledObject->location; // ###
+ idBinding.value.nullMarker = 0; // zero the value field to make codechecker happy
setPropertyValue(idProperty, &idBinding);
}
}
@@ -682,7 +726,7 @@ void QQmlObjectCreator::setupBindings(bool applyDeferredBindings)
if (_valueTypeProperty) {
QQmlAbstractBinding *binding = QQmlPropertyPrivate::binding(_bindingTarget, QQmlPropertyIndex(_valueTypeProperty->coreIndex()));
- if (binding && !binding->isValueTypeProxy()) {
+ if (binding && binding->kind() != QQmlAbstractBinding::ValueTypeProxy) {
QQmlPropertyPrivate::removeBinding(_bindingTarget, QQmlPropertyIndex(_valueTypeProperty->coreIndex()));
} else if (binding) {
QQmlValueTypeProxyBinding *proxy = static_cast<QQmlValueTypeProxyBinding *>(binding);
@@ -690,11 +734,11 @@ void QQmlObjectCreator::setupBindings(bool applyDeferredBindings)
if (qmlTypeForObject(_bindingTarget).isValid()) {
quint32 bindingSkipList = 0;
- QQmlPropertyData *defaultProperty = _compiledObject->indexOfDefaultPropertyOrAlias != -1 ? _propertyCache->parent()->defaultProperty() : _propertyCache->defaultProperty();
+ const QQmlPropertyData *defaultProperty = _compiledObject->indexOfDefaultPropertyOrAlias != -1 ? _propertyCache->parent()->defaultProperty() : _propertyCache->defaultProperty();
const QV4::CompiledData::Binding *binding = _compiledObject->bindingTable();
for (quint32 i = 0; i < _compiledObject->nBindings; ++i, ++binding) {
- QQmlPropertyData *property = binding->propertyNameIndex != 0
+ const QQmlPropertyData *property = binding->propertyNameIndex != 0
? _propertyCache->property(stringAt(binding->propertyNameIndex),
_qobject, context)
: defaultProperty;
@@ -711,9 +755,9 @@ void QQmlObjectCreator::setupBindings(bool applyDeferredBindings)
const QV4::CompiledData::Binding *binding = _compiledObject->bindingTable();
for (quint32 i = 0; i < _compiledObject->nBindings; ++i, ++binding) {
- QQmlPropertyData *const property = propertyData.at(i);
+ const QQmlPropertyData *const property = propertyData->at(i);
if (property) {
- QQmlPropertyData* targetProperty = property;
+ const QQmlPropertyData *targetProperty = property;
if (targetProperty->isAlias()) {
// follow alias
QQmlPropertyIndex originalIndex(targetProperty->coreIndex(), _valueTypeProperty ? _valueTypeProperty->coreIndex() : -1);
@@ -721,23 +765,23 @@ void QQmlObjectCreator::setupBindings(bool applyDeferredBindings)
QQmlData *data = QQmlData::get(targetObject);
Q_ASSERT(data && data->propertyCache);
targetProperty = data->propertyCache->property(targetIndex.coreIndex());
+ sharedState->requiredProperties.remove({targetObject, targetProperty});
}
- sharedState->requiredProperties.remove(targetProperty);
+ sharedState->requiredProperties.remove({_bindingTarget, property});
}
- if (binding->flags & QV4::CompiledData::Binding::IsCustomParserBinding)
+ if (binding->hasFlag(QV4::CompiledData::Binding::IsCustomParserBinding))
continue;
- if (binding->flags & QV4::CompiledData::Binding::IsDeferredBinding) {
- if (!applyDeferredBindings)
- continue;
- } else {
- if (applyDeferredBindings)
+ if (binding->hasFlag(QV4::CompiledData::Binding::IsDeferredBinding)) {
+ if (!(mode & ApplyDeferred))
continue;
+ } else if (!(mode & ApplyImmediate)) {
+ continue;
}
- if (property && property->isQList()) {
+ if (property && property->propType().flags().testFlag(QMetaType::IsQmlList)) {
if (property->coreIndex() != currentListPropertyIndex) {
void *argv[1] = { (void*)&_currentList };
QMetaObject::metacall(_qobject, QMetaObject::ReadProperty, property->coreIndex(), argv);
@@ -786,22 +830,32 @@ void QQmlObjectCreator::setupBindings(bool applyDeferredBindings)
bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *bindingProperty, const QV4::CompiledData::Binding *binding)
{
- if (binding->type == QV4::CompiledData::Binding::Type_AttachedProperty) {
+ const QV4::CompiledData::Binding::Type bindingType = binding->type();
+ if (bindingType == QV4::CompiledData::Binding::Type_AttachedProperty) {
Q_ASSERT(stringAt(compilationUnit->objectAt(binding->value.objectIndex)->inheritedTypeNameIndex).isEmpty());
QV4::ResolvedTypeReference *tr = resolvedType(binding->propertyNameIndex);
Q_ASSERT(tr);
QQmlType attachedType = tr->type();
+ QQmlEnginePrivate *enginePrivate = QQmlEnginePrivate::get(engine);
if (!attachedType.isValid()) {
QQmlTypeNameCache::Result res = context->imports()->query(
- stringAt(binding->propertyNameIndex));
+ stringAt(binding->propertyNameIndex), QQmlTypeLoader::get(enginePrivate));
if (res.isValid())
attachedType = res.type;
else
return false;
}
QObject *qmlObject = qmlAttachedPropertiesObject(
- _qobject, attachedType.attachedPropertiesFunction(QQmlEnginePrivate::get(engine)));
- if (!populateInstance(binding->value.objectIndex, qmlObject, qmlObject, /*value type property*/nullptr))
+ _qobject, attachedType.attachedPropertiesFunction(enginePrivate));
+ if (!qmlObject) {
+ recordError(binding->location,
+ QStringLiteral("Could not create attached properties object '%1'")
+ .arg(QString::fromUtf8(attachedType.typeName())));
+ return false;
+ }
+
+ if (!populateInstance(binding->value.objectIndex, qmlObject, qmlObject,
+ /*value type property*/ nullptr, binding))
return false;
return true;
}
@@ -810,11 +864,11 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *bindingProper
if (bindingProperty && bindingProperty->propType() == QMetaType::fromType<QQmlScriptString>()) {
QQmlScriptString ss(compilationUnit->bindingValueAsScriptString(binding),
context->asQQmlContext(), _scopeObject);
- ss.d.data()->bindingId = binding->type == QV4::CompiledData::Binding::Type_Script ? binding->value.compiledScriptIndex : (quint32)QQmlBinding::Invalid;
- ss.d.data()->lineNumber = binding->location.line;
- ss.d.data()->columnNumber = binding->location.column;
- ss.d.data()->isStringLiteral = binding->type == QV4::CompiledData::Binding::Type_String;
- ss.d.data()->isNumberLiteral = binding->type == QV4::CompiledData::Binding::Type_Number;
+ ss.d.data()->bindingId = bindingType == QV4::CompiledData::Binding::Type_Script ? binding->value.compiledScriptIndex : (quint32)QQmlBinding::Invalid;
+ ss.d.data()->lineNumber = binding->location.line();
+ ss.d.data()->columnNumber = binding->location.column();
+ ss.d.data()->isStringLiteral = bindingType == QV4::CompiledData::Binding::Type_String;
+ ss.d.data()->isNumberLiteral = bindingType == QV4::CompiledData::Binding::Type_Number;
ss.d.data()->numberValue = compilationUnit->bindingValueAsNumber(binding);
QQmlPropertyData::WriteFlags propertyWriteFlags = QQmlPropertyData::BypassInterceptor |
@@ -826,16 +880,13 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *bindingProper
}
QObject *createdSubObject = nullptr;
- if (binding->type == QV4::CompiledData::Binding::Type_Object) {
+ if (bindingType == QV4::CompiledData::Binding::Type_Object) {
createdSubObject = createInstance(binding->value.objectIndex, _bindingTarget);
if (!createdSubObject)
return false;
}
- if (!bindingProperty) // ### error
- return true;
-
- if (binding->type == QV4::CompiledData::Binding::Type_GroupProperty) {
+ if (bindingType == QV4::CompiledData::Binding::Type_GroupProperty) {
const QV4::CompiledData::Object *obj = compilationUnit->objectAt(binding->value.objectIndex);
if (stringAt(obj->inheritedTypeNameIndex).isEmpty()) {
@@ -843,8 +894,19 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *bindingProper
QQmlGadgetPtrWrapper *valueType = nullptr;
const QQmlPropertyData *valueTypeProperty = nullptr;
QObject *bindingTarget = _bindingTarget;
-
- if (QQmlMetaType::isValueType(bindingProperty->propType())) {
+ int groupObjectIndex = binding->value.objectIndex;
+
+ if (!bindingProperty) {
+ for (int i = 0, end = compilationUnit->objectCount(); i != end; ++i) {
+ const QV4::CompiledData::Object *external = compilationUnit->objectAt(i);
+ if (external->idNameIndex == binding->propertyNameIndex) {
+ bindingTarget = groupObject = context->idValue(external->objectId());
+ break;
+ }
+ }
+ if (!groupObject)
+ return true;
+ } else if (QQmlMetaType::isValueType(bindingProperty->propType())) {
valueType = QQmlGadgetPtrWrapper::instance(engine, bindingProperty->propType());
if (!valueType) {
recordError(binding->location, tr("Cannot set properties on %1 as it is null").arg(stringAt(binding->propertyNameIndex)));
@@ -859,15 +921,27 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *bindingProper
void *argv[1] = { &groupObject };
QMetaObject::metacall(_qobject, QMetaObject::ReadProperty, bindingProperty->coreIndex(), argv);
if (!groupObject) {
- recordError(binding->location, tr("Cannot set properties on %1 as it is null").arg(stringAt(binding->propertyNameIndex)));
- return false;
+ QQmlPropertyIndex index(bindingProperty->coreIndex());
+ auto anyBinding = QQmlAnyBinding::ofProperty(_qobject, index);
+ if (anyBinding) {
+ // if there is a binding, try to force-evaluate it now
+ // this might instantiate a necessary part of a grouped property
+ anyBinding.refresh();
+ QMetaObject::metacall(_qobject, QMetaObject::ReadProperty, bindingProperty->coreIndex(), argv);
+ }
+ if (!groupObject) {
+ recordError(binding->location, tr("Cannot set properties on %1 as it is null").arg(stringAt(binding->propertyNameIndex)));
+ return false;
+ }
}
bindingTarget = groupObject;
}
- if (!populateInstance(binding->value.objectIndex, groupObject, bindingTarget, valueTypeProperty))
+ if (!populateInstance(groupObjectIndex, groupObject, bindingTarget, valueTypeProperty,
+ binding)) {
return false;
+ }
if (valueType)
valueType->write(_qobject, bindingProperty->coreIndex(), QQmlPropertyData::BypassInterceptor);
@@ -876,14 +950,28 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *bindingProper
}
}
- if (_ddata->hasBindingBit(bindingProperty->coreIndex()) && !(binding->flags & QV4::CompiledData::Binding::IsSignalHandlerExpression)
- && !(binding->flags & QV4::CompiledData::Binding::IsOnAssignment)
- && !_valueTypeProperty)
- QQmlPropertyPrivate::removeBinding(_bindingTarget, QQmlPropertyIndex(bindingProperty->coreIndex()));
+ if (!bindingProperty) // ### error
+ return true;
+
+ const QV4::CompiledData::Binding::Flags bindingFlags = binding->flags();
+ const bool allowedToRemoveBinding
+ = !(bindingFlags & QV4::CompiledData::Binding::IsSignalHandlerExpression)
+ && !(bindingFlags & QV4::CompiledData::Binding::IsOnAssignment)
+ && !(bindingFlags & QV4::CompiledData::Binding::IsPropertyObserver)
+ && !_valueTypeProperty;
+
+ if (allowedToRemoveBinding) {
+ if (bindingProperty->isBindable()) {
+ removePendingBinding(_bindingTarget, bindingProperty->coreIndex());
+ } else {
+ QQmlPropertyPrivate::removeBinding(
+ _bindingTarget, QQmlPropertyIndex(bindingProperty->coreIndex()));
+ }
+ }
- if (binding->type == QV4::CompiledData::Binding::Type_Script || binding->isTranslationBinding()) {
- if (binding->flags & QV4::CompiledData::Binding::IsSignalHandlerExpression
- || binding->flags & QV4::CompiledData::Binding::IsPropertyObserver) {
+ if (bindingType == QV4::CompiledData::Binding::Type_Script || binding->isTranslationBinding()) {
+ if (bindingFlags & QV4::CompiledData::Binding::IsSignalHandlerExpression
+ || bindingFlags & QV4::CompiledData::Binding::IsPropertyObserver) {
QV4::Function *runtimeFunction = compilationUnit->runtimeFunctions[binding->value.compiledScriptIndex];
int signalIndex = _propertyCache->methodIndexToSignalIndex(bindingProperty->coreIndex());
QQmlBoundSignalExpression *expr = new QQmlBoundSignalExpression(
@@ -923,7 +1011,10 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *bindingProper
QQmlPropertyIndex index(bindingProperty->coreIndex(), -1);
qmlBinding = QQmlPropertyBinding::create(bindingProperty, runtimeFunction, _scopeObject, context, currentQmlContext(), _bindingTarget, index);
}
- sharedState.data()->allQPropertyBindings.emplaceBack(_bindingTarget, bindingProperty->coreIndex(), qmlBinding);
+ sharedState.data()->allQPropertyBindings.push_back(DeferredQPropertyBinding {_bindingTarget, bindingProperty->coreIndex(), qmlBinding });
+
+ QQmlData *data = QQmlData::get(_bindingTarget, true);
+ data->setBindingBit(_bindingTarget, bindingProperty->coreIndex());
} else {
// When writing bindings to grouped properties implemented as value types,
// such as point.x: { someExpression; }, then the binding is installed on
@@ -974,8 +1065,8 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *bindingProper
return true;
}
- if (binding->type == QV4::CompiledData::Binding::Type_Object) {
- if (binding->flags & QV4::CompiledData::Binding::IsOnAssignment) {
+ if (bindingType == QV4::CompiledData::Binding::Type_Object) {
+ if (bindingFlags & QV4::CompiledData::Binding::IsOnAssignment) {
// ### determine value source and interceptor casts ahead of time.
QQmlType type = qmlTypeForObject(createdSubObject);
Q_ASSERT(type.isValid());
@@ -1039,7 +1130,7 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *bindingProper
}
// Assigning object to signal property? ### Qt 7: Remove that functionality
- if (binding->flags & QV4::CompiledData::Binding::IsSignalHandlerObject) {
+ if (bindingFlags & QV4::CompiledData::Binding::IsSignalHandlerObject) {
if (!bindingProperty->isFunction()) {
recordError(binding->valueLocation, tr("Cannot assign an object to signal property %1").arg(bindingProperty->name(_qobject)));
return false;
@@ -1049,9 +1140,9 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *bindingProper
recordError(binding->valueLocation, tr("Cannot assign object type %1 with no default method").arg(QString::fromLatin1(createdSubObject->metaObject()->className())));
return false;
}
- qCWarning(lcQmlDefaultMethod) << "Assigning an object to a signal handler is deprecated."
- "Instead, create the object, give it an id, and call the desired slot from the signal handler."
- ;
+ qCWarning(lcQmlDefaultMethod) << "Assigning an object to a signal handler is deprecated. "
+ "Instead, create the object, give it an id, and call the desired slot "
+ "from the signal handler. The object is:" << createdSubObject;
QMetaMethod signalMethod = _qobject->metaObject()->method(bindingProperty->coreIndex());
if (!QMetaObject::checkConnectArgs(signalMethod, method)) {
@@ -1071,7 +1162,7 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *bindingProper
int propertyWriteStatus = -1;
void *argv[] = { nullptr, nullptr, &propertyWriteStatus, &propertyWriteFlags };
- if (const char *iid = QQmlMetaType::interfaceIId(bindingProperty->propType().id())) {
+ if (const char *iid = QQmlMetaType::interfaceIId(bindingProperty->propType())) {
void *ptr = createdSubObject->qt_metacast(iid);
if (ptr) {
argv[0] = &ptr;
@@ -1101,17 +1192,17 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *bindingProper
argv[0] = &value;
QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, bindingProperty->coreIndex(), argv);
}
- } else if (bindingProperty->isQList()) {
+ } else if (bindingProperty->propType().flags().testFlag(QMetaType::IsQmlList)) {
Q_ASSERT(_currentList.object);
void *itemToAdd = createdSubObject;
- const char *iid = nullptr;
- int listItemType = QQmlMetaType::listType(bindingProperty->propType().id());
- if (listItemType != -1)
- iid = QQmlMetaType::interfaceIId(listItemType);
- if (iid)
- itemToAdd = createdSubObject->qt_metacast(iid);
+ QMetaType listItemType = QQmlMetaType::listValueType(bindingProperty->propType());
+ if (listItemType.isValid()) {
+ const char *iid = QQmlMetaType::interfaceIId(listItemType);
+ if (iid)
+ itemToAdd = createdSubObject->qt_metacast(iid);
+ }
if (_currentList.append)
_currentList.append(&_currentList, itemToAdd);
@@ -1148,7 +1239,7 @@ void QQmlObjectCreator::setupFunctions()
QV4::Function *runtimeFunction = compilationUnit->runtimeFunctions[*functionIdx];
const QString name = runtimeFunction->name()->toQString();
- QQmlPropertyData *property = _propertyCache->property(name, _qobject, context);
+ const QQmlPropertyData *property = _propertyCache->property(name, _qobject, context);
if (!property->isVMEFunction())
continue;
@@ -1164,16 +1255,16 @@ void QQmlObjectCreator::recordError(const QV4::CompiledData::Location &location,
{
QQmlError error;
error.setUrl(compilationUnit->url());
- error.setLine(qmlConvertSourceCoordinate<quint32, int>(location.line));
- error.setColumn(qmlConvertSourceCoordinate<quint32, int>(location.column));
+ error.setLine(qmlConvertSourceCoordinate<quint32, int>(location.line()));
+ error.setColumn(qmlConvertSourceCoordinate<quint32, int>(location.column()));
error.setDescription(description);
errors << error;
}
void QQmlObjectCreator::registerObjectWithContextById(const QV4::CompiledData::Object *object, QObject *instance) const
{
- if (object->id >= 0)
- context->setIdValue(object->id, instance);
+ if (object->objectId() >= 0)
+ context->setIdValue(object->objectId(), instance);
}
QObject *QQmlObjectCreator::createInstance(int index, QObject *parent, bool isContextObject)
@@ -1193,13 +1284,12 @@ QObject *QQmlObjectCreator::createInstance(int index, QObject *parent, bool isCo
QQmlParserStatus *parserStatus = nullptr;
bool installPropertyCache = true;
- if (obj->flags & QV4::CompiledData::Object::IsComponent) {
+ if (obj->hasFlag(QV4::CompiledData::Object::IsComponent)) {
isComponent = true;
- QQmlComponent *component = new QQmlComponent(engine, compilationUnit.data(), index, parent);
+ instance = createComponent(engine, compilationUnit.data(), index, parent, context);
typeName = QStringLiteral("<component>");
- QQmlComponentPrivate::get(component)->creationContext = context;
- instance = component;
- ddata = QQmlData::get(instance, /*create*/true);
+ ddata = QQmlData::get(instance);
+ Q_ASSERT(ddata); // we just created it inside createComponent
} else {
QV4::ResolvedTypeReference *typeRef = resolvedType(obj->inheritedTypeNameIndex);
Q_ASSERT(typeRef);
@@ -1208,21 +1298,17 @@ QObject *QQmlObjectCreator::createInstance(int index, QObject *parent, bool isCo
if (type.isValid() && !type.isInlineComponentType()) {
typeName = type.qmlTypeName();
- void *ddataMemory = nullptr;
- type.create(&instance, &ddataMemory, sizeof(QQmlData));
+ instance = type.createWithQQmlData();
if (!instance) {
recordError(obj->location, tr("Unable to create object of type %1").arg(stringAt(obj->inheritedTypeNameIndex)));
return nullptr;
}
- {
- QQmlData *ddata = new (ddataMemory) QQmlData;
- ddata->ownMemory = false;
- QObjectPrivate* p = QObjectPrivate::get(instance);
- Q_ASSERT(!p->isDeletingChildren);
- p->declarativeData = ddata;
+ const int finalizerCast = type.finalizerCast();
+ if (finalizerCast != -1) {
+ auto hook = reinterpret_cast<QQmlFinalizerHook *>(reinterpret_cast<char *>(instance) + finalizerCast);
+ sharedState->finalizeHooks.push_back(hook);
}
-
const int parserStatusCast = type.parserStatusCast();
if (parserStatusCast != -1)
parserStatus = reinterpret_cast<QQmlParserStatus*>(reinterpret_cast<char *>(instance) + parserStatusCast);
@@ -1237,7 +1323,7 @@ QObject *QQmlObjectCreator::createInstance(int index, QObject *parent, bool isCo
sharedState->allCreatedObjects.push(instance);
} else {
- const auto compilationUnit = typeRef->compilationUnit();
+ auto compilationUnit = typeRef->compilationUnit();
Q_ASSERT(compilationUnit);
typeName = compilationUnit->fileName();
// compilation unit is shared between root type and its inline component types
@@ -1248,17 +1334,42 @@ QObject *QQmlObjectCreator::createInstance(int index, QObject *parent, bool isCo
}
if (!type.isInlineComponentType()) {
- QQmlObjectCreator subCreator(context, compilationUnit, sharedState.data());
+ QQmlObjectCreator subCreator(
+ context, engine->handle()->executableCompilationUnit(
+ std::move(compilationUnit)),
+ sharedState.data(), isContextObject);
instance = subCreator.create();
if (!instance) {
errors += subCreator.errors;
return nullptr;
}
} else {
- int subObjectId = type.inlineComponentId();
- QScopedValueRollback<int> rollback {compilationUnit->icRoot, subObjectId};
- QQmlObjectCreator subCreator(context, compilationUnit, sharedState.data());
- instance = subCreator.create(subObjectId, nullptr, nullptr, CreationFlags::InlineComponent);
+ QString subObjectName;
+ if (QString *icRootName = compilationUnit->icRootName.get()) {
+ subObjectName = type.elementName();
+ std::swap(*icRootName, subObjectName);
+ } else {
+ compilationUnit->icRootName = std::make_unique<QString>(type.elementName());
+ }
+
+ const auto guard = qScopeGuard([&] {
+ if (subObjectName.isEmpty())
+ compilationUnit->icRootName.reset();
+ else
+ std::swap(*compilationUnit->icRootName, subObjectName);
+ });
+
+ const int inlineComponentId
+ = compilationUnit->inlineComponentId(*compilationUnit->icRootName);
+ QQmlObjectCreator subCreator(
+ context,
+ engine->handle()->executableCompilationUnit(
+ QQmlRefPointer<QV4::CompiledData::CompilationUnit>(
+ compilationUnit)),
+ sharedState.data(),
+ isContextObject);
+ instance = subCreator.create(
+ inlineComponentId, nullptr, nullptr, CreationFlags::InlineComponent);
if (!instance) {
errors += subCreator.errors;
return nullptr;
@@ -1283,31 +1394,17 @@ QObject *QQmlObjectCreator::createInstance(int index, QObject *parent, bool isCo
compilationUnit.data(), obj, typeName, context->url()));
Q_UNUSED(typeName); // only relevant for tracing
- ddata->lineNumber = obj->location.line;
- ddata->columnNumber = obj->location.column;
+ ddata->lineNumber = obj->location.line();
+ ddata->columnNumber = obj->location.column();
ddata->setImplicitDestructible();
// inline components are root objects, but their index is != 0, so we need
// an additional check
- const bool isInlineComponent = obj->flags & QV4::CompiledData::Object::IsInlineComponentRoot;
- if (static_cast<quint32>(index) == /*root object*/0 || ddata->rootObjectInCreation || isInlineComponent) {
- if (ddata->context) {
- Q_ASSERT(ddata->context != context.data());
- Q_ASSERT(ddata->outerContext);
- Q_ASSERT(ddata->outerContext != context.data());
- QQmlRefPointer<QQmlContextData> c = ddata->context;
- while (QQmlRefPointer<QQmlContextData> linked = c->linkedContext())
- c = linked;
- c->setLinkedContext(context);
- } else {
- ddata->context = context.data();
- }
- ddata->ownContext = ddata->context;
- } else if (!ddata->context) {
- ddata->context = context.data();
- }
-
- context->addOwnedObject(ddata);
+ const bool documentRoot = static_cast<quint32>(index) == /*root object*/ 0
+ || ddata->rootObjectInCreation
+ || obj->hasFlag(QV4::CompiledData::Object::IsInlineComponentRoot);
+ context->installContext(
+ ddata, documentRoot ? QQmlContextData::DocumentRoot : QQmlContextData::OrdinaryObject);
if (parserStatus) {
parserStatus->classBegin();
@@ -1323,19 +1420,18 @@ QObject *QQmlObjectCreator::createInstance(int index, QObject *parent, bool isCo
if (isContextObject)
context->setContextObject(instance);
- if (customParser && obj->flags & QV4::CompiledData::Object::HasCustomParserBindings) {
+ if (customParser && obj->hasFlag(QV4::CompiledData::Object::HasCustomParserBindings)) {
customParser->engine = QQmlEnginePrivate::get(engine);
- customParser->imports = compilationUnit->typeNameCache.data();
+ customParser->imports = compilationUnit->typeNameCache().data();
QList<const QV4::CompiledData::Binding *> bindings;
const QV4::CompiledData::Object *obj = compilationUnit->objectAt(index);
const QV4::CompiledData::Binding *binding = obj->bindingTable();
for (quint32 i = 0; i < obj->nBindings; ++i, ++binding) {
- if (binding->flags & QV4::CompiledData::Binding::IsCustomParserBinding) {
+ if (binding->hasFlag(QV4::CompiledData::Binding::IsCustomParserBinding))
bindings << binding;
- }
}
- customParser->applyBindings(instance, compilationUnit.data(), bindings);
+ customParser->applyBindings(instance, compilationUnit, bindings);
customParser->engine = nullptr;
customParser->imports = (QQmlTypeNameCache*)nullptr;
@@ -1346,21 +1442,16 @@ QObject *QQmlObjectCreator::createInstance(int index, QObject *parent, bool isCo
return instance;
}
- QQmlRefPointer<QQmlPropertyCache> cache = propertyCaches->at(index);
+ QQmlPropertyCache::ConstPtr cache = propertyCaches->at(index);
Q_ASSERT(!cache.isNull());
- if (installPropertyCache) {
- if (ddata->propertyCache)
- ddata->propertyCache->release();;
- ddata->propertyCache = cache.data();
- ddata->propertyCache->addref();
- }
+ if (installPropertyCache)
+ ddata->propertyCache = cache;
QObject *scopeObject = instance;
qSwap(_scopeObject, scopeObject);
- Q_ASSERT(sharedState->allJavaScriptObjects);
- *sharedState->allJavaScriptObjects = QV4::QObjectWrapper::wrap(v4, instance);
- ++sharedState->allJavaScriptObjects;
+ Q_ASSERT(sharedState->allJavaScriptObjects.canTrack());
+ sharedState->allJavaScriptObjects.trackObject(v4, instance);
QV4::Scope valueScope(v4);
QV4::QmlContext *qmlContext = static_cast<QV4::QmlContext *>(valueScope.alloc());
@@ -1404,6 +1495,19 @@ bool QQmlObjectCreator::finalize(QQmlInstantiationInterrupt &interrupt)
QQmlObjectCreatorRecursionWatcher watcher(this);
QScopedValueRollback<QQmlObjectCreator*> ocRestore(QQmlEnginePrivate::get(engine)->activeObjectCreator, this);
+ /* We install all pending bindings (both plain QML and QProperty), and remove the ones which do not
+ actually have dependencies.
+ It is necessary to install the binding so that it runs at least once, which causes it to capture any
+ dependencies.
+ We then check for the following conditions:
+ - Is the binding in an error state?
+ - Does the binding has any dependencies (from properties)?
+ - Does it depend on anything in the context, which has not been resolved yet (and thus couldn't be
+ captured)?
+ If the answer to all of those questions is "no", it is safe to remove the binding, as there is no
+ way for it to change its value afterwards from that point on.
+ */
+
while (!sharedState->allCreatedBindings.isEmpty()) {
QQmlAbstractBinding::Ptr b = sharedState->allCreatedBindings.pop();
Q_ASSERT(b);
@@ -1415,10 +1519,10 @@ bool QQmlObjectCreator::finalize(QQmlInstantiationInterrupt &interrupt)
data->clearPendingBindingBit(b->targetPropertyIndex().coreIndex());
b->setEnabled(true, QQmlPropertyData::BypassInterceptor |
QQmlPropertyData::DontRemoveBinding);
- if (!b->isValueTypeProxy()) {
+ if (b->kind() == QQmlAbstractBinding::QmlBinding) {
QQmlBinding *binding = static_cast<QQmlBinding*>(b.data());
if (!binding->hasError() && !binding->hasDependencies()
- && binding->hasContext() && !binding->hasUnresolvedNames()) {
+ && !binding->hasUnresolvedNames()) {
b->removeFromObject();
}
}
@@ -1429,11 +1533,38 @@ bool QQmlObjectCreator::finalize(QQmlInstantiationInterrupt &interrupt)
while (!sharedState->allQPropertyBindings.isEmpty()) {
auto& [target, index, qmlBinding] = sharedState->allQPropertyBindings.first();
+
+ QQmlData *data = QQmlData::get(target);
+ if (!data || !data->hasBindingBit(index)) {
+ // The target property has been overwritten since we stashed the binding.
+ sharedState->allQPropertyBindings.pop_front();
+ continue;
+ }
+
QUntypedBindable bindable;
void *argv[] = { &bindable };
- target->qt_metacall(QMetaObject::BindableProperty, index, argv);
- bindable.setBinding(qmlBinding);
+ // allow interception
+ target->metaObject()->metacall(target, QMetaObject::BindableProperty, index, argv);
+ const bool success = bindable.setBinding(qmlBinding);
+
+ const auto bindingPrivateRefCount = QPropertyBindingPrivate::get(qmlBinding)->refCount();
+
+ // Only pop_front after setting the binding as the bindings are refcounted.
sharedState->allQPropertyBindings.pop_front();
+
+ // If the binding was actually not set, it's deleted now.
+ if (success && bindingPrivateRefCount > 1) {
+ if (auto priv = QPropertyBindingPrivate::get(qmlBinding); priv->hasCustomVTable()) {
+ auto qmlBindingPriv = static_cast<QQmlPropertyBinding *>(priv);
+ auto jsExpression = qmlBindingPriv->jsExpression();
+ const bool canRemove = !qmlBinding.error().hasError()
+ && !qmlBindingPriv->hasDependencies()
+ && !jsExpression->hasUnresolvedNames();
+ if (canRemove)
+ bindable.takeBinding();
+ }
+ }
+
if (watcher.hasRecursed() || interrupt.shouldInterrupt())
return false;
}
@@ -1453,17 +1584,12 @@ bool QQmlObjectCreator::finalize(QQmlInstantiationInterrupt &interrupt)
}
}
- for (int ii = 0; ii < sharedState->finalizeCallbacks.count(); ++ii) {
- QQmlEnginePrivate::FinalizeCallback callback = sharedState->finalizeCallbacks.at(ii);
- QObject *obj = callback.first;
- if (obj) {
- void *args[] = { nullptr };
- QMetaObject::metacall(obj, QMetaObject::InvokeMetaMethod, callback.second, args);
- }
+ for (QQmlFinalizerHook *hook: sharedState->finalizeHooks) {
+ hook->componentFinalized();
if (watcher.hasRecursed())
return false;
}
- sharedState->finalizeCallbacks.clear();
+ sharedState->finalizeHooks.clear();
while (sharedState->componentAttached) {
QQmlComponentAttached *a = sharedState->componentAttached;
@@ -1505,8 +1631,11 @@ void QQmlObjectCreator::clear()
phase = Done;
}
-bool QQmlObjectCreator::populateInstance(int index, QObject *instance, QObject *bindingTarget, const QQmlPropertyData *valueTypeProperty)
+bool QQmlObjectCreator::populateInstance(int index, QObject *instance, QObject *bindingTarget,
+ const QQmlPropertyData *valueTypeProperty,
+ const QV4::CompiledData::Binding *binding)
{
+ Q_ASSERT(instance);
QQmlData *declarativeData = QQmlData::get(instance, /*create*/true);
qSwap(_qobject, instance);
@@ -1520,17 +1649,14 @@ bool QQmlObjectCreator::populateInstance(int index, QObject *instance, QObject *
QV4::Scope valueScope(v4);
QV4::ScopedValue scopeObjectProtector(valueScope);
- QQmlRefPointer<QQmlPropertyCache> cache = propertyCaches->at(_compiledObjectIndex);
+ QQmlPropertyCache::ConstPtr cache = propertyCaches->at(_compiledObjectIndex);
QQmlVMEMetaObject *vmeMetaObject = nullptr;
if (propertyCaches->needsVMEMetaObject(_compiledObjectIndex)) {
Q_ASSERT(!cache.isNull());
// install on _object
vmeMetaObject = new QQmlVMEMetaObject(v4, _qobject, cache, compilationUnit, _compiledObjectIndex);
- if (_ddata->propertyCache)
- _ddata->propertyCache->release();
- _ddata->propertyCache = cache.data();
- _ddata->propertyCache->addref();
+ _ddata->propertyCache = cache;
scopeObjectProtector = _ddata->jsWrapper.value();
} else {
vmeMetaObject = QQmlVMEMetaObject::get(_qobject);
@@ -1541,9 +1667,11 @@ bool QQmlObjectCreator::populateInstance(int index, QObject *instance, QObject *
qSwap(_propertyCache, cache);
qSwap(_vmeMetaObject, vmeMetaObject);
- if (_compiledObject->flags & QV4::CompiledData::Object::HasDeferredBindings)
+ _ddata->compilationUnit = compilationUnit;
+ if (_compiledObject->hasFlag(QV4::CompiledData::Object::HasDeferredBindings))
_ddata->deferData(_compiledObjectIndex, compilationUnit, context);
+ const qsizetype oldRequiredPropertiesCount = sharedState->requiredProperties.size();
QSet<QString> postHocRequired;
for (auto it = _compiledObject->requiredPropertyExtraDataBegin(); it != _compiledObject->requiredPropertyExtraDataEnd(); ++it)
postHocRequired.insert(stringAt(it->nameIndex));
@@ -1551,23 +1679,62 @@ bool QQmlObjectCreator::populateInstance(int index, QObject *instance, QObject *
for (int propertyIndex = 0; propertyIndex != _compiledObject->propertyCount(); ++propertyIndex) {
const QV4::CompiledData::Property* property = _compiledObject->propertiesBegin() + propertyIndex;
- QQmlPropertyData *propertyData = _propertyCache->property(_propertyCache->propertyOffset() + propertyIndex);
+ const QQmlPropertyData *propertyData = _propertyCache->property(_propertyCache->propertyOffset() + propertyIndex);
// only compute stringAt if there's a chance for the lookup to succeed
auto postHocIt = postHocRequired.isEmpty() ? postHocRequired.end() : postHocRequired.find(stringAt(property->nameIndex));
- if (!property->isRequired && postHocRequired.end() == postHocIt)
+ if (!property->isRequired() && postHocRequired.end() == postHocIt)
continue;
if (postHocIt != postHocRequired.end())
postHocRequired.erase(postHocIt);
- sharedState->hadRequiredProperties = true;
- sharedState->requiredProperties.insert(propertyData,
+ if (isContextObject)
+ sharedState->hadTopLevelRequiredProperties = true;
+ sharedState->requiredProperties.insert({_qobject, propertyData},
RequiredPropertyInfo {compilationUnit->stringAt(property->nameIndex), compilationUnit->finalUrl(), property->location, {}});
}
- for (int i = 0; i <= _propertyCache->propertyOffset(); ++i) {
- QQmlPropertyData *propertyData = _propertyCache->maybeUnresolvedProperty(i);
+ const auto getPropertyCacheRange = [&]() -> std::pair<int, int> {
+ // the logic in a nutshell: we work with QML instances here. every
+ // instance has a QQmlType:
+ // * if QQmlType is valid && not an inline component, it's a C++ type
+ // * otherwise, it's a QML-defined type (a.k.a. Composite type), where
+ // invalid type == "comes from another QML document"
+ //
+ // 1. if the type we inherit from comes from C++, we must check *all*
+ // properties in the property cache so far - since we can have
+ // required properties defined in C++
+ // 2. otherwise - the type comes from QML, it's enough to check just
+ // *own* properties in the property cache, because there's a previous
+ // type in the hierarchy that has checked the C++ properties (via 1.)
+ // 3. required attached properties are explicitly not supported. to
+ // achieve that, go through all its properties
+ // 4. required group properties: the group itself is covered by 1.
+ // required sub-properties are not properly handled (QTBUG-96544), so
+ // just return the old range here for consistency
+ QV4::ResolvedTypeReference *typeRef = resolvedType(_compiledObject->inheritedTypeNameIndex);
+ if (!typeRef) { // inside a binding on attached/group property
+ Q_ASSERT(binding);
+ if (binding->isAttachedProperty())
+ return { 0, _propertyCache->propertyCount() }; // 3.
+ Q_ASSERT(binding->isGroupProperty());
+ return { 0, _propertyCache->propertyOffset() + 1 }; // 4.
+ }
+ Q_ASSERT(!_compiledObject->hasFlag(QV4::CompiledData::Object::IsComponent));
+ QQmlType type = typeRef->type();
+ if (type.isValid() && !type.isInlineComponentType()) {
+ return { 0, _propertyCache->propertyCount() }; // 1.
+ }
+ // Q_ASSERT(type.isComposite());
+ return { _propertyCache->propertyOffset(), _propertyCache->propertyCount() }; // 2.
+ };
+ const auto [offset, count] = getPropertyCacheRange();
+ for (int i = offset; i < count; ++i) {
+ const QQmlPropertyData *propertyData = _propertyCache->maybeUnresolvedProperty(i);
if (!propertyData)
continue;
+ // TODO: the property might be a group property (in which case we need
+ // to dive into its sub-properties and check whether there are any
+ // required elements there) - QTBUG-96544
if (!propertyData->isRequired() && postHocRequired.isEmpty())
continue;
QString name = propertyData->name(_qobject);
@@ -1578,37 +1745,80 @@ bool QQmlObjectCreator::populateInstance(int index, QObject *instance, QObject *
if (postHocIt != postHocRequired.end())
postHocRequired.erase(postHocIt);
- sharedState->hadRequiredProperties = true;
- sharedState->requiredProperties.insert(propertyData, RequiredPropertyInfo {name, compilationUnit->finalUrl(), _compiledObject->location, {}});
+ if (isContextObject)
+ sharedState->hadTopLevelRequiredProperties = true;
+ sharedState->requiredProperties.insert(
+ {_qobject, propertyData},
+ RequiredPropertyInfo {
+ name, compilationUnit->finalUrl(), _compiledObject->location, {} });
+ }
+
+ if (binding && binding->isAttachedProperty()
+ && sharedState->requiredProperties.size() != oldRequiredPropertiesCount) {
+ recordError(
+ binding->location,
+ QLatin1String("Attached property has required properties. This is not supported"));
+ }
+
+ // Note: there's a subtle case with the above logic: if we process a random
+ // QML-defined leaf type, it could have a required attribute overwrite on an
+ // *existing* property: `import QtQuick; Text { required text }`. in this
+ // case, we must add the property to a required list
+ if (!postHocRequired.isEmpty()) {
+ // NB: go through [0, offset) range as [offset, count) is already done
+ for (int i = 0; i < offset; ++i) {
+ const QQmlPropertyData *propertyData = _propertyCache->maybeUnresolvedProperty(i);
+ if (!propertyData)
+ continue;
+ QString name = propertyData->name(_qobject);
+ auto postHocIt = postHocRequired.find(name);
+ if (postHocRequired.end() == postHocIt)
+ continue;
+ postHocRequired.erase(postHocIt);
+
+ if (isContextObject)
+ sharedState->hadTopLevelRequiredProperties = true;
+ sharedState->requiredProperties.insert(
+ {_qobject, propertyData},
+ RequiredPropertyInfo {
+ name, compilationUnit->finalUrl(), _compiledObject->location, {} });
+ }
}
+
if (!postHocRequired.isEmpty() && hadInheritedRequiredProperties)
recordError({}, QLatin1String("Property %1 was marked as required but does not exist").arg(*postHocRequired.begin()));
if (_compiledObject->nFunctions > 0)
setupFunctions();
- setupBindings();
+ setupBindings((binding && binding->hasFlag(QV4::CompiledData::Binding::IsDeferredBinding))
+ ? BindingMode::ApplyAll
+ : BindingMode::ApplyImmediate);
for (int aliasIndex = 0; aliasIndex != _compiledObject->aliasCount(); ++aliasIndex) {
const QV4::CompiledData::Alias* alias = _compiledObject->aliasesBegin() + aliasIndex;
const auto originalAlias = alias;
- while (alias->aliasToLocalAlias)
+ while (alias->isAliasToLocalAlias())
alias = _compiledObject->aliasesBegin() + alias->localAliasIndex;
- Q_ASSERT(alias->flags & QV4::CompiledData::Alias::Resolved);
+ Q_ASSERT(alias->hasFlag(QV4::CompiledData::Alias::Resolved));
if (!context->isIdValueSet(0)) // TODO: Do we really want 0 here?
continue;
- QObject *target = context->idValue(alias->targetObjectId);
+ QObject *target = context->idValue(alias->targetObjectId());
if (!target)
continue;
QQmlData *targetDData = QQmlData::get(target, /*create*/false);
- if (targetDData == nullptr || targetDData->propertyCache == nullptr)
+ if (targetDData == nullptr || targetDData->propertyCache.isNull())
continue;
int coreIndex = QQmlPropertyIndex::fromEncoded(alias->encodedMetaPropertyIndex).coreIndex();
- QQmlPropertyData *const targetProperty = targetDData->propertyCache->property(coreIndex);
+ const QQmlPropertyData *const targetProperty = targetDData->propertyCache->property(coreIndex);
if (!targetProperty)
continue;
- auto it = sharedState->requiredProperties.find(targetProperty);
+ auto it = sharedState->requiredProperties.find({target, targetProperty});
if (it != sharedState->requiredProperties.end())
- it->aliasesToRequired.push_back(AliasToRequiredInfo {compilationUnit->stringAt(originalAlias->nameIndex), compilationUnit->finalUrl()});
+ it->aliasesToRequired.push_back(
+ AliasToRequiredInfo {
+ compilationUnit->stringAt(originalAlias->nameIndex()),
+ compilationUnit->finalUrl()
+ });
}
qSwap(_vmeMetaObject, vmeMetaObject);
@@ -1623,11 +1833,34 @@ bool QQmlObjectCreator::populateInstance(int index, QObject *instance, QObject *
return errors.isEmpty();
}
-
-
+/*!
+ \internal
+*/
+QQmlComponent *QQmlObjectCreator::createComponent(QQmlEngine *engine,
+ QV4::ExecutableCompilationUnit *compilationUnit,
+ int index, QObject *parent,
+ const QQmlRefPointer<QQmlContextData> &context)
+{
+ QQmlComponent *component = new QQmlComponent(engine, compilationUnit, index, parent);
+ QQmlComponentPrivate::get(component)->creationContext = context;
+ QQmlData::get(component, /*create*/ true);
+ return component;
+}
QQmlObjectCreatorRecursionWatcher::QQmlObjectCreatorRecursionWatcher(QQmlObjectCreator *creator)
: sharedState(creator->sharedState)
, watcher(creator->sharedState.data())
{
}
+
+void ObjectInCreationGCAnchorList::trackObject(QV4::ExecutionEngine *engine, QObject *instance)
+{
+ *allJavaScriptObjects = QV4::QObjectWrapper::wrap(engine, instance);
+ // we have to handle the case where the gc is already running, but the scope is discarded
+ // before the collector runs again. In that case, rescanning won't help us. Thus, mark the
+ // object.
+ QV4::WriteBarrier::markCustom(engine, [this](QV4::MarkStack *ms) {
+ allJavaScriptObjects->heapObject()->mark(ms);
+ });
+ ++allJavaScriptObjects;
+}
diff --git a/src/qml/qml/qqmlobjectcreator_p.h b/src/qml/qml/qqmlobjectcreator_p.h
index 0059c6da7b..8b1c251e2b 100644
--- a/src/qml/qml/qqmlobjectcreator_p.h
+++ b/src/qml/qml/qqmlobjectcreator_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the tools applications 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLOBJECTCREATOR_P_H
#define QQMLOBJECTCREATOR_P_H
@@ -58,6 +22,8 @@
#include <private/qqmlprofiler_p.h>
#include <private/qv4qmlcontext_p.h>
#include <private/qqmlguardedcontextdata_p.h>
+#include <private/qqmlfinalizer_p.h>
+#include <private/qqmlvmemetaobject_p.h>
#include <qpointer.h>
@@ -87,26 +53,69 @@ struct RequiredPropertyInfo
QVector<AliasToRequiredInfo> aliasesToRequired;
};
-class RequiredProperties : public QHash<QQmlPropertyData*, RequiredPropertyInfo> {};
+struct RequiredPropertyKey
+{
+ RequiredPropertyKey() = default;
+ RequiredPropertyKey(const QObject *object, const QQmlPropertyData *data)
+ : object(object)
+ , data(data)
+ {}
+
+ const QObject *object = nullptr;
+ const QQmlPropertyData *data = nullptr;
+
+private:
+ friend size_t qHash(const RequiredPropertyKey &key, size_t seed = 0)
+ {
+ return qHashMulti(seed, key.object, key.data);
+ }
+
+ friend bool operator==(const RequiredPropertyKey &a, const RequiredPropertyKey &b)
+ {
+ return a.object == b.object && a.data == b.data;
+ }
+};
+
+class RequiredProperties : public QHash<RequiredPropertyKey, RequiredPropertyInfo> {};
-struct QQmlObjectCreatorSharedState : public QSharedData
+struct DeferredQPropertyBinding {
+ QObject *target = nullptr;
+ int properyIndex = -1;
+ QUntypedPropertyBinding binding;
+};
+
+class ObjectInCreationGCAnchorList {
+public:
+ // this is a non owning view, rule of zero applies
+ ObjectInCreationGCAnchorList() = default;
+ ObjectInCreationGCAnchorList(const QV4::Scope &scope, int totalObjectCount)
+ {
+ allJavaScriptObjects = scope.alloc(totalObjectCount);
+ }
+ void trackObject(QV4::ExecutionEngine *engine, QObject *instance);
+ bool canTrack() const { return allJavaScriptObjects; }
+private:
+ QV4::Value *allJavaScriptObjects = nullptr; // pointer to vector on JS stack to reference JS wrappers during creation phase.
+};
+
+struct QQmlObjectCreatorSharedState final : QQmlRefCounted<QQmlObjectCreatorSharedState>
{
QQmlRefPointer<QQmlContextData> rootContext;
QQmlRefPointer<QQmlContextData> creationContext;
QFiniteStack<QQmlAbstractBinding::Ptr> allCreatedBindings;
QFiniteStack<QQmlParserStatus*> allParserStatusCallbacks;
- QFiniteStack<QPointer<QObject> > allCreatedObjects;
- QV4::Value *allJavaScriptObjects; // pointer to vector on JS stack to reference JS wrappers during creation phase.
+ QFiniteStack<QQmlGuard<QObject> > allCreatedObjects;
+ ObjectInCreationGCAnchorList allJavaScriptObjects; // pointer to vector on JS stack to reference JS wrappers during creation phase.
QQmlComponentAttached *componentAttached;
- QList<QQmlEnginePrivate::FinalizeCallback> finalizeCallbacks;
+ QList<QQmlFinalizerHook *> finalizeHooks;
QQmlVmeProfiler profiler;
QRecursionNode recursionNode;
RequiredProperties requiredProperties;
- QList<std::tuple<QObject *, int, QUntypedPropertyBinding>> allQPropertyBindings;
- bool hadRequiredProperties;
+ QList<DeferredQPropertyBinding> allQPropertyBindings;
+ bool hadTopLevelRequiredProperties;
};
-class Q_QML_PRIVATE_EXPORT QQmlObjectCreator
+class Q_QML_EXPORT QQmlObjectCreator
{
Q_DECLARE_TR_FUNCTIONS(QQmlObjectCreator)
public:
@@ -125,6 +134,10 @@ public:
void beginPopulateDeferred(const QQmlRefPointer<QQmlContextData> &context);
void populateDeferredBinding(const QQmlProperty &qmlProperty, int deferredIndex,
const QV4::CompiledData::Binding *binding);
+ void populateDeferredInstance(QObject *outerObject, int deferredIndex,
+ int index, QObject *instance, QObject *bindingTarget,
+ const QQmlPropertyData *valueTypeProperty,
+ const QV4::CompiledData::Binding *binding = nullptr);
void finalizePopulateDeferred();
bool finalize(QQmlInstantiationInterrupt &interrupt);
@@ -133,37 +146,59 @@ public:
QQmlRefPointer<QQmlContextData> rootContext() const { return sharedState->rootContext; }
QQmlComponentAttached **componentAttachment() { return &sharedState->componentAttached; }
- QList<QQmlEnginePrivate::FinalizeCallback> *finalizeCallbacks() { return &sharedState->finalizeCallbacks; }
-
QList<QQmlError> errors;
QQmlRefPointer<QQmlContextData> parentContextData() const
{
return parentContext.contextData();
}
- QFiniteStack<QPointer<QObject> > &allCreatedObjects() { return sharedState->allCreatedObjects; }
+ QFiniteStack<QQmlGuard<QObject> > &allCreatedObjects() { return sharedState->allCreatedObjects; }
- RequiredProperties &requiredProperties() {return sharedState->requiredProperties;}
- bool componentHadRequiredProperties() const {return sharedState->hadRequiredProperties;}
+ RequiredProperties *requiredProperties() {return &sharedState->requiredProperties;}
+ bool componentHadTopLevelRequiredProperties() const {return sharedState->hadTopLevelRequiredProperties;}
+
+ static QQmlComponent *createComponent(QQmlEngine *engine,
+ QV4::ExecutableCompilationUnit *compilationUnit,
+ int index, QObject *parent,
+ const QQmlRefPointer<QQmlContextData> &context);
+
+ void removePendingBinding(QObject *target, int propertyIndex)
+ {
+ QList<DeferredQPropertyBinding> &pendingBindings = sharedState.data()->allQPropertyBindings;
+ pendingBindings.removeIf([&](const DeferredQPropertyBinding &deferred) {
+ return deferred.properyIndex == propertyIndex && deferred.target == target;
+ });
+ }
private:
QQmlObjectCreator(QQmlRefPointer<QQmlContextData> contextData,
const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit,
- QQmlObjectCreatorSharedState *inheritedSharedState);
+ QQmlObjectCreatorSharedState *inheritedSharedState,
+ bool isContextObject);
void init(QQmlRefPointer<QQmlContextData> parentContext);
QObject *createInstance(int index, QObject *parent = nullptr, bool isContextObject = false);
- bool populateInstance(int index, QObject *instance,
- QObject *bindingTarget, const QQmlPropertyData *valueTypeProperty);
+ bool populateInstance(int index, QObject *instance, QObject *bindingTarget,
+ const QQmlPropertyData *valueTypeProperty,
+ const QV4::CompiledData::Binding *binding = nullptr);
// If qmlProperty and binding are null, populate all properties, otherwise only the given one.
+ void populateDeferred(QObject *instance, int deferredIndex);
void populateDeferred(QObject *instance, int deferredIndex,
- const QQmlPropertyPrivate *qmlProperty = nullptr,
- const QV4::CompiledData::Binding *binding = nullptr);
-
- void setupBindings(bool applyDeferredBindings = false);
+ const QQmlPropertyPrivate *qmlProperty,
+ const QV4::CompiledData::Binding *binding);
+
+ enum BindingMode {
+ ApplyNone = 0x0,
+ ApplyImmediate = 0x1,
+ ApplyDeferred = 0x2,
+ ApplyAll = ApplyImmediate | ApplyDeferred,
+ };
+ Q_DECLARE_FLAGS(BindingSetupFlags, BindingMode);
+
+ void setupBindings(BindingSetupFlags mode = BindingMode::ApplyImmediate);
bool setPropertyBinding(const QQmlPropertyData *property, const QV4::CompiledData::Binding *binding);
void setPropertyValue(const QQmlPropertyData *property, const QV4::CompiledData::Binding *binding);
void setupFunctions();
@@ -195,8 +230,9 @@ private:
QQmlGuardedContextData parentContext;
QQmlRefPointer<QQmlContextData> context;
const QQmlPropertyCacheVector *propertyCaches;
- QExplicitlySharedDataPointer<QQmlObjectCreatorSharedState> sharedState;
+ QQmlRefPointer<QQmlObjectCreatorSharedState> sharedState;
bool topLevelCreator;
+ bool isContextObject;
QQmlIncubatorPrivate *incubator;
QObject *_qobject;
@@ -207,7 +243,7 @@ private:
int _compiledObjectIndex;
const QV4::CompiledData::Object *_compiledObject;
QQmlData *_ddata;
- QQmlRefPointer<QQmlPropertyCache> _propertyCache;
+ QQmlPropertyCache::ConstPtr _propertyCache;
QQmlVMEMetaObject *_vmeMetaObject;
QQmlListProperty<void> _currentList;
QV4::QmlContext *_qmlContext;
@@ -216,6 +252,58 @@ private:
typedef std::function<bool(QQmlObjectCreatorSharedState *sharedState)> PendingAliasBinding;
std::vector<PendingAliasBinding> pendingAliasBindings;
+
+ template<typename Functor>
+ void doPopulateDeferred(QObject *instance, int deferredIndex, Functor f)
+ {
+ QQmlData *declarativeData = QQmlData::get(instance);
+
+ // We're in the process of creating the object. We sure hope it's still alive.
+ Q_ASSERT(declarativeData && declarativeData->propertyCache);
+
+ QObject *bindingTarget = instance;
+
+ QQmlPropertyCache::ConstPtr cache = declarativeData->propertyCache;
+ QQmlVMEMetaObject *vmeMetaObject = QQmlVMEMetaObject::get(instance);
+
+ QObject *scopeObject = instance;
+ qt_ptr_swap(_scopeObject, scopeObject);
+
+ QV4::Scope valueScope(v4);
+ QScopedValueRollback<ObjectInCreationGCAnchorList> jsObjectGuard(
+ sharedState->allJavaScriptObjects,
+ ObjectInCreationGCAnchorList(valueScope, compilationUnit->totalObjectCount()));
+
+ Q_ASSERT(topLevelCreator);
+ QV4::QmlContext *qmlContext = static_cast<QV4::QmlContext *>(valueScope.alloc());
+
+ qt_ptr_swap(_qmlContext, qmlContext);
+
+ _propertyCache.swap(cache);
+ qt_ptr_swap(_qobject, instance);
+
+ int objectIndex = deferredIndex;
+ std::swap(_compiledObjectIndex, objectIndex);
+
+ const QV4::CompiledData::Object *obj = compilationUnit->objectAt(_compiledObjectIndex);
+ qt_ptr_swap(_compiledObject, obj);
+ qt_ptr_swap(_ddata, declarativeData);
+ qt_ptr_swap(_bindingTarget, bindingTarget);
+ qt_ptr_swap(_vmeMetaObject, vmeMetaObject);
+
+ f();
+
+ qt_ptr_swap(_vmeMetaObject, vmeMetaObject);
+ qt_ptr_swap(_bindingTarget, bindingTarget);
+ qt_ptr_swap(_ddata, declarativeData);
+ qt_ptr_swap(_compiledObject, obj);
+ std::swap(_compiledObjectIndex, objectIndex);
+ qt_ptr_swap(_qobject, instance);
+ _propertyCache.swap(cache);
+
+ qt_ptr_swap(_qmlContext, qmlContext);
+ qt_ptr_swap(_scopeObject, scopeObject);
+ }
};
struct QQmlObjectCreatorRecursionWatcher
@@ -225,7 +313,7 @@ struct QQmlObjectCreatorRecursionWatcher
bool hasRecursed() const { return watcher.hasRecursed(); }
private:
- QExplicitlySharedDataPointer<QQmlObjectCreatorSharedState> sharedState;
+ QQmlRefPointer<QQmlObjectCreatorSharedState> sharedState;
QRecursionWatcher<QQmlObjectCreatorSharedState, &QQmlObjectCreatorSharedState::recursionNode> watcher;
};
diff --git a/src/qml/qml/qqmlobjectorgadget.cpp b/src/qml/qml/qqmlobjectorgadget.cpp
index 454c029fc3..bc70138144 100644
--- a/src/qml/qml/qqmlobjectorgadget.cpp
+++ b/src/qml/qml/qqmlobjectorgadget.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 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$
-**
-****************************************************************************/
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qqmlobjectorgadget_p.h"
diff --git a/src/qml/qml/qqmlobjectorgadget_p.h b/src/qml/qml/qqmlobjectorgadget_p.h
index 109a1813e8..ddce295c9d 100644
--- a/src/qml/qml/qqmlobjectorgadget_p.h
+++ b/src/qml/qml/qqmlobjectorgadget_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 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$
-**
-****************************************************************************/
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLOBJECTORGADGET_P_H
#define QQMLOBJECTORGADGET_P_H
@@ -52,6 +16,7 @@
//
#include <private/qqmlmetaobject_p.h>
+#include <private/qbipointer_p.h>
QT_BEGIN_NAMESPACE
@@ -72,6 +37,9 @@ public:
void metacall(QMetaObject::Call type, int index, void **argv) const;
+ bool isNull() const { return ptr.isNull(); }
+ QObject *qObject() const { return ptr.isT1() ? ptr.asT1() : nullptr; }
+
private:
QBiPointer<QObject, void> ptr;
};
diff --git a/src/qml/qml/qqmlopenmetaobject.cpp b/src/qml/qml/qqmlopenmetaobject.cpp
index ec2d57013f..2d0a78c6cb 100644
--- a/src/qml/qml/qqmlopenmetaobject.cpp
+++ b/src/qml/qml/qqmlopenmetaobject.cpp
@@ -1,47 +1,15 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qqmlopenmetaobject_p.h"
#include <private/qqmlpropertycache_p.h>
#include <private/qqmldata_p.h>
+#include <private/qqmlmetatype_p.h>
+
#include <private/qmetaobjectbuilder_p.h>
#include <qdebug.h>
+#include <QtCore/qpointer.h>
+#include <QtCore/qset.h>
QT_BEGIN_NAMESPACE
@@ -49,7 +17,7 @@ QT_BEGIN_NAMESPACE
class QQmlOpenMetaObjectTypePrivate
{
public:
- QQmlOpenMetaObjectTypePrivate() : mem(nullptr), cache(nullptr) {}
+ QQmlOpenMetaObjectTypePrivate() : mem(nullptr) {}
void init(const QMetaObject *metaObj);
@@ -58,7 +26,13 @@ public:
QHash<QByteArray, int> names;
QMetaObjectBuilder mob;
QMetaObject *mem;
- QQmlPropertyCache *cache;
+
+ // TODO: We need to make sure that this does not escape into other threads.
+ // In particular, all its non-const uses are probably wrong. You should
+ // only set the open metaobject to "cached" once it's not going to be
+ // modified anymore.
+ QQmlPropertyCache::Ptr cache;
+
QSet<QQmlOpenMetaObject*> referers;
};
@@ -72,8 +46,6 @@ QQmlOpenMetaObjectType::~QQmlOpenMetaObjectType()
{
if (d->mem)
free(d->mem);
- if (d->cache)
- d->cache->release();
delete d;
}
@@ -89,24 +61,19 @@ int QQmlOpenMetaObjectType::signalOffset() const
int QQmlOpenMetaObjectType::propertyCount() const
{
- return d->names.count();
+ return d->names.size();
}
QByteArray QQmlOpenMetaObjectType::propertyName(int idx) const
{
- Q_ASSERT(idx >= 0 && idx < d->names.count());
+ Q_ASSERT(idx >= 0 && idx < d->names.size());
return d->mob.property(idx).name();
}
-QMetaObject *QQmlOpenMetaObjectType::metaObject() const
-{
- return d->mem;
-}
-
void QQmlOpenMetaObjectType::createProperties(const QVector<QByteArray> &names)
{
- for (int i = 0; i < names.count(); ++i) {
+ for (int i = 0; i < names.size(); ++i) {
const QByteArray &name = names.at(i);
const int id = d->mob.propertyCount();
d->mob.addSignal("__" + QByteArray::number(id) + "()");
@@ -128,13 +95,13 @@ void QQmlOpenMetaObjectType::createProperties(const QVector<QByteArray> &names)
int QQmlOpenMetaObjectType::createProperty(const QByteArray &name)
{
- int id = d->mob.propertyCount();
- d->mob.addSignal("__" + QByteArray::number(id) + "()");
- QMetaPropertyBuilder build = d->mob.addProperty(name, "QVariant", id);
- propertyCreated(id, build);
+ const int signalIdx = d->mob.addSignal(
+ "__" + QByteArray::number(d->mob.propertyCount()) + "()").index();
+ QMetaPropertyBuilder build = d->mob.addProperty(name, "QVariant", signalIdx);
+ propertyCreated(build.index(), build);
free(d->mem);
d->mem = d->mob.toMetaObject();
- d->names.insert(name, id);
+ d->names.insert(name, build.index());
QSet<QQmlOpenMetaObject*>::iterator it = d->referers.begin();
while (it != d->referers.end()) {
QQmlOpenMetaObject *omo = *it;
@@ -144,12 +111,12 @@ int QQmlOpenMetaObjectType::createProperty(const QByteArray &name)
++it;
}
- return d->propertyOffset + id;
+ return d->propertyOffset + build.index();
}
void QQmlOpenMetaObjectType::propertyCreated(int id, QMetaPropertyBuilder &builder)
{
- if (d->referers.count())
+ if (d->referers.size())
(*d->referers.begin())->propertyCreated(id, builder);
}
@@ -198,13 +165,13 @@ public:
};
inline void setPropertyValue(int idx, const QVariant &value) {
- if (data.count() <= idx)
+ if (data.size() <= idx)
data.resize(idx + 1);
data[idx].setValue(value);
}
inline Property &propertyRef(int idx) {
- if (data.count() <= idx)
+ if (data.size() <= idx)
data.resize(idx + 1);
Property &prop = data[idx];
if (!prop.valueSet)
@@ -223,22 +190,18 @@ public:
}
inline bool hasProperty(int idx) const {
- if (idx >= data.count())
+ if (idx >= data.size())
return false;
return data[idx].valueSet;
}
void dropPropertyCache() {
- if (QQmlData *ddata = QQmlData::get(object, /*create*/false)) {
- if (ddata->propertyCache) {
- ddata->propertyCache->release();
- ddata->propertyCache = nullptr;
- }
- }
+ if (QQmlData *ddata = QQmlData::get(object, /*create*/false))
+ ddata->propertyCache.reset();
}
QQmlOpenMetaObject *q;
- QAbstractDynamicMetaObject *parent = nullptr;
+ QDynamicMetaObjectData *parent = nullptr;
QVector<Property> data;
QObject *object;
QQmlRefPointer<QQmlOpenMetaObjectType> type;
@@ -254,19 +217,20 @@ QQmlOpenMetaObject::QQmlOpenMetaObject(QObject *obj, const QMetaObject *base)
d->type->d->referers.insert(this);
QObjectPrivate *op = QObjectPrivate::get(obj);
- d->parent = static_cast<QAbstractDynamicMetaObject *>(op->metaObject);
+ d->parent = op->metaObject;
*static_cast<QMetaObject *>(this) = *d->type->d->mem;
op->metaObject = this;
}
-QQmlOpenMetaObject::QQmlOpenMetaObject(QObject *obj, QQmlOpenMetaObjectType *type)
+QQmlOpenMetaObject::QQmlOpenMetaObject(
+ QObject *obj, const QQmlRefPointer<QQmlOpenMetaObjectType> &type)
: d(new QQmlOpenMetaObjectPrivate(this, obj))
{
d->type = type;
d->type->d->referers.insert(this);
QObjectPrivate *op = QObjectPrivate::get(obj);
- d->parent = static_cast<QAbstractDynamicMetaObject *>(op->metaObject);
+ d->parent = op->metaObject;
*static_cast<QMetaObject *>(this) = *d->type->d->mem;
op->metaObject = this;
}
@@ -292,6 +256,11 @@ void QQmlOpenMetaObject::emitPropertyNotification(const QByteArray &propertyName
activate(d->object, *iter + d->type->d->signalOffset, nullptr);
}
+void QQmlOpenMetaObject::unparent()
+{
+ d->parent = nullptr;
+}
+
int QQmlOpenMetaObject::metaCall(QObject *o, QMetaObject::Call c, int id, void **a)
{
Q_ASSERT(d->object == o);
@@ -303,7 +272,7 @@ int QQmlOpenMetaObject::metaCall(QObject *o, QMetaObject::Call c, int id, void *
propertyRead(propId);
*reinterpret_cast<QVariant *>(a[0]) = d->propertyValue(propId);
} else if (c == QMetaObject::WriteProperty) {
- if (propId >= d->data.count() || d->data.at(propId).value() != *reinterpret_cast<QVariant *>(a[0])) {
+ if (propId >= d->data.size() || d->data.at(propId).value() != *reinterpret_cast<QVariant *>(a[0])) {
propertyWrite(propId);
d->setPropertyValue(propId, propertyWriteValue(propId, *reinterpret_cast<QVariant *>(a[0])));
propertyWritten(propId);
@@ -319,7 +288,7 @@ int QQmlOpenMetaObject::metaCall(QObject *o, QMetaObject::Call c, int id, void *
}
}
-QAbstractDynamicMetaObject *QQmlOpenMetaObject::parent() const
+QDynamicMetaObjectData *QQmlOpenMetaObject::parent() const
{
return d->parent;
}
@@ -408,7 +377,7 @@ void QQmlOpenMetaObject::setValues(const QHash<QByteArray, QVariant> &values, bo
d->type->createProperties(missingProperties);
d->dropPropertyCache();
- for (const QByteArray &name : qAsConst(missingProperties))
+ for (const QByteArray &name : std::as_const(missingProperties))
checkedSetValue(names[name], values[name], force);
}
@@ -427,14 +396,15 @@ void QQmlOpenMetaObject::setCached(bool c)
QQmlData *qmldata = QQmlData::get(d->object, true);
if (d->cacheProperties) {
+ // As the propertyCache is not saved in QQmlMetaType (due to it being dynamic)
+ // we cannot leak it to other places before we're done with it. Yes, it's still
+ // terrible.
if (!d->type->d->cache)
- d->type->d->cache = new QQmlPropertyCache(this);
+ d->type->d->cache = QQmlPropertyCache::createStandalone(this);
qmldata->propertyCache = d->type->d->cache;
- d->type->d->cache->addref();
} else {
- if (d->type->d->cache)
- d->type->d->cache->release();
- qmldata->propertyCache = nullptr;
+ d->type->d->cache.reset();
+ qmldata->propertyCache.reset();
}
}
@@ -493,12 +463,12 @@ QVariant QQmlOpenMetaObject::initialValue(int)
int QQmlOpenMetaObject::count() const
{
- return d->type->d->names.count();
+ return d->type->d->names.size();
}
QByteArray QQmlOpenMetaObject::name(int idx) const
{
- Q_ASSERT(idx >= 0 && idx < d->type->d->names.count());
+ Q_ASSERT(idx >= 0 && idx < d->type->d->names.size());
return d->type->d->mob.property(idx).name();
}
diff --git a/src/qml/qml/qqmlopenmetaobject_p.h b/src/qml/qml/qqmlopenmetaobject_p.h
index 47bba085b5..35e595ec15 100644
--- a/src/qml/qml/qqmlopenmetaobject_p.h
+++ b/src/qml/qml/qqmlopenmetaobject_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLOPENMETAOBJECT_H
#define QQMLOPENMETAOBJECT_H
@@ -64,11 +28,12 @@ QT_BEGIN_NAMESPACE
class QQmlEngine;
class QMetaPropertyBuilder;
class QQmlOpenMetaObjectTypePrivate;
-class Q_QML_PRIVATE_EXPORT QQmlOpenMetaObjectType : public QQmlRefCount
+class Q_QML_EXPORT QQmlOpenMetaObjectType final
+ : public QQmlRefCounted<QQmlOpenMetaObjectType>
{
public:
QQmlOpenMetaObjectType(const QMetaObject *base);
- ~QQmlOpenMetaObjectType() override;
+ ~QQmlOpenMetaObjectType();
void createProperties(const QVector<QByteArray> &names);
int createProperty(const QByteArray &name);
@@ -78,7 +43,6 @@ public:
int propertyCount() const;
QByteArray propertyName(int) const;
- QMetaObject *metaObject() const;
protected:
virtual void propertyCreated(int, QMetaPropertyBuilder &);
@@ -90,11 +54,11 @@ private:
};
class QQmlOpenMetaObjectPrivate;
-class Q_QML_PRIVATE_EXPORT QQmlOpenMetaObject : public QAbstractDynamicMetaObject
+class Q_QML_EXPORT QQmlOpenMetaObject : public QAbstractDynamicMetaObject
{
public:
QQmlOpenMetaObject(QObject *, const QMetaObject * = nullptr);
- QQmlOpenMetaObject(QObject *, QQmlOpenMetaObjectType *);
+ QQmlOpenMetaObject(QObject *, const QQmlRefPointer<QQmlOpenMetaObjectType> &);
~QQmlOpenMetaObject() override;
QVariant value(const QByteArray &) const;
@@ -121,6 +85,7 @@ public:
QQmlOpenMetaObjectType *type() const;
void emitPropertyNotification(const QByteArray &propertyName);
+ void unparent();
protected:
int metaCall(QObject *o, QMetaObject::Call _c, int _id, void **_a) override;
@@ -132,7 +97,7 @@ protected:
virtual void propertyWritten(int);
virtual void propertyCreated(int, QMetaPropertyBuilder &);
- QAbstractDynamicMetaObject *parent() const;
+ QDynamicMetaObjectData *parent() const;
bool checkedSetValue(int index, const QVariant &value, bool force);
diff --git a/src/qml/qml/qqmlparserstatus.cpp b/src/qml/qml/qqmlparserstatus.cpp
index d2aa679a95..522b829e68 100644
--- a/src/qml/qml/qqmlparserstatus.cpp
+++ b/src/qml/qml/qqmlparserstatus.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qqmlparserstatus.h"
diff --git a/src/qml/qml/qqmlparserstatus.h b/src/qml/qml/qqmlparserstatus.h
index f6bcb32a14..9cfb544358 100644
--- a/src/qml/qml/qqmlparserstatus.h
+++ b/src/qml/qml/qqmlparserstatus.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLPARSERSTATUS_H
#define QQMLPARSERSTATUS_H
diff --git a/src/qml/qml/qqmlplatform.cpp b/src/qml/qml/qqmlplatform.cpp
index 077b9f0698..dbd54b5f11 100644
--- a/src/qml/qml/qqmlplatform.cpp
+++ b/src/qml/qml/qqmlplatform.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qqmlplatform_p.h"
#include "qqmlglobal_p.h"
diff --git a/src/qml/qml/qqmlplatform_p.h b/src/qml/qml/qqmlplatform_p.h
index 8378854a80..b8d2167fd5 100644
--- a/src/qml/qml/qqmlplatform_p.h
+++ b/src/qml/qml/qqmlplatform_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLPLATFORM_P_H
#define QQMLPLATFORM_P_H
@@ -57,7 +21,7 @@
QT_BEGIN_NAMESPACE
-class Q_QML_PRIVATE_EXPORT QQmlPlatform : public QObject
+class Q_QML_EXPORT QQmlPlatform : public QObject
{
Q_OBJECT
Q_PROPERTY(QString os READ os CONSTANT)
@@ -78,6 +42,4 @@ private:
QT_END_NAMESPACE
-QML_DECLARE_TYPE(QQmlPlatform)
-
#endif // QQMLPLATFORM_P_H
diff --git a/src/qml/qml/qqmlpluginimporter.cpp b/src/qml/qml/qqmlpluginimporter.cpp
new file mode 100644
index 0000000000..24f12891b9
--- /dev/null
+++ b/src/qml/qml/qqmlpluginimporter.cpp
@@ -0,0 +1,612 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qqmlpluginimporter_p.h"
+#include "qqmlimport_p.h"
+
+#include <private/qqmlextensionplugin_p.h>
+#include <private/qqmltypeloader_p.h>
+#include <private/qqmlglobal_p.h>
+
+#include <QtCore/qobject.h>
+#include <QtCore/qpluginloader.h>
+#include <QtCore/qdir.h>
+#include <QtCore/qloggingcategory.h>
+#include <QtCore/qjsonarray.h>
+
+#include <unordered_map>
+
+QT_BEGIN_NAMESPACE
+
+Q_DECLARE_LOGGING_CATEGORY(lcQmlImport)
+
+struct QmlPlugin {
+ std::unique_ptr<QPluginLoader> loader;
+};
+
+class PluginMap
+{
+ Q_DISABLE_COPY_MOVE(PluginMap)
+public:
+ PluginMap() = default;
+ ~PluginMap() = default;
+
+ // This is a std::unordered_map because QHash cannot handle move-only types.
+ using Container = std::unordered_map<QString, QmlPlugin>;
+
+private:
+ QBasicMutex mutex;
+ Container plugins;
+ friend class PluginMapPtr;
+};
+
+class PluginMapPtr
+{
+ Q_DISABLE_COPY_MOVE(PluginMapPtr)
+public:
+ PluginMapPtr(PluginMap *map) : map(map), locker(&map->mutex) {}
+ ~PluginMapPtr() = default;
+
+ PluginMap::Container &operator*() { return map->plugins; }
+ const PluginMap::Container &operator*() const { return map->plugins; }
+
+ PluginMap::Container *operator->() { return &map->plugins; }
+ const PluginMap::Container *operator->() const { return &map->plugins; }
+
+private:
+ PluginMap *map;
+ QMutexLocker<QBasicMutex> locker;
+};
+
+Q_GLOBAL_STATIC(PluginMap, qmlPluginsById); // stores the uri and the PluginLoaders
+
+static QVector<QStaticPlugin> makePlugins()
+{
+ QVector<QStaticPlugin> plugins;
+ // To avoid traversing all static plugins for all imports, we cut down
+ // the list the first time called to only contain QML plugins:
+ const auto staticPlugins = QPluginLoader::staticPlugins();
+ for (const QStaticPlugin &plugin : staticPlugins) {
+ const QString iid = plugin.metaData().value(QLatin1String("IID")).toString();
+ if (iid == QLatin1String(QQmlEngineExtensionInterface_iid)
+ || iid == QLatin1String(QQmlExtensionInterface_iid)
+ || iid == QLatin1String(QQmlExtensionInterface_iid_old)) {
+ if (Q_UNLIKELY(iid == QLatin1String(QQmlExtensionInterface_iid_old))) {
+ qWarning()
+ << "Found plugin with old IID, this will be unsupported in upcoming Qt releases:"
+ << plugin.metaData();
+ }
+ plugins.append(plugin);
+ }
+ }
+ return plugins;
+}
+
+/*
+ Returns the list of possible versioned URI combinations. For example, if \a uri is
+ QtQml.Models, \a vmaj is 2, and \a vmin is 0, this method returns the following:
+ [QtQml.Models.2.0, QtQml.2.0.Models, QtQml.Models.2, QtQml.2.Models, QtQml.Models]
+ */
+static QStringList versionUriList(const QString &uri, QTypeRevision version)
+{
+ QStringList result;
+ for (int mode = QQmlImports::FullyVersioned; mode <= QQmlImports::Unversioned; ++mode) {
+ int index = uri.size();
+ do {
+ QString versionUri = uri;
+ versionUri.insert(index, QQmlImports::versionString(
+ version, QQmlImports::ImportVersion(mode)));
+ result += versionUri;
+
+ index = uri.lastIndexOf(u'.', index - 1);
+ } while (index > 0 && mode != QQmlImports::Unversioned);
+ }
+ return result;
+}
+
+static bool unloadPlugin(const std::pair<const QString, QmlPlugin> &plugin)
+{
+ const auto &loader = plugin.second.loader;
+ if (!loader)
+ return false;
+
+#if QT_CONFIG(library)
+ if (auto extensionPlugin = qobject_cast<QQmlExtensionPlugin *>(loader->instance()))
+ extensionPlugin->unregisterTypes();
+
+# ifndef Q_OS_MACOS
+ if (!loader->unload()) {
+ qWarning("Unloading %s failed: %s", qPrintable(plugin.first),
+ qPrintable(loader->errorString()));
+ return false;
+ }
+# endif
+#endif
+
+ return true;
+}
+
+void qmlClearEnginePlugins()
+{
+ PluginMapPtr plugins(qmlPluginsById());
+ for (const auto &plugin : std::as_const(*plugins))
+ unloadPlugin(plugin);
+ plugins->clear();
+}
+
+bool QQmlPluginImporter::removePlugin(const QString &pluginId)
+{
+ PluginMapPtr plugins(qmlPluginsById());
+
+ auto it = plugins->find(pluginId);
+ if (it == plugins->end())
+ return false;
+
+ const bool success = unloadPlugin(*it);
+
+ plugins->erase(it);
+ return success;
+}
+
+QStringList QQmlPluginImporter::plugins()
+{
+ PluginMapPtr plugins(qmlPluginsById());
+ QStringList results;
+ for (auto it = plugins->cbegin(), end = plugins->cend(); it != end; ++it) {
+ if (it->second.loader != nullptr)
+ results.append(it->first);
+ }
+ return results;
+}
+
+QString QQmlPluginImporter::truncateToDirectory(const QString &qmldirFilePath)
+{
+ const int slash = qmldirFilePath.lastIndexOf(u'/');
+ return slash > 0 ? qmldirFilePath.left(slash) : qmldirFilePath;
+}
+
+void QQmlPluginImporter::finalizePlugin(QObject *instance, const QString &pluginId) {
+ // The plugin's per-engine initialization does not need lock protection, as this function is
+ // only called from the engine specific loader thread and importDynamicPlugin as well as
+ // importStaticPlugin are the only places of access.
+
+ database->initializedPlugins.insert(pluginId);
+ if (auto *extensionIface = qobject_cast<QQmlExtensionInterface *>(instance))
+ typeLoader->initializeEngine(extensionIface, uri.toUtf8().constData());
+ else if (auto *engineIface = qobject_cast<QQmlEngineExtensionInterface *>(instance))
+ typeLoader->initializeEngine(engineIface, uri.toUtf8().constData());
+}
+
+QTypeRevision QQmlPluginImporter::importStaticPlugin(QObject *instance, const QString &pluginId) {
+ // Dynamic plugins are differentiated by their filepath. For static plugins we
+ // don't have that information so we use their address as key instead.
+ QTypeRevision importVersion = version;
+ {
+ PluginMapPtr plugins(qmlPluginsById());
+
+ // Plugin types are global across all engines and should only be
+ // registered once. But each engine still needs to be initialized.
+ bool typesRegistered = plugins->find(pluginId) != plugins->end();
+
+ if (!typesRegistered) {
+ plugins->insert(std::make_pair(pluginId, QmlPlugin()));
+ if (QQmlMetaType::registerPluginTypes(
+ instance, QFileInfo(qmldirPath).absoluteFilePath(), uri,
+ qmldir->typeNamespace(), importVersion, errors)
+ == QQmlMetaType::RegistrationResult::Failure) {
+ return QTypeRevision();
+ }
+
+ importVersion = QQmlImportDatabase::lockModule(
+ uri, qmldir->typeNamespace(), importVersion, errors);
+ if (!importVersion.isValid())
+ return QTypeRevision();
+ }
+
+ // Release the lock on plugins early as we're done with the global part. Releasing the lock
+ // also allows other QML loader threads to acquire the lock while this thread is blocking
+ // in the initializeEngine call to the gui thread (which in turn may be busy waiting for
+ // other QML loader threads and thus not process the initializeEngine call).
+ }
+
+ if (!database->initializedPlugins.contains(pluginId))
+ finalizePlugin(instance, pluginId);
+
+ return QQmlImports::validVersion(importVersion);
+}
+
+QTypeRevision QQmlPluginImporter::importDynamicPlugin(
+ const QString &filePath, const QString &pluginId, bool optional)
+{
+ QObject *instance = nullptr;
+ QTypeRevision importVersion = version;
+
+ const bool engineInitialized = database->initializedPlugins.contains(pluginId);
+ {
+ PluginMapPtr plugins(qmlPluginsById());
+ bool typesRegistered = plugins->find(pluginId) != plugins->end();
+
+ if (!engineInitialized || !typesRegistered) {
+ const QFileInfo fileInfo(filePath);
+ if (!typesRegistered && optional) {
+ switch (QQmlMetaType::registerPluginTypes(
+ nullptr, fileInfo.absolutePath(), uri, qmldir->typeNamespace(),
+ importVersion, errors)) {
+ case QQmlMetaType::RegistrationResult::NoRegistrationFunction:
+ // try again with plugin
+ break;
+ case QQmlMetaType::RegistrationResult::Success:
+ importVersion = QQmlImportDatabase::lockModule(
+ uri, qmldir->typeNamespace(), importVersion, errors);
+ if (!importVersion.isValid())
+ return QTypeRevision();
+ // instance and loader intentionally left at nullptr
+ plugins->insert(std::make_pair(pluginId, QmlPlugin()));
+ // Not calling initializeEngine with null instance
+ database->initializedPlugins.insert(pluginId);
+ return importVersion;
+ case QQmlMetaType::RegistrationResult::Failure:
+ return QTypeRevision();
+ }
+ }
+
+#if QT_CONFIG(library)
+ if (!typesRegistered) {
+
+ // Check original filePath. If that one is empty, not being able
+ // to load the plugin is not an error. We were just checking if
+ // the types are already available. absoluteFilePath can still be
+ // empty if filePath is not.
+ if (filePath.isEmpty())
+ return QTypeRevision();
+
+ const QString absoluteFilePath = fileInfo.absoluteFilePath();
+ if (!QQml_isFileCaseCorrect(absoluteFilePath)) {
+ if (errors) {
+ QQmlError error;
+ error.setDescription(
+ QQmlImportDatabase::tr("File name case mismatch for \"%1\"")
+ .arg(absoluteFilePath));
+ errors->prepend(error);
+ }
+ return QTypeRevision();
+ }
+
+ QmlPlugin plugin;
+ plugin.loader = std::make_unique<QPluginLoader>(absoluteFilePath);
+ if (!plugin.loader->load()) {
+ if (errors) {
+ QQmlError error;
+ error.setDescription(plugin.loader->errorString());
+ errors->prepend(error);
+ }
+ return QTypeRevision();
+ }
+
+ instance = plugin.loader->instance();
+ plugins->insert(std::make_pair(pluginId, std::move(plugin)));
+
+ // Continue with shared code path for dynamic and static plugins:
+ if (QQmlMetaType::registerPluginTypes(
+ instance, fileInfo.absolutePath(), uri, qmldir->typeNamespace(),
+ importVersion, errors)
+ == QQmlMetaType::RegistrationResult::Failure) {
+ return QTypeRevision();
+ }
+
+ importVersion = QQmlImportDatabase::lockModule(
+ uri, qmldir->typeNamespace(), importVersion, errors);
+ if (!importVersion.isValid())
+ return QTypeRevision();
+ } else {
+ auto it = plugins->find(pluginId);
+ if (it != plugins->end() && it->second.loader)
+ instance = it->second.loader->instance();
+ }
+#else
+ // Here plugin is not optional and NOT QT_CONFIG(library)
+ // Cannot finalize such plugin and return valid, because no types are registered.
+ // Just return invalid.
+ if (!optional)
+ return QTypeRevision();
+#endif // QT_CONFIG(library)
+ }
+
+ // Release the lock on plugins early as we're done with the global part. Releasing the lock
+ // also allows other QML loader threads to acquire the lock while this thread is blocking
+ // in the initializeEngine call to the gui thread (which in turn may be busy waiting for
+ // other QML loader threads and thus not process the initializeEngine call).
+ }
+
+ if (!engineInitialized)
+ finalizePlugin(instance, pluginId);
+
+ return QQmlImports::validVersion(importVersion);
+}
+
+/*!
+ \internal
+
+ Searches for a plugin called \a baseName in \a qmldirPluginPath, taking the
+ path of the qmldir file itself, and the plugin paths of the QQmlImportDatabase
+ into account.
+
+ The baseName is amended with a platform-dependent prefix and suffix to
+ construct the final plugin file name:
+
+ \table
+ \header \li Platform \li Prefix \li Valid suffixes
+ \row \li Windows \li \li \c .dll, \c .d.dll
+ \row \li Unix/Linux \li lib \li \c .so
+ \row \li \macos \li lib \li \c .dylib, \c _debug.dylib \c .bundle, \c .so
+ \row \li Android \li lib \li \c .so, \c _<ABI>.so
+ \endtable
+
+ If the \a qmldirPluginPath is absolute, it is searched first. Then each of the
+ filePluginPath entries in the QQmlImportDatabase is checked in turn. If the
+ entry is relative, it is resolved on top of the path of the qmldir file,
+ otherwise it is taken verbatim. If a "." is found in the filePluginPath, and
+ \a qmldirPluginPath is relative, then \a qmldirPluginPath is used in its
+ place.
+
+ TODO: Document the android special casing.
+
+ TODO: The above paragraph, as well as the code implementing it makes very
+ little sense and is mostly here for backwards compatibility.
+ */
+QString QQmlPluginImporter::resolvePlugin(const QString &qmldirPluginPath, const QString &baseName)
+{
+#if defined(Q_OS_WIN)
+ static const QString prefix;
+ static const QStringList suffixes = {
+ # ifdef QT_DEBUG
+ QLatin1String("d.dll"), // try a qmake-style debug build first
+ QLatin1String(".dll")
+ #else
+ QLatin1String(".dll"),
+ QLatin1String("d.dll") // try a qmake-style debug build after
+ # endif
+ };
+#elif defined(Q_OS_DARWIN)
+ static const QString prefix = QLatin1String("lib");
+ static const QStringList suffixes = {
+ # ifdef QT_DEBUG
+ QLatin1String("_debug.dylib"), // try a qmake-style debug build first
+ QLatin1String(".dylib"),
+ # else
+ QLatin1String(".dylib"),
+ QLatin1String("_debug.dylib"), // try a qmake-style debug build after
+ # endif
+ QLatin1String(".so"),
+ QLatin1String(".bundle")
+ };
+#else // Unix
+ static const QString prefix = QLatin1String("lib");
+ static const QStringList suffixes = {
+ # if defined(Q_OS_ANDROID)
+ QStringLiteral(LIBS_SUFFIX),
+ # endif
+ QLatin1String(".so")
+ };
+#endif
+
+ QStringList searchPaths = database->filePluginPath;
+ bool qmldirPluginPathIsRelative = QDir::isRelativePath(qmldirPluginPath);
+ if (!qmldirPluginPathIsRelative)
+ searchPaths.prepend(qmldirPluginPath);
+
+ for (const QString &pluginPath : std::as_const(searchPaths)) {
+ QString resolvedBasePath;
+ if (pluginPath == QLatin1String(".")) {
+ if (qmldirPluginPathIsRelative && !qmldirPluginPath.isEmpty()
+ && qmldirPluginPath != QLatin1String(".")) {
+ resolvedBasePath = QDir::cleanPath(qmldirPath + u'/' + qmldirPluginPath);
+ } else {
+ resolvedBasePath = qmldirPath;
+ }
+ } else {
+ if (QDir::isRelativePath(pluginPath))
+ resolvedBasePath = QDir::cleanPath(qmldirPath + u'/' + pluginPath);
+ else
+ resolvedBasePath = pluginPath;
+ }
+
+ // hack for resources, should probably go away
+ if (resolvedBasePath.startsWith(u':'))
+ resolvedBasePath = QCoreApplication::applicationDirPath();
+
+ if (!resolvedBasePath.endsWith(u'/'))
+ resolvedBasePath += u'/';
+
+ QString resolvedPath = resolvedBasePath + prefix + baseName;
+ for (const QString &suffix : suffixes) {
+ QString absolutePath = typeLoader->absoluteFilePath(resolvedPath + suffix);
+ if (!absolutePath.isEmpty())
+ return absolutePath;
+ }
+
+#if defined(Q_OS_ANDROID)
+ if (qmldirPath.size() > 25 && qmldirPath.at(0) == QLatin1Char(':')
+ && qmldirPath.at(1) == QLatin1Char('/')
+ && qmldirPath.startsWith(QStringLiteral(":/android_rcc_bundle/qml/"),
+ Qt::CaseInsensitive)) {
+ QString pluginName = qmldirPath.mid(21) + u'/' + baseName;
+ pluginName.replace(QLatin1Char('/'), QLatin1Char('_'));
+ QString bundledPath = resolvedBasePath + QLatin1String("lib") + pluginName;
+ for (const QString &suffix : suffixes) {
+ const QString absolutePath = typeLoader->absoluteFilePath(bundledPath + suffix);
+ if (!absolutePath.isEmpty()) {
+ qWarning("The implicit resolving of Qml plugin locations using the URI "
+ "embedded in the filename has been deprecated. Please use the "
+ "modern CMake API to create QML modules or set the name of "
+ "QML plugin in qmldir file, that matches the name of plugin "
+ "on file system. The correct plugin name is '%s'.",
+ qPrintable(pluginName));
+ return absolutePath;
+ }
+ }
+ }
+#endif
+ }
+
+ qCDebug(lcQmlImport) << "resolvePlugin" << "Could not resolve dynamic plugin with base name"
+ << baseName << "in" << qmldirPath
+ << " file does not exist";
+
+ return QString();
+}
+
+/*
+ Get all static plugins that are QML plugins and has a meta data URI that matches with one of
+ \a versionUris, which is a list of all possible versioned URI combinations - see versionUriList()
+ above.
+ */
+bool QQmlPluginImporter::populatePluginDataVector(QVector<StaticPluginData> &result, const QStringList &versionUris)
+{
+ static const QVector<QStaticPlugin> plugins = makePlugins();
+ for (const QStaticPlugin &plugin : plugins) {
+ // Since a module can list more than one plugin,
+ // we keep iterating even after we found a match.
+ QObject *instance = plugin.instance();
+ if (qobject_cast<QQmlEngineExtensionPlugin *>(instance)
+ || qobject_cast<QQmlExtensionPlugin *>(instance)) {
+ const QJsonArray metaTagsUriList = plugin.metaData().value(
+ QStringLiteral("uri")).toArray();
+ if (metaTagsUriList.isEmpty()) {
+ if (errors) {
+ QQmlError error;
+ error.setDescription(QQmlImportDatabase::tr(
+ "static plugin for module \"%1\" with name \"%2\" "
+ "has no metadata URI")
+ .arg(uri, QString::fromUtf8(
+ instance->metaObject()->className())));
+ error.setUrl(QUrl::fromLocalFile(qmldir->qmldirLocation()));
+ errors->prepend(error);
+ }
+ return false;
+ }
+ // A plugin can be set up to handle multiple URIs, so go through the list:
+ for (const QJsonValueConstRef metaTagUri : metaTagsUriList) {
+ if (versionUris.contains(metaTagUri.toString())) {
+ result.append({ plugin, metaTagsUriList });
+ break;
+ }
+ }
+ }
+ }
+ return true;
+}
+
+QTypeRevision QQmlPluginImporter::importPlugins() {
+ const auto qmldirPlugins = qmldir->plugins();
+ const int qmldirPluginCount = qmldirPlugins.size();
+ QTypeRevision importVersion = version;
+
+ // If the path contains a version marker or if we have more than one plugin,
+ // we need to use paths. In that case we cannot fall back to other instances
+ // of the same module if a qmldir is rejected. However, as we don't generate
+ // such modules, it shouldn't be a problem.
+ const bool canUseUris = qmldirPluginCount == 1
+ && qmldirPath.endsWith(u'/' + QString(uri).replace(u'.', u'/'));
+ const QString moduleId = canUseUris ? uri : qmldir->qmldirLocation();
+
+ if (!database->modulesForWhichPluginsHaveBeenLoaded.contains(moduleId)) {
+ // First search for listed qmldir plugins dynamically. If we cannot resolve them all, we
+ // continue searching static plugins that has correct metadata uri. Note that since we
+ // only know the uri for a static plugin, and not the filename, we cannot know which
+ // static plugin belongs to which listed plugin inside qmldir. And for this reason,
+ // mixing dynamic and static plugins inside a single module is not recommended.
+
+ int dynamicPluginsFound = 0;
+ int staticPluginsFound = 0;
+
+ for (const QQmlDirParser::Plugin &plugin : qmldirPlugins) {
+ const QString resolvedFilePath = resolvePlugin(plugin.path, plugin.name);
+
+ if (!canUseUris && resolvedFilePath.isEmpty())
+ continue;
+
+ importVersion = importDynamicPlugin(
+ resolvedFilePath,
+ canUseUris ? uri : QFileInfo(resolvedFilePath).absoluteFilePath(),
+ plugin.optional);
+ if (importVersion.isValid())
+ ++dynamicPluginsFound;
+ else if (!resolvedFilePath.isEmpty())
+ return QTypeRevision();
+ }
+
+ if (dynamicPluginsFound < qmldirPluginCount) {
+ // Check if the missing plugins can be resolved statically. We do this by looking at
+ // the URIs embedded in a plugins meta data. Since those URIs can be anything from
+ // fully versioned to unversioned, we need to compare with differnt version strings.
+ // If a module has several plugins, they must all have the same version. Start by
+ // populating pluginPairs with relevant plugins to cut the list short early on:
+ const QStringList versionUris = versionUriList(uri, importVersion);
+ QVector<StaticPluginData> pluginPairs;
+ if (!populatePluginDataVector(pluginPairs, versionUris))
+ return QTypeRevision();
+
+ for (const QString &versionUri : versionUris) {
+ for (const StaticPluginData &pair : std::as_const(pluginPairs)) {
+ for (const QJsonValueConstRef metaTagUri : pair.uriList) {
+ if (versionUri == metaTagUri.toString()) {
+ staticPluginsFound++;
+ QObject *instance = pair.plugin.instance();
+ importVersion = importStaticPlugin(
+ instance,
+ canUseUris ? uri : QString::asprintf("%p", instance));
+ if (!importVersion.isValid()){
+ if (errors) {
+ Q_ASSERT(!errors->isEmpty());
+ const QQmlError poppedError = errors->takeFirst();
+ QQmlError error;
+ error.setDescription(
+ QQmlImportDatabase::tr(
+ "static plugin for module \"%1\" with "
+ "name \"%2\" cannot be loaded: %3")
+ .arg(uri, QString::fromUtf8(
+ instance->metaObject()->className()),
+ poppedError.description()));
+ error.setUrl(QUrl::fromLocalFile(qmldir->qmldirLocation()));
+ errors->prepend(error);
+ }
+ return QTypeRevision();
+ }
+
+ qCDebug(lcQmlImport)
+ << "importExtension" << "loaded static plugin " << versionUri;
+
+ break;
+ }
+ }
+ }
+ if (staticPluginsFound > 0)
+ break;
+ }
+ }
+
+ if ((dynamicPluginsFound + staticPluginsFound) < qmldirPluginCount) {
+ if (errors) {
+ QQmlError error;
+ if (qmldirPluginCount > 1 && staticPluginsFound > 0) {
+ error.setDescription(QQmlImportDatabase::tr(
+ "could not resolve all plugins for module \"%1\"")
+ .arg(uri));
+ } else {
+ error.setDescription(QQmlImportDatabase::tr(
+ "module \"%1\" plugin \"%2\" not found")
+ .arg(uri, qmldirPlugins[dynamicPluginsFound].name));
+ }
+ error.setUrl(QUrl::fromLocalFile(qmldir->qmldirLocation()));
+ errors->prepend(error);
+ }
+ return QTypeRevision();
+ }
+
+ database->modulesForWhichPluginsHaveBeenLoaded.insert(moduleId);
+ }
+ return QQmlImports::validVersion(importVersion);
+}
+
+QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlpluginimporter_p.h b/src/qml/qml/qqmlpluginimporter_p.h
new file mode 100644
index 0000000000..b0056e8e33
--- /dev/null
+++ b/src/qml/qml/qqmlpluginimporter_p.h
@@ -0,0 +1,81 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QQMLPLUGINIMPORTER_P_H
+#define QQMLPLUGINIMPORTER_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 <private/qtqmlglobal_p.h>
+#include <private/qqmlimport_p.h>
+#include <private/qqmltypeloaderqmldircontent_p.h>
+
+#include <QtCore/qjsonarray.h>
+#include <QtCore/qplugin.h>
+#include <QtCore/qversionnumber.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQmlPluginImporter
+{
+ Q_DISABLE_COPY_MOVE(QQmlPluginImporter)
+
+public:
+ QQmlPluginImporter(const QString &uri, QTypeRevision version, QQmlImportDatabase *database,
+ const QQmlTypeLoaderQmldirContent *qmldir, QQmlTypeLoader *typeLoader,
+ QList<QQmlError> *errors)
+ : uri(uri)
+ , qmldirPath(truncateToDirectory(qmldir->qmldirLocation()))
+ , qmldir(qmldir)
+ , database(database)
+ , typeLoader(typeLoader)
+ , errors(errors)
+ , version(version)
+ {}
+
+ ~QQmlPluginImporter() = default;
+
+ QTypeRevision importDynamicPlugin(
+ const QString &filePath, const QString &pluginId, bool optional);
+ QTypeRevision importStaticPlugin(QObject *instance, const QString &pluginId);
+ QTypeRevision importPlugins();
+
+ static bool removePlugin(const QString &pluginId);
+ static QStringList plugins();
+
+private:
+ struct StaticPluginData {
+ QStaticPlugin plugin;
+ QJsonArray uriList;
+ };
+
+ static QString truncateToDirectory(const QString &qmldirFilePath);
+ bool populatePluginDataVector(QVector<StaticPluginData> &result,
+ const QStringList &versionUris);
+
+ QString resolvePlugin(const QString &qmldirPluginPath, const QString &baseName);
+ void finalizePlugin(QObject *instance, const QString &path);
+
+ const QString uri;
+ const QString qmldirPath;
+
+ const QQmlTypeLoaderQmldirContent *qmldir = nullptr;
+ QQmlImportDatabase *database = nullptr;
+ QQmlTypeLoader *typeLoader = nullptr;
+ QList<QQmlError> *errors = nullptr;
+
+ const QTypeRevision version;
+};
+
+QT_END_NAMESPACE
+
+#endif // QQMLPLUGINIMPORTER_P_H
diff --git a/src/qml/qml/qqmlprivate.h b/src/qml/qml/qqmlprivate.h
index fb2d80b3df..92c9765509 100644
--- a/src/qml/qml/qqmlprivate.h
+++ b/src/qml/qml/qqmlprivate.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLPRIVATE_H
#define QQMLPRIVATE_H
@@ -51,29 +15,32 @@
// We mean it.
//
-#include <functional>
-#include <type_traits>
-
-#include <QtQml/qtqmlglobal.h>
-#include <QtQml/qqmlparserstatus.h>
+#include <QtQml/qjsprimitivevalue.h>
+#include <QtQml/qjsvalue.h>
#include <QtQml/qqmllist.h>
+#include <QtQml/qqmlparserstatus.h>
#include <QtQml/qqmlpropertyvaluesource.h>
-#include <QtQml/qjsvalue.h>
+#include <QtQml/qtqmlglobal.h>
+#include <QtCore/qdatetime.h>
+#include <QtCore/qdebug.h>
#include <QtCore/qglobal.h>
-#include <QtCore/qvariant.h>
-#include <QtCore/qurl.h>
+#include <QtCore/qmetacontainer.h>
+#include <QtCore/qmetaobject.h>
#include <QtCore/qpointer.h>
+#include <QtCore/qurl.h>
+#include <QtCore/qvariant.h>
#include <QtCore/qversionnumber.h>
-#include <QtCore/qmetaobject.h>
-#include <QtCore/qmetacontainer.h>
-#include <QtCore/qdebug.h>
+#include <functional>
+#include <limits>
+#include <type_traits>
QT_BEGIN_NAMESPACE
class QQmlPropertyValueInterceptor;
-class QQmlContext;
+class QQmlContextData;
+class QQmlFinalizerHook;
namespace QQmlPrivate {
struct CachedQmlUnit;
@@ -83,9 +50,9 @@ using QQmlAttachedPropertiesFunc = A *(*)(QObject *);
namespace QV4 {
struct ExecutionEngine;
+class ExecutableCompilationUnit;
namespace CompiledData {
struct Unit;
-struct CompilationUnit;
}
}
namespace QmlIR {
@@ -115,6 +82,10 @@ class QQmlEngine;
class QQmlCustomParser;
class QQmlTypeNotAvailable;
+class QQmlV4Function;
+using QQmlV4FunctionPtr = QQmlV4Function *;
+using QQmlV4ExecutionEnginePtr = QV4::ExecutionEngine *;
+
template<class T>
QQmlCustomParser *qmlCreateCustomParser()
{
@@ -139,13 +110,16 @@ namespace QQmlPrivate
// the size that was allocated.
::operator delete (ptr);
}
+#ifdef Q_CC_MSVC
static void operator delete(void *, void *) {
// Deliberately empty placement delete operator.
// Silences MSVC warning C4291: no matching operator delete found
+ // On MinGW it causes -Wmismatched-new-delete, though.
}
+#endif
};
- enum class ConstructionMode
+ enum class SingletonConstructionMode
{
None,
Constructor,
@@ -170,33 +144,45 @@ namespace QQmlPrivate
};
template<typename T, typename WrapperT>
- constexpr ConstructionMode constructionMode()
+ constexpr SingletonConstructionMode singletonConstructionMode()
{
if constexpr (!std::is_base_of<QObject, T>::value)
- return ConstructionMode::None;
+ return SingletonConstructionMode::None;
if constexpr (!std::is_same_v<T, WrapperT> && HasSingletonFactory<T, WrapperT>::value)
- return ConstructionMode::FactoryWrapper;
+ return SingletonConstructionMode::FactoryWrapper;
if constexpr (std::is_default_constructible<T>::value)
- return ConstructionMode::Constructor;
+ return SingletonConstructionMode::Constructor;
if constexpr (HasSingletonFactory<T>::value)
- return ConstructionMode::Factory;
+ return SingletonConstructionMode::Factory;
- return ConstructionMode::None;
+ return SingletonConstructionMode::None;
}
+ template<typename>
+ struct QmlMarkerFunction;
+
+ template<typename Ret, typename Class>
+ struct QmlMarkerFunction<Ret (Class::*)()>
+ {
+ using ClassType = Class;
+ };
+
+ template<typename T, typename Marker>
+ using QmlTypeHasMarker = std::is_same<T, typename QmlMarkerFunction<Marker>::ClassType>;
+
template<typename T>
void createInto(void *memory, void *) { new (memory) QQmlElement<T>; }
- template<typename T, typename WrapperT, ConstructionMode Mode>
+ template<typename T, typename WrapperT, SingletonConstructionMode Mode>
QObject *createSingletonInstance(QQmlEngine *q, QJSEngine *j)
{
Q_UNUSED(q);
Q_UNUSED(j);
- if constexpr (Mode == ConstructionMode::Constructor)
+ if constexpr (Mode == SingletonConstructionMode::Constructor)
return new T;
- else if constexpr (Mode == ConstructionMode::Factory)
+ else if constexpr (Mode == SingletonConstructionMode::Factory)
return T::create(q, j);
- else if constexpr (Mode == ConstructionMode::FactoryWrapper)
+ else if constexpr (Mode == SingletonConstructionMode::FactoryWrapper)
return WrapperT::create(q, j);
else
return nullptr;
@@ -210,39 +196,43 @@ namespace QQmlPrivate
using CreateParentFunction = QObject *(*)(QObject *);
using CreateValueTypeFunction = QVariant (*)(const QJSValue &);
- template<typename T, typename WrapperT = T, ConstructionMode Mode = constructionMode<T, WrapperT>()>
+ template<typename T, typename WrapperT = T,
+ SingletonConstructionMode Mode = singletonConstructionMode<T, WrapperT>()>
struct Constructors;
template<typename T, typename WrapperT>
- struct Constructors<T, WrapperT, ConstructionMode::Constructor>
+ struct Constructors<T, WrapperT, SingletonConstructionMode::Constructor>
{
static constexpr CreateIntoFunction createInto
= QQmlPrivate::createInto<T>;
static constexpr CreateSingletonFunction createSingletonInstance
- = QQmlPrivate::createSingletonInstance<T, WrapperT, ConstructionMode::Constructor>;
+ = QQmlPrivate::createSingletonInstance<
+ T, WrapperT, SingletonConstructionMode::Constructor>;
};
template<typename T, typename WrapperT>
- struct Constructors<T, WrapperT, ConstructionMode::None>
+ struct Constructors<T, WrapperT, SingletonConstructionMode::None>
{
static constexpr CreateIntoFunction createInto = nullptr;
static constexpr CreateSingletonFunction createSingletonInstance = nullptr;
};
template<typename T, typename WrapperT>
- struct Constructors<T, WrapperT, ConstructionMode::Factory>
+ struct Constructors<T, WrapperT, SingletonConstructionMode::Factory>
{
static constexpr CreateIntoFunction createInto = nullptr;
static constexpr CreateSingletonFunction createSingletonInstance
- = QQmlPrivate::createSingletonInstance<T, WrapperT, ConstructionMode::Factory>;
+ = QQmlPrivate::createSingletonInstance<
+ T, WrapperT, SingletonConstructionMode::Factory>;
};
template<typename T, typename WrapperT>
- struct Constructors<T, WrapperT, ConstructionMode::FactoryWrapper>
+ struct Constructors<T, WrapperT, SingletonConstructionMode::FactoryWrapper>
{
static constexpr CreateIntoFunction createInto = nullptr;
static constexpr CreateSingletonFunction createSingletonInstance
- = QQmlPrivate::createSingletonInstance<T, WrapperT, ConstructionMode::FactoryWrapper>;
+ = QQmlPrivate::createSingletonInstance<
+ T, WrapperT, SingletonConstructionMode::FactoryWrapper>;
};
template<typename T,
@@ -380,11 +370,13 @@ namespace QQmlPrivate
struct Properties<Parent, void>
{
using Func = QQmlAttachedPropertiesFunc<QObject>;
- static const QMetaObject *staticMetaObject() { return nullptr; };
- static Func attachedPropertiesFunc() { return nullptr; };
+ static const QMetaObject *staticMetaObject() { return nullptr; }
+ static Func attachedPropertiesFunc() { return nullptr; }
};
- using Type = typename OverridableAttachedType<T, typename T::QmlAttachedType>::Type;
+ using Type = typename std::conditional<
+ QmlTypeHasMarker<T, decltype(&T::qt_qmlMarker_attached)>::value,
+ typename OverridableAttachedType<T, typename T::QmlAttachedType>::Type, void>::type;
using Func = typename Properties<T, Type>::Func;
static const QMetaObject *staticMetaObject()
@@ -444,7 +436,18 @@ namespace QQmlPrivate
enum AutoParentResult { Parented, IncompatibleObject, IncompatibleParent };
typedef AutoParentResult (*AutoParentFunction)(QObject *object, QObject *parent);
+ enum class ValueTypeCreationMethod { None, Construct, Structured };
+
struct RegisterType {
+ enum StructVersion: int {
+ Base = 0,
+ FinalizerCast = 1,
+ CreationMethod = 2,
+ CurrentVersion = CreationMethod,
+ };
+
+ bool has(StructVersion v) const { return structVersion >= int(v); }
+
int structVersion;
QMetaType typeId;
@@ -455,6 +458,7 @@ namespace QQmlPrivate
void *userdata;
QString noCreationReason;
+ // ### Qt7: Get rid of this. It can be covered by creationMethod below.
QVariant (*createValueType)(const QJSValue &);
const char *uri;
@@ -475,6 +479,9 @@ namespace QQmlPrivate
QQmlCustomParser *customParser;
QTypeRevision revision;
+ int finalizerCast;
+
+ ValueTypeCreationMethod creationMethod;
// If this is extended ensure "version" is bumped!!!
};
@@ -507,6 +514,10 @@ namespace QQmlPrivate
QQmlCustomParser *(*customParserFactory)();
QVector<int> *qmlTypeIds;
+ int finalizerCast;
+
+ bool forceAnonymous;
+ QMetaSequence listMetaSequence;
};
struct RegisterInterface {
@@ -584,7 +595,11 @@ namespace QQmlPrivate
int structVersion;
const char *uri;
QTypeRevision version;
+
+ // ### Qt7: Remove typeName. It's ignored because the only valid name is "list",
+ // and that's automatic.
const char *typeName;
+
QMetaType typeId;
QMetaSequence metaSequence;
QTypeRevision revision;
@@ -603,22 +618,139 @@ namespace QQmlPrivate
};
struct Q_QML_EXPORT AOTCompiledContext {
- QQmlContext *qmlContext;
+ enum: uint { InvalidStringId = (std::numeric_limits<uint>::max)() };
+
+ QQmlContextData *qmlContext;
QObject *qmlScopeObject;
QJSEngine *engine;
- QV4::CompiledData::CompilationUnit *compilationUnit;
+ union {
+ QV4::ExecutableCompilationUnit *compilationUnit;
+ qintptr extraData;
+ };
+
+ QObject *thisObject() const;
+ QQmlEngine *qmlEngine() const;
QJSValue jsMetaType(int index) const;
void setInstructionPointer(int offset) const;
+ void setReturnValueUndefined() const;
+
+ // Run QQmlPropertyCapture::captureProperty() without retrieving the value.
+ bool captureLookup(uint index, QObject *object) const;
+ bool captureQmlContextPropertyLookup(uint index) const;
+ void captureTranslation() const;
+ QString translationContext() const;
+ QMetaType lookupResultMetaType(uint index) const;
+ void storeNameSloppy(uint nameIndex, void *value, QMetaType type) const;
+ QJSValue javaScriptGlobalProperty(uint nameIndex) const;
+
+ const QLoggingCategory *resolveLoggingCategory(QObject *wrapper, bool *ok) const;
+
+ void writeToConsole(
+ QtMsgType type, const QString &message,
+ const QLoggingCategory *loggingCategory) const;
+
+ QVariant constructValueType(
+ QMetaType resultMetaType, const QMetaObject *resultMetaObject,
+ int ctorIndex, void *ctorArg) const;
+
+ // Those are explicit arguments to the Date() ctor, not implicit coercions.
+ QDateTime constructDateTime(double timestamp) const;
+ QDateTime constructDateTime(const QString &string) const;
+ QDateTime constructDateTime(const QJSPrimitiveValue &arg) const
+ {
+ return arg.type() == QJSPrimitiveValue::String
+ ? constructDateTime(arg.toString())
+ : constructDateTime(arg.toDouble());
+ }
+
+ QDateTime constructDateTime(
+ double year, double month, double day = 1,
+ double hours = 0, double minutes = 0, double seconds = 0, double msecs = 0) const;
+
+ // All of these lookup functions should be used as follows:
+ //
+ // while (!fooBarLookup(...)) {
+ // setInstructionPointer(...);
+ // initFooBarLookup(...);
+ // if (engine->hasException()) {
+ // ...
+ // break;
+ // }
+ // }
+ //
+ // The bool-returning *Lookup functions exclusively run the happy path and return false if
+ // that fails in any way. The failure may either be in the lookup structs not being
+ // initialized or an exception being thrown.
+ // The init*Lookup functions initialize the lookup structs and amend any exceptions
+ // previously thrown with line numbers. They might also throw their own exceptions. If an
+ // exception is present after the initialization there is no way to carry out the lookup and
+ // the exception should be propagated. If not, the original lookup can be tried again.
+
+ bool callQmlContextPropertyLookup(
+ uint index, void **args, const QMetaType *types, int argc) const;
+ void initCallQmlContextPropertyLookup(uint index) const;
+
+ bool loadContextIdLookup(uint index, void *target) const;
+ void initLoadContextIdLookup(uint index) const;
+
+ bool callObjectPropertyLookup(uint index, QObject *object,
+ void **args, const QMetaType *types, int argc) const;
+ void initCallObjectPropertyLookup(uint index) const;
+
+ bool callGlobalLookup(uint index, void **args, const QMetaType *types, int argc) const;
+ void initCallGlobalLookup(uint index) const;
+
+ bool loadGlobalLookup(uint index, void *target, QMetaType type) const;
+ void initLoadGlobalLookup(uint index) const;
+
+ bool loadScopeObjectPropertyLookup(uint index, void *target) const;
+ bool writeBackScopeObjectPropertyLookup(uint index, void *source) const;
+ void initLoadScopeObjectPropertyLookup(uint index, QMetaType type) const;
+
+ bool loadSingletonLookup(uint index, void *target) const;
+ void initLoadSingletonLookup(uint index, uint importNamespace) const;
+
+ bool loadAttachedLookup(uint index, QObject *object, void *target) const;
+ void initLoadAttachedLookup(uint index, uint importNamespace, QObject *object) const;
+
+ bool loadTypeLookup(uint index, void *target) const;
+ void initLoadTypeLookup(uint index, uint importNamespace) const;
+
+ bool getObjectLookup(uint index, QObject *object, void *target) const;
+ bool writeBackObjectLookup(uint index, QObject *object, void *source) const;
+ void initGetObjectLookup(uint index, QObject *object, QMetaType type) const;
+
+ bool getValueLookup(uint index, void *value, void *target) const;
+ bool writeBackValueLookup(uint index, void *value, void *source) const;
+ void initGetValueLookup(uint index, const QMetaObject *metaObject, QMetaType type) const;
+
+ bool getEnumLookup(uint index, void *target) const;
+#if QT_QML_REMOVED_SINCE(6, 6)
+ bool getEnumLookup(uint index, int *target) const;
+#endif
+ void initGetEnumLookup(uint index, const QMetaObject *metaObject,
+ const char *enumerator, const char *enumValue) const;
+
+ bool setObjectLookup(uint index, QObject *object, void *value) const;
+ void initSetObjectLookup(uint index, QObject *object, QMetaType type) const;
+
+ bool setValueLookup(uint index, void *target, void *value) const;
+ void initSetValueLookup(uint index, const QMetaObject *metaObject, QMetaType type) const;
};
struct AOTCompiledFunction {
- int index;
- QMetaType returnType;
- QList<QMetaType> argumentTypes;
- void (*functionPtr)(const AOTCompiledContext *context, void *resultPtr, void **arguments);
+ int functionIndex;
+ int numArguments;
+ void (*signature)(QV4::ExecutableCompilationUnit *unit, QMetaType *argTypes);
+ void (*functionPtr)(const AOTCompiledContext *context, void **argv);
};
+#if QT_DEPRECATED_SINCE(6, 6)
+ QT_DEPRECATED_VERSION_X(6, 6, "Use AOTCompiledFunction instead")
+ typedef AOTCompiledFunction TypedFunction;
+#endif
+
struct CachedQmlUnit {
const QV4::CompiledData::Unit *qmlData;
const AOTCompiledFunction *aotCompiledFunctions;
@@ -647,21 +779,38 @@ namespace QQmlPrivate
int Q_QML_EXPORT qmlregister(RegistrationType, void *);
void Q_QML_EXPORT qmlunregister(RegistrationType, quintptr);
+
+#if QT_DEPRECATED_SINCE(6, 3)
struct Q_QML_EXPORT SingletonFunctor
{
+ QT_DEPRECATED QObject *operator()(QQmlEngine *, QJSEngine *);
+ QPointer<QObject> m_object;
+ bool alreadyCalled = false;
+ };
+#endif
+
+ struct Q_QML_EXPORT SingletonInstanceFunctor
+ {
QObject *operator()(QQmlEngine *, QJSEngine *);
QPointer<QObject> m_object;
- bool alreadyCalled = false;
+
+ // Not a QPointer, so that you cannot assign it to a different
+ // engine when the first one is deleted.
+ // That would mess up the QML contexts.
+ QQmlEngine *m_engine = nullptr;
};
- static int indexOfOwnClassInfo(const QMetaObject *metaObject, const char *key)
+ static int indexOfOwnClassInfo(const QMetaObject *metaObject, const char *key, int startOffset = -1)
{
if (!metaObject || !key)
return -1;
const int offset = metaObject->classInfoOffset();
- for (int i = metaObject->classInfoCount() + offset - 1; i >= offset; --i)
+ const int start = (startOffset == -1)
+ ? (metaObject->classInfoCount() + offset - 1)
+ : startOffset;
+ for (int i = start; i >= offset; --i)
if (qstrcmp(key, metaObject->classInfo(i).name()) == 0) {
return i;
}
@@ -679,38 +828,18 @@ namespace QQmlPrivate
const int index = indexOfOwnClassInfo(metaObject, key);
return (index == -1) ? defaultValue
: QTypeRevision::fromEncodedVersion(
- QByteArray(metaObject->classInfo(index).value()).toInt());
+ QLatin1StringView(metaObject->classInfo(index).value()).toInt());
}
+ Q_QML_EXPORT QList<QTypeRevision> revisionClassInfos(const QMetaObject *metaObject, const char *key);
+
inline bool boolClassInfo(const QMetaObject *metaObject, const char *key,
bool defaultValue = false)
{
const int index = indexOfOwnClassInfo(metaObject, key);
- return (index == -1) ? defaultValue
- : (QByteArray(metaObject->classInfo(index).value()) == "true");
- }
-
- inline const char *classElementName(const QMetaObject *metaObject)
- {
- const char *elementName = classInfo(metaObject, "QML.Element");
- if (qstrcmp(elementName, "auto") == 0) {
- const char *strippedClassName = metaObject->className();
- for (const char *c = strippedClassName; *c != '\0'; c++) {
- if (*c == ':')
- strippedClassName = c + 1;
- }
-
- return strippedClassName;
- }
- if (qstrcmp(elementName, "anonymous") == 0)
- return nullptr;
-
- if (!elementName) {
- qWarning().nospace() << "Missing QML.Element class info \"" << elementName << "\""
- << " for " << metaObject->className();
- }
-
- return elementName;
+ if (index == -1)
+ return defaultValue;
+ return qstrcmp(metaObject->classInfo(index).value(), "true") == 0;
}
template<class T, class = std::void_t<>>
@@ -722,7 +851,9 @@ namespace QQmlPrivate
template<class T>
struct QmlExtended<T, std::void_t<typename T::QmlExtendedType>>
{
- using Type = typename T::QmlExtendedType;
+ using Type = typename std::conditional<
+ QmlTypeHasMarker<T, decltype(&T::qt_qmlMarker_extended)>::value,
+ typename T::QmlExtendedType, void>::type;
};
template<class T, class = std::void_t<>>
@@ -734,7 +865,13 @@ namespace QQmlPrivate
template<class T>
struct QmlExtendedNamespace<T, std::void_t<decltype(T::qmlExtendedNamespace())>>
{
- static constexpr const QMetaObject *metaObject() { return T::qmlExtendedNamespace(); }
+ static constexpr const QMetaObject *metaObject()
+ {
+ if constexpr (QmlTypeHasMarker<T, decltype(&T::qt_qmlMarker_extendedNamespace)>::value)
+ return T::qmlExtendedNamespace();
+ else
+ return nullptr;
+ }
};
template<class T, class = std::void_t<>>
@@ -746,9 +883,40 @@ namespace QQmlPrivate
template<class T>
struct QmlResolved<T, std::void_t<typename T::QmlForeignType>>
{
- using Type = typename T::QmlForeignType;
+ using Type = typename std::conditional<
+ QmlTypeHasMarker<T, decltype(&T::qt_qmlMarker_foreign)>::value,
+ typename T::QmlForeignType, T>::type;
+ };
+
+ template<class T, class = std::void_t<>>
+ struct QmlUncreatable
+ {
+ static constexpr bool Value = false;
+ };
+
+ template<class T>
+ struct QmlUncreatable<T, std::void_t<typename T::QmlIsUncreatable>>
+ {
+ static constexpr bool Value =
+ QmlTypeHasMarker<T, decltype(&T::qt_qmlMarker_uncreatable)>::value
+ && bool(T::QmlIsUncreatable::yes);
+ };
+
+ template<class T, class = std::void_t<>>
+ struct QmlAnonymous
+ {
+ static constexpr bool Value = false;
+ };
+
+ template<class T>
+ struct QmlAnonymous<T, std::void_t<typename T::QmlIsAnonymous>>
+ {
+ static constexpr bool Value =
+ QmlTypeHasMarker<T, decltype(&T::qt_qmlMarker_anonymous)>::value
+ && bool(T::QmlIsAnonymous::yes);
};
+
template<class T, class = std::void_t<>>
struct QmlSingleton
{
@@ -758,7 +926,9 @@ namespace QQmlPrivate
template<class T>
struct QmlSingleton<T, std::void_t<typename T::QmlIsSingleton>>
{
- static constexpr bool Value = bool(T::QmlIsSingleton::yes);
+ static constexpr bool Value =
+ QmlTypeHasMarker<T, decltype(&T::qt_qmlMarker_singleton)>::value
+ && bool(T::QmlIsSingleton::yes);
};
template<class T, class = std::void_t<>>
@@ -782,7 +952,7 @@ namespace QQmlPrivate
};
template<class T>
- struct QmlInterface<T, std::void_t<typename T::QmlIsInterface>>
+ struct QmlInterface<T, std::void_t<typename T::QmlIsInterface, decltype(qobject_interface_iid<T *>())>>
{
static constexpr bool Value = bool(T::QmlIsInterface::yes);
};
@@ -802,7 +972,17 @@ namespace QQmlPrivate
template<class T>
struct QmlMetaType
{
- static QMetaType self()
+ static constexpr bool hasAcceptableCtors()
+ {
+ if constexpr (!std::is_default_constructible_v<T>)
+ return false;
+ else if constexpr (std::is_base_of_v<QObject, T>)
+ return true;
+ else
+ return std::is_copy_constructible_v<T>;
+ }
+
+ static constexpr QMetaType self()
{
if constexpr (std::is_base_of_v<QObject, T>)
return QMetaType::fromType<T*>();
@@ -810,20 +990,44 @@ namespace QQmlPrivate
return QMetaType::fromType<T>();
}
- static QMetaType list()
+ static constexpr QMetaType list()
{
if constexpr (std::is_base_of_v<QObject, T>)
return QMetaType::fromType<QQmlListProperty<T>>();
else
- return QMetaType();
+ return QMetaType::fromType<QList<T>>();
+ }
+
+ static constexpr QMetaSequence sequence()
+ {
+ if constexpr (std::is_base_of_v<QObject, T>)
+ return QMetaSequence();
+ else
+ return QMetaSequence::fromContainer<QList<T>>();
+ }
+
+ static constexpr int size()
+ {
+ return sizeof(T);
}
};
+ template<>
+ struct QmlMetaType<void>
+ {
+ static constexpr bool hasAcceptableCtors() { return true; }
+ static constexpr QMetaType self() { return QMetaType(); }
+ static constexpr QMetaType list() { return QMetaType(); }
+ static constexpr QMetaSequence sequence() { return QMetaSequence(); }
+ static constexpr int size() { return 0; }
+ };
+
template<typename T, typename E, typename WrapperT = T>
void qmlRegisterSingletonAndRevisions(const char *uri, int versionMajor,
const QMetaObject *classInfoMetaObject,
QVector<int> *qmlTypeIds, const QMetaObject *extension)
{
+ static_assert(std::is_base_of_v<QObject, T>);
RegisterSingletonTypeAndRevisions api = {
0,
@@ -849,14 +1053,16 @@ namespace QQmlPrivate
template<typename T, typename E>
void qmlRegisterTypeAndRevisions(const char *uri, int versionMajor,
const QMetaObject *classInfoMetaObject,
- QVector<int> *qmlTypeIds, const QMetaObject *extension)
+ QVector<int> *qmlTypeIds, const QMetaObject *extension,
+ bool forceAnonymous = false)
{
RegisterTypeAndRevisions type = {
- 0,
+ 3,
QmlMetaType<T>::self(),
QmlMetaType<T>::list(),
- int(sizeof(T)),
- Constructors<T>::createInto, nullptr,
+ QmlMetaType<T>::size(),
+ Constructors<T>::createInto,
+ nullptr,
ValueType<T, E>::create,
uri,
@@ -876,9 +1082,16 @@ namespace QQmlPrivate
extension ? extension : ExtendedType<E>::staticMetaObject(),
&qmlCreateCustomParser<T>,
- qmlTypeIds
+ qmlTypeIds,
+ StaticCastSelector<T, QQmlFinalizerHook>::cast(),
+
+ forceAnonymous,
+ QmlMetaType<T>::sequence(),
};
+ // Initialize the extension so that we can find it by name or ID.
+ qMetaTypeId<E>();
+
qmlregister(TypeAndRevisionsRegistration, &type);
}
@@ -903,7 +1116,7 @@ namespace QQmlPrivate
template<>
void Q_QML_EXPORT qmlRegisterTypeAndRevisions<QQmlTypeNotAvailable, void>(
const char *uri, int versionMajor, const QMetaObject *classInfoMetaObject,
- QVector<int> *qmlTypeIds, const QMetaObject *);
+ QVector<int> *qmlTypeIds, const QMetaObject *, bool);
constexpr QtPrivate::QMetaTypeInterface metaTypeForNamespace(
const QtPrivate::QMetaTypeInterface::MetaObjectFn &metaObjectFunction, const char *name)
@@ -929,8 +1142,26 @@ namespace QQmlPrivate
};
}
+ Q_QML_EXPORT QObject *qmlExtendedObject(QObject *, int);
+
+ enum QmlRegistrationWarning {
+ UnconstructibleType,
+ UnconstructibleSingleton,
+ NonQObjectWithAtached,
+ };
+
+ Q_QML_EXPORT void qmlRegistrationWarning(QmlRegistrationWarning warning, QMetaType type);
+
+ Q_QML_EXPORT QMetaType compositeMetaType(
+ QV4::ExecutableCompilationUnit *unit, const QString &elementName);
+ Q_QML_EXPORT QMetaType compositeListMetaType(
+ QV4::ExecutableCompilationUnit *unit, const QString &elementName);
+
} // namespace QQmlPrivate
QT_END_NAMESPACE
+Q_DECLARE_OPAQUE_POINTER(QQmlV4FunctionPtr)
+Q_DECLARE_OPAQUE_POINTER(QQmlV4ExecutionEnginePtr)
+
#endif // QQMLPRIVATE_H
diff --git a/src/qml/qml/qqmlproperty.cpp b/src/qml/qml/qqmlproperty.cpp
index af5d916c68..7c78fbb984 100644
--- a/src/qml/qml/qqmlproperty.cpp
+++ b/src/qml/qml/qqmlproperty.cpp
@@ -1,78 +1,41 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qqmlproperty.h"
-#include "qqmlproperty_p.h"
-
-#include "qqml.h"
-#include "qqmlbinding_p.h"
-#include "qqmlboundsignal_p.h"
-#include "qqmlcontext.h"
-#include "qqmlcontext_p.h"
-#include "qqmlboundsignal_p.h"
-#include "qqmlengine.h"
-#include "qqmlengine_p.h"
-#include "qqmldata_p.h"
-#include "qqmlstringconverters_p.h"
-#include "qqmllist_p.h"
-#include "qqmlvmemetaobject_p.h"
-#include "qqmlexpression_p.h"
-#include "qqmlvaluetypeproxybinding_p.h"
-#include <private/qjsvalue_p.h>
-#include <private/qv4functionobject_p.h>
-#include <QStringList>
-#include <QVector>
+#include <private/qjsvalue_p.h>
#include <private/qmetaobject_p.h>
+#include <private/qproperty_p.h>
+#include <private/qqmlboundsignal_p.h>
+#include <private/qqmlbuiltinfunctions_p.h>
+#include <private/qqmldata_p.h>
+#include <private/qqmlengine_p.h>
+#include <private/qqmlirbuilder_p.h>
+#include <private/qqmllist_p.h>
+#include <private/qqmlproperty_p.h>
+#include <private/qqmlsignalnames_p.h>
+#include <private/qqmlstringconverters_p.h>
+#include <private/qqmlvaluetypeproxybinding_p.h>
#include <private/qqmlvaluetypewrapper_p.h>
+#include <private/qqmlvmemetaobject_p.h>
+#include <private/qv4functionobject_p.h>
+#include <private/qv4qobjectwrapper_p.h>
+
+#include <QtQml/qqmlcontext.h>
+#include <QtQml/qqmlengine.h>
+#include <QtQml/qqmlpropertymap.h>
+
#include <QtCore/qdebug.h>
-#include <cmath>
-#include <QtQml/QQmlPropertyMap>
+#include <QtCore/qsequentialiterable.h>
+#include <QtCore/qstringlist.h>
+#include <QtCore/qvector.h>
-Q_DECLARE_METATYPE(QList<int>)
-Q_DECLARE_METATYPE(QList<qreal>)
-Q_DECLARE_METATYPE(QList<bool>)
-Q_DECLARE_METATYPE(QList<QString>)
-Q_DECLARE_METATYPE(QList<QUrl>)
+#include <cmath>
QT_BEGIN_NAMESPACE
+DEFINE_BOOL_CONFIG_OPTION(compatResolveUrlsOnAssigment, QML_COMPAT_RESOLVE_URLS_ON_ASSIGNMENT);
+
/*!
\class QQmlProperty
\since 5.0
@@ -117,10 +80,7 @@ qWarning() << "Pixel size should now be 24:" << property.read().toInt();
/*!
Create an invalid QQmlProperty.
*/
-QQmlProperty::QQmlProperty()
-: d(nullptr)
-{
-}
+QQmlProperty::QQmlProperty() = default;
/*! \internal */
QQmlProperty::~QQmlProperty()
@@ -149,8 +109,10 @@ QQmlProperty::QQmlProperty(QObject *obj)
QQmlProperty::QQmlProperty(QObject *obj, QQmlContext *ctxt)
: d(new QQmlPropertyPrivate)
{
- d->context = ctxt?QQmlContextData::get(ctxt):nullptr;
- d->engine = ctxt?ctxt->engine():nullptr;
+ if (ctxt) {
+ d->context = QQmlContextData::get(ctxt);
+ d->engine = ctxt->engine();
+ }
d->initDefault(obj);
}
@@ -201,12 +163,15 @@ QQmlProperty::QQmlProperty(QObject *obj, const QString &name)
QQmlProperty::QQmlProperty(QObject *obj, const QString &name, QQmlContext *ctxt)
: d(new QQmlPropertyPrivate)
{
- d->context = ctxt?QQmlContextData::get(ctxt):nullptr;
- d->engine = ctxt?ctxt->engine():nullptr;
+ if (ctxt) {
+ d->context = QQmlContextData::get(ctxt);
+ d->engine = ctxt->engine();
+ }
+
d->initProperty(obj, name);
if (!isValid()) {
d->object = nullptr;
- d->context = nullptr;
+ d->context.reset();
d->engine = nullptr;
}
}
@@ -223,28 +188,34 @@ QQmlProperty::QQmlProperty(QObject *obj, const QString &name, QQmlEngine *engine
d->initProperty(obj, name);
if (!isValid()) {
d->object = nullptr;
- d->context = nullptr;
+ d->context.reset();
d->engine = nullptr;
}
}
QQmlProperty QQmlPropertyPrivate::create(QObject *target, const QString &propertyName,
- const QQmlRefPointer<QQmlContextData> &context)
+ const QQmlRefPointer<QQmlContextData> &context,
+ QQmlPropertyPrivate::InitFlags flags)
{
QQmlProperty result;
auto d = new QQmlPropertyPrivate;
result.d = d;
d->context = context;
d->engine = context ? context->engine() : nullptr;
- d->initProperty(target, propertyName);
+ d->initProperty(target, propertyName, flags);
if (!result.isValid()) {
d->object = nullptr;
- d->context = nullptr;
+ d->context.reset();
d->engine = nullptr;
}
return result;
}
+bool QQmlPropertyPrivate::resolveUrlsOnAssignment()
+{
+ return ::compatResolveUrlsOnAssigment();
+}
+
QQmlRefPointer<QQmlContextData> QQmlPropertyPrivate::effectiveContext() const
{
if (context)
@@ -255,10 +226,10 @@ QQmlRefPointer<QQmlContextData> QQmlPropertyPrivate::effectiveContext() const
return nullptr;
}
-void QQmlPropertyPrivate::initProperty(QObject *obj, const QString &name)
+// ### Qt7: Do not accept the "onFoo" syntax for signals anymore, and change the flags accordingly.
+void QQmlPropertyPrivate::initProperty(QObject *obj, const QString &name,
+ QQmlPropertyPrivate::InitFlags flags)
{
- if (!obj) return;
-
QQmlRefPointer<QQmlTypeNameCache> typeNameCache = context ? context->imports() : nullptr;
QObject *currentObject = obj;
@@ -270,33 +241,40 @@ void QQmlPropertyPrivate::initProperty(QObject *obj, const QString &name)
if (path.isEmpty()) return;
// Everything up to the last property must be an "object type" property
- for (int ii = 0; ii < path.count() - 1; ++ii) {
+ for (int ii = 0; ii < path.size() - 1; ++ii) {
const QStringView &pathName = path.at(ii);
// Types must begin with an uppercase letter (see checkRegistration()
// in qqmlmetatype.cpp for the enforcement of this).
if (typeNameCache && !pathName.isEmpty() && pathName.at(0).isUpper()) {
- QQmlTypeNameCache::Result r = typeNameCache->query(pathName);
+ QQmlEnginePrivate *enginePrivate = QQmlEnginePrivate::get(engine);
+ QQmlTypeLoader *typeLoader = QQmlTypeLoader::get(enginePrivate);
+ QQmlTypeNameCache::Result r = typeNameCache->query(pathName, typeLoader);
if (r.isValid()) {
if (r.type.isValid()) {
- QQmlEnginePrivate *enginePrivate = QQmlEnginePrivate::get(engine);
QQmlAttachedPropertiesFunc func = r.type.attachedPropertiesFunction(enginePrivate);
if (!func) return; // Not an attachable type
currentObject = qmlAttachedPropertiesObject(currentObject, func);
if (!currentObject) return; // Something is broken with the attachable type
} else if (r.importNamespace) {
- if ((ii + 1) == path.count()) return; // No type following the namespace
+ if (++ii == path.size())
+ return; // No type following the namespace
+
+ // TODO: Do we really _not_ want to query the namespaced types here?
+ r = typeNameCache->query<QQmlTypeNameCache::QueryNamespaced::No>(
+ path.at(ii), r.importNamespace, typeLoader);
- ++ii; r = typeNameCache->query(path.at(ii), r.importNamespace);
- if (!r.type.isValid()) return; // Invalid type in namespace
+ if (!r.type.isValid())
+ return; // Invalid type in namespace
- QQmlEnginePrivate *enginePrivate = QQmlEnginePrivate::get(engine);
QQmlAttachedPropertiesFunc func = r.type.attachedPropertiesFunction(enginePrivate);
- if (!func) return; // Not an attachable type
+ if (!func)
+ return; // Not an attachable type
currentObject = qmlAttachedPropertiesObject(currentObject, func);
- if (!currentObject) return; // Something is broken with the attachable type
+ if (!currentObject)
+ return; // Something is broken with the attachable type
} else if (r.scriptIndex != -1) {
return; // Not a type
@@ -309,16 +287,35 @@ void QQmlPropertyPrivate::initProperty(QObject *obj, const QString &name)
}
QQmlPropertyData local;
- QQmlPropertyData *property =
- QQmlPropertyCache::property(engine, currentObject, pathName, context, &local);
+ const QQmlPropertyData *property = currentObject
+ ? QQmlPropertyCache::property(currentObject, pathName, context, &local)
+ : nullptr;
+
+ if (!property) {
+ // Not a property; Might be an ID
+ // You can't look up an ID on a non-null object, though.
+ if (currentObject || !(flags & InitFlag::AllowId))
+ return;
+
+ for (auto idContext = context; idContext; idContext = idContext->parent()) {
+ const int objectId = idContext->propertyIndex(pathName.toString());
+ if (objectId != -1 && objectId < idContext->numIdValues()) {
+ currentObject = context->idValue(objectId);
+ break;
+ }
+ }
- if (!property) return; // Not a property
- if (property->isFunction())
+ if (!currentObject)
+ return;
+
+ continue;
+ } else if (property->isFunction()) {
return; // Not an object property
+ }
- if (ii == (path.count() - 2) && QQmlMetaType::isValueType(property->propType())) {
+ if (ii == (path.size() - 2) && QQmlMetaType::isValueType(property->propType())) {
// We're now at a value type property
- const QMetaObject *valueTypeMetaObject = QQmlMetaType::metaObjectForMetaType(property->propType());
+ const QMetaObject *valueTypeMetaObject = QQmlMetaType::metaObjectForValueType(property->propType());
if (!valueTypeMetaObject) return; // Not a value type
int idx = valueTypeMetaObject->indexOfProperty(path.last().toUtf8().constData());
@@ -352,68 +349,119 @@ void QQmlPropertyPrivate::initProperty(QObject *obj, const QString &name)
}
terminal = path.last();
+ } else if (!currentObject) {
+ return;
}
- if (terminal.size() >= 3 && terminal.at(0) == u'o' && terminal.at(1) == u'n'
- && (terminal.at(2).isUpper() || terminal.at(2) == u'_')) {
+ auto findSignalInMetaObject = [&](const QByteArray &signalName) {
+ const QMetaMethod method = findSignalByName(currentObject->metaObject(), signalName);
+ if (!method.isValid())
+ return false;
- QString signalName = terminal.mid(2).toString();
- int firstNon_;
- int length = signalName.length();
- for (firstNon_ = 0; firstNon_ < length; ++firstNon_)
- if (signalName.at(firstNon_) != u'_')
- break;
- signalName[firstNon_] = signalName.at(firstNon_).toLower();
+ object = currentObject;
+ core.load(method);
+ return true;
+ };
- // XXX - this code treats methods as signals
+ QQmlData *ddata = QQmlData::get(currentObject, false);
+ auto findChangeSignal = [&](QStringView signalName) {
+ if (auto propName = QQmlSignalNames::changedSignalNameToPropertyName(signalName)) {
+ const QQmlPropertyData *d =
+ ddata->propertyCache->property(*propName, currentObject, context);
+ while (d && d->isFunction())
+ d = ddata->propertyCache->overrideData(d);
- QQmlData *ddata = QQmlData::get(currentObject, false);
- if (ddata && ddata->propertyCache) {
+ if (d && d->notifyIndex() != -1) {
+ object = currentObject;
+ core = *ddata->propertyCache->signal(d->notifyIndex());
+ return true;
+ }
+ }
+ return false;
+ };
+ const auto findSignal = [&](const QString &signalName) {
+ if (ddata && ddata->propertyCache) {
// Try method
- QQmlPropertyData *d = ddata->propertyCache->property(signalName, currentObject, context);
+ const QQmlPropertyData *d
+ = ddata->propertyCache->property(signalName, currentObject, context);
+
+ // ### Qt7: This code treats methods as signals. It should use d->isSignal().
+ // That would be a change in behavior, though. Right now you can construct a
+ // QQmlProperty from such a thing.
while (d && !d->isFunction())
d = ddata->propertyCache->overrideData(d);
if (d) {
object = currentObject;
core = *d;
- return;
+ return true;
}
- // Try property
- if (signalName.endsWith(QLatin1String("Changed"))) {
- const QStringView propName = QStringView{signalName}.mid(0, signalName.length() - 7);
- QQmlPropertyData *d = ddata->propertyCache->property(propName, currentObject, context);
- while (d && d->isFunction())
- d = ddata->propertyCache->overrideData(d);
+ return findChangeSignal(signalName);
+ }
+
+ return findSignalInMetaObject(signalName.toUtf8());
+ };
- if (d && d->notifyIndex() != -1) {
- object = currentObject;
- core = *ddata->propertyCache->signal(d->notifyIndex());
- return;
- }
+ auto signalName = QQmlSignalNames::handlerNameToSignalName(terminal);
+ if (signalName) {
+ if (findSignal(*signalName))
+ return;
+ } else {
+ signalName = QQmlSignalNames::badHandlerNameToSignalName(terminal);
+ if (signalName) {
+ if (findSignal(*signalName)) {
+ qWarning()
+ << terminal
+ << "is not a properly capitalized signal handler name."
+ << QQmlSignalNames::signalNameToHandlerName(*signalName)
+ << "would be correct.";
+ return;
}
+ }
+ }
- } else {
- QMetaMethod method = findSignalByName(currentObject->metaObject(),
- signalName.toLatin1());
- if (method.isValid()) {
+ if (ddata && ddata->propertyCache) {
+ const QQmlPropertyData *property = ddata->propertyCache->property(
+ terminal, currentObject, context);
+
+ // Technically, we might find an override that is not a function.
+ while (property && !property->isSignal()) {
+ if (!property->isFunction()) {
object = currentObject;
- core.load(method);
+ core = *property;
+ nameCache = terminal.toString();
return;
}
+ property = ddata->propertyCache->overrideData(property);
}
- }
- // Property
- QQmlPropertyData local;
- QQmlPropertyData *property =
- QQmlPropertyCache::property(engine, currentObject, terminal, context, &local);
- if (property && !property->isFunction()) {
- object = currentObject;
- core = *property;
- nameCache = terminal.toString();
+ if (!(flags & InitFlag::AllowSignal))
+ return;
+
+ if (property) {
+ Q_ASSERT(property->isSignal());
+ object = currentObject;
+ core = *property;
+ return;
+ }
+
+ // At last: Try the change signal.
+ findChangeSignal(terminal);
+ } else {
+ // We might still find the property in the metaobject, even without property cache.
+ const QByteArray propertyName = terminal.toUtf8();
+ const QMetaProperty prop = findPropertyByName(currentObject->metaObject(), propertyName);
+
+ if (prop.isValid()) {
+ object = currentObject;
+ core.load(prop);
+ return;
+ }
+
+ if (flags & InitFlag::AllowSignal)
+ findSignalInMetaObject(terminal.toUtf8());
}
}
@@ -501,7 +549,7 @@ const char *QQmlProperty::propertyTypeName() const
if (!d)
return nullptr;
if (d->isValueType()) {
- const QMetaObject *valueTypeMetaObject = QQmlMetaType::metaObjectForMetaType(d->core.propType());
+ const QMetaObject *valueTypeMetaObject = QQmlMetaType::metaObjectForValueType(d->core.propType());
Q_ASSERT(valueTypeMetaObject);
return valueTypeMetaObject->property(d->valueTypeData.coreIndex()).typeName();
} else if (d->object && type() & Property && d->core.isValid()) {
@@ -611,12 +659,8 @@ QObject *QQmlProperty::object() const
*/
QQmlProperty &QQmlProperty::operator=(const QQmlProperty &other)
{
- if (d)
- d->release();
- d = other.d;
- if (d)
- d->addref();
-
+ QQmlProperty copied(other);
+ qSwap(d, copied.d);
return *this;
}
@@ -699,18 +743,16 @@ QString QQmlProperty::name() const
if (!d)
return QString();
if (d->nameCache.isEmpty()) {
- // ###
if (!d->object) {
} else if (d->isValueType()) {
- const QMetaObject *valueTypeMetaObject = QQmlMetaType::metaObjectForMetaType(d->core.propType());
+ const QMetaObject *valueTypeMetaObject = QQmlMetaType::metaObjectForValueType(d->core.propType());
Q_ASSERT(valueTypeMetaObject);
const char *vtName = valueTypeMetaObject->property(d->valueTypeData.coreIndex()).name();
d->nameCache = d->core.name(d->object) + QLatin1Char('.') + QString::fromUtf8(vtName);
} else if (type() & SignalProperty) {
- QString name = QLatin1String("on") + d->core.name(d->object);
- name[2] = name.at(2).toUpper();
- d->nameCache = name;
+ // ### Qt7: Return the original signal name here. Do not prepend "on"
+ d->nameCache = QQmlSignalNames::signalNameToHandlerName(d->core.name(d->object));
} else {
d->nameCache = d->core.name(d->object);
}
@@ -807,7 +849,7 @@ static void removeOldBinding(QObject *object, QQmlPropertyIndex index, QQmlPrope
if (!oldBinding)
return;
- if (valueTypeIndex != -1 && oldBinding->isValueTypeProxy())
+ if (valueTypeIndex != -1 && oldBinding->kind() == QQmlAbstractBinding::ValueTypeProxy)
oldBinding = static_cast<QQmlValueTypeProxyBinding *>(oldBinding.data())->binding(index);
if (!oldBinding)
@@ -862,9 +904,8 @@ QQmlPropertyPrivate::binding(QObject *object, QQmlPropertyIndex index)
binding = binding->nextBinding();
if (binding && valueTypeIndex != -1) {
- if (binding->isValueTypeProxy()) {
+ if (binding->kind() == QQmlAbstractBinding::ValueTypeProxy)
binding = static_cast<QQmlValueTypeProxyBinding *>(binding)->binding(index);
- }
}
return binding;
@@ -879,7 +920,7 @@ void QQmlPropertyPrivate::findAliasTarget(QObject *object, QQmlPropertyIndex bin
int coreIndex = bindingIndex.coreIndex();
int valueTypeIndex = bindingIndex.valueTypeIndex();
- QQmlPropertyData *propertyData =
+ const QQmlPropertyData *propertyData =
data->propertyCache?data->propertyCache->property(coreIndex):nullptr;
if (propertyData && propertyData->isAlias()) {
QQmlVMEMetaObject *vme = QQmlVMEMetaObject::getForProperty(object, coreIndex);
@@ -927,7 +968,7 @@ void QQmlPropertyPrivate::setBinding(QQmlAbstractBinding *binding, BindingFlags
int coreIndex = index.coreIndex();
QQmlData *data = QQmlData::get(object, true);
if (data->propertyCache) {
- QQmlPropertyData *propertyData = data->propertyCache->property(coreIndex);
+ const QQmlPropertyData *propertyData = data->propertyCache->property(coreIndex);
Q_ASSERT(propertyData);
}
#endif
@@ -1087,7 +1128,7 @@ QVariant QQmlPropertyPrivate::readValueProperty()
{
auto doRead = [&](QQmlGadgetPtrWrapper *wrapper) {
wrapper->read(object, core.coreIndex());
- return wrapper->property(valueTypeData.coreIndex()).read(wrapper);
+ return wrapper->readOnGadget(wrapper->property(valueTypeData.coreIndex()));
};
if (isValueType()) {
@@ -1102,7 +1143,7 @@ QVariant QQmlPropertyPrivate::readValueProperty()
QQmlListProperty<QObject> prop;
core.readProperty(object, &prop);
- return QVariant::fromValue(QQmlListReferencePrivate::init(prop, core.propType().id(), engine));
+ return QVariant::fromValue(QQmlListReferencePrivate::init(prop, core.propType()));
} else if (core.isQObject()) {
@@ -1133,32 +1174,38 @@ QVariant QQmlPropertyPrivate::readValueProperty()
}
// helper function to allow assignment / binding to QList<QUrl> properties.
-QVariant QQmlPropertyPrivate::urlSequence(const QVariant &value)
+QList<QUrl> QQmlPropertyPrivate::urlSequence(const QVariant &value)
{
+ if (value.metaType() == QMetaType::fromType<QList<QUrl>>())
+ return value.value<QList<QUrl> >();
+
QList<QUrl> urls;
- if (value.userType() == qMetaTypeId<QUrl>()) {
+ if (value.metaType() == QMetaType::fromType<QUrl>()) {
urls.append(value.toUrl());
- } else if (value.userType() == qMetaTypeId<QString>()) {
+ } else if (value.metaType() == QMetaType::fromType<QString>()) {
urls.append(QUrl(value.toString()));
- } else if (value.userType() == qMetaTypeId<QByteArray>()) {
+ } else if (value.metaType() == QMetaType::fromType<QByteArray>()) {
urls.append(QUrl(QString::fromUtf8(value.toByteArray())));
- } else if (value.userType() == qMetaTypeId<QList<QUrl> >()) {
- urls = value.value<QList<QUrl> >();
- } else if (value.userType() == qMetaTypeId<QStringList>()) {
+ } else if (value.metaType() == QMetaType::fromType<QStringList>()) {
QStringList urlStrings = value.value<QStringList>();
const int urlStringsSize = urlStrings.size();
urls.reserve(urlStringsSize);
for (int i = 0; i < urlStringsSize; ++i)
urls.append(QUrl(urlStrings.at(i)));
- } else if (value.userType() == qMetaTypeId<QList<QString> >()) {
- QList<QString> urlStrings = value.value<QList<QString> >();
- const int urlStringsSize = urlStrings.size();
- urls.reserve(urlStringsSize);
- for (int i = 0; i < urlStringsSize; ++i)
- urls.append(QUrl(urlStrings.at(i)));
} // note: QList<QByteArray> is not currently supported.
+ return urls;
+}
+
+// ### Qt7: Get rid of this
+QList<QUrl> QQmlPropertyPrivate::urlSequence(
+ const QVariant &value, const QQmlRefPointer<QQmlContextData> &ctxt)
+{
+ QList<QUrl> urls = urlSequence(value);
- return QVariant::fromValue<QList<QUrl> >(urls);
+ for (auto urlIt = urls.begin(); urlIt != urls.end(); ++urlIt)
+ *urlIt = ctxt->resolvedUrl(*urlIt);
+
+ return urls;
}
//writeEnumProperty MIRRORS the relelvant bit of QMetaProperty::write AND MUST BE KEPT IN SYNC!
@@ -1168,13 +1215,9 @@ bool QQmlPropertyPrivate::writeEnumProperty(const QMetaProperty &prop, int idx,
return false;
QVariant v = value;
- if (prop.isEnumType()) {
+ if (prop.isEnumType() && v.metaType() != prop.metaType()) {
QMetaEnum menum = prop.enumerator();
- if (v.userType() == QMetaType::QString
-#ifdef QT3_SUPPORT
- || v.userType() == QVariant::CString
-#endif
- ) {
+ if (v.userType() == QMetaType::QString) {
bool ok;
if (prop.isFlagType())
v = QVariant(menum.keysToValue(value.toByteArray(), &ok));
@@ -1182,14 +1225,9 @@ bool QQmlPropertyPrivate::writeEnumProperty(const QMetaProperty &prop, int idx,
v = QVariant(menum.keyToValue(value.toByteArray(), &ok));
if (!ok)
return false;
- } else if (v.userType() != QMetaType::Int && v.userType() != QMetaType::UInt) {
- int enumMetaTypeId = QMetaType::fromName(
- QByteArray(menum.scope() + QByteArray("::") + menum.name())).id();
- if ((enumMetaTypeId == QMetaType::UnknownType) || (v.userType() != enumMetaTypeId) || !v.constData())
- return false;
- v = QVariant(*reinterpret_cast<const int *>(v.constData()));
}
- v.convert(QMetaType(QMetaType::Int));
+ if (!v.convert(prop.metaType())) // ### TODO: underlyingType might be faster?
+ return false;
}
// the status variable is changed by qt_metacall to indicate what it did
@@ -1208,41 +1246,228 @@ bool QQmlPropertyPrivate::writeValueProperty(const QVariant &value, QQmlProperty
return writeValueProperty(object, core, valueTypeData, value, effectiveContext(), flags);
}
-bool
-QQmlPropertyPrivate::writeValueProperty(QObject *object,
- const QQmlPropertyData &core,
- const QQmlPropertyData &valueTypeData,
- const QVariant &value,
- const QQmlRefPointer<QQmlContextData> &context,
- QQmlPropertyData::WriteFlags flags)
+static void removeValuePropertyBinding(
+ QObject *object, const QQmlPropertyData &core,
+ const QQmlPropertyData &valueTypeData, QQmlPropertyData::WriteFlags flags)
{
// Remove any existing bindings on this property
- if (!(flags & QQmlPropertyData::DontRemoveBinding) && object)
- removeBinding(object, encodedIndex(core, valueTypeData));
-
- bool rv = false;
- if (valueTypeData.isValid()) {
- auto doWrite = [&](QQmlGadgetPtrWrapper *wrapper) {
- wrapper->read(object, core.coreIndex());
- rv = write(wrapper, valueTypeData, value, context, flags);
- wrapper->write(object, core.coreIndex(), flags);
- };
-
- QQmlGadgetPtrWrapper *wrapper = context
- ? QQmlGadgetPtrWrapper::instance(context->engine(), core.propType())
- : nullptr;
- if (wrapper) {
- doWrite(wrapper);
- } else if (QQmlValueType *valueType = QQmlMetaType::valueType(core.propType())) {
- QQmlGadgetPtrWrapper wrapper(valueType, nullptr);
- doWrite(&wrapper);
+ if (!(flags & QQmlPropertyData::DontRemoveBinding) && object) {
+ QQmlPropertyPrivate::removeBinding(
+ object, QQmlPropertyPrivate::encodedIndex(core, valueTypeData));
+ }
+}
+
+template<typename Op>
+bool changePropertyAndWriteBack(
+ QObject *object, int coreIndex, QQmlGadgetPtrWrapper *wrapper,
+ QQmlPropertyData::WriteFlags flags, int internalIndex, Op op)
+{
+ wrapper->read(object, coreIndex);
+ const bool rv = op(wrapper);
+ wrapper->write(object, coreIndex, flags, internalIndex);
+ return rv;
+}
+
+template<typename Op>
+bool changeThroughGadgetPtrWrapper(
+ QObject *object, const QQmlPropertyData &core,
+ const QQmlRefPointer<QQmlContextData> &context, QQmlPropertyData::WriteFlags flags,
+ int internalIndex, Op op)
+{
+ if (QQmlGadgetPtrWrapper *wrapper = context
+ ? QQmlGadgetPtrWrapper::instance(context->engine(), core.propType())
+ : nullptr) {
+ return changePropertyAndWriteBack(
+ object, core.coreIndex(), wrapper, flags, internalIndex, op);
+ }
+
+ if (QQmlValueType *valueType = QQmlMetaType::valueType(core.propType())) {
+ QQmlGadgetPtrWrapper wrapper(valueType, nullptr);
+ return changePropertyAndWriteBack(
+ object, core.coreIndex(), &wrapper, flags, internalIndex, op);
+ }
+
+ return false;
+}
+
+bool QQmlPropertyPrivate::writeValueProperty(
+ QObject *object, const QQmlPropertyData &core, const QQmlPropertyData &valueTypeData,
+ const QVariant &value, const QQmlRefPointer<QQmlContextData> &context,
+ QQmlPropertyData::WriteFlags flags)
+{
+ removeValuePropertyBinding(object, core, valueTypeData, flags);
+
+ if (!valueTypeData.isValid())
+ return write(object, core, value, context, flags);
+
+ return changeThroughGadgetPtrWrapper(
+ object, core, context, flags | QQmlPropertyData::HasInternalIndex,
+ valueTypeData.coreIndex(), [&](QQmlGadgetPtrWrapper *wrapper) {
+ return write(wrapper, valueTypeData, value, context, flags);
+ });
+}
+
+bool QQmlPropertyPrivate::resetValueProperty(
+ QObject *object, const QQmlPropertyData &core, const QQmlPropertyData &valueTypeData,
+ const QQmlRefPointer<QQmlContextData> &context, QQmlPropertyData::WriteFlags flags)
+{
+ removeValuePropertyBinding(object, core, valueTypeData, flags);
+
+ if (!valueTypeData.isValid())
+ return reset(object, core, flags);
+
+ return changeThroughGadgetPtrWrapper(
+ object, core, context, flags | QQmlPropertyData::HasInternalIndex,
+ valueTypeData.coreIndex(), [&](QQmlGadgetPtrWrapper *wrapper) {
+ return reset(wrapper, valueTypeData, flags);
+ });
+}
+
+// We need to prevent new-style bindings from being removed.
+struct BindingFixer
+{
+ Q_DISABLE_COPY_MOVE(BindingFixer);
+
+ BindingFixer(QObject *object, const QQmlPropertyData &property,
+ QQmlPropertyData::WriteFlags flags)
+ {
+ if (!property.isBindable() || !(flags & QQmlPropertyData::DontRemoveBinding))
+ return;
+
+ QUntypedBindable bindable;
+ void *argv[] = {&bindable};
+ QMetaObject::metacall(object, QMetaObject::BindableProperty, property.coreIndex(), argv);
+ untypedBinding = bindable.binding();
+ if (auto priv = QPropertyBindingPrivate::get(untypedBinding))
+ priv->setSticky(true);
+ }
+
+ ~BindingFixer()
+ {
+ if (untypedBinding.isNull())
+ return;
+ auto priv = QPropertyBindingPrivate::get(untypedBinding);
+ priv->setSticky(false);
+ }
+
+private:
+ QUntypedPropertyBinding untypedBinding;
+};
+
+struct ConvertAndAssignResult {
+ bool couldConvert = false;
+ bool couldWrite = false;
+
+ operator bool() const { return couldConvert; }
+};
+
+static ConvertAndAssignResult tryConvertAndAssign(
+ QObject *object, const QQmlPropertyData &property, const QVariant &value,
+ QQmlPropertyData::WriteFlags flags, QMetaType propertyMetaType, QMetaType variantMetaType,
+ bool isUrl) {
+
+ if (isUrl
+ || variantMetaType == QMetaType::fromType<QString>()
+ || propertyMetaType == QMetaType::fromType<QList<QUrl>>()
+ || property.isQList()) {
+ return {false, false};
+ }
+
+ if (variantMetaType == QMetaType::fromType<QJSValue>()) {
+ // Handle Qt.binding bindings here to avoid mistaken conversion below
+ const QJSValue &jsValue = get<QJSValue>(value);
+ const QV4::FunctionObject *f
+ = QJSValuePrivate::asManagedType<QV4::FunctionObject>(&jsValue);
+ if (f && f->isBinding()) {
+ QV4::QObjectWrapper::setProperty(
+ f->engine(), object, &property, f->asReturnedValue());
+ return {true, true};
}
+ }
- } else {
- rv = write(object, core, value, context, flags);
+ // common cases:
+ switch (propertyMetaType.id()) {
+ case QMetaType::Bool:
+ if (value.canConvert(propertyMetaType)) {
+ bool b = value.toBool();
+ return {true, property.writeProperty(object, &b, flags)};
+ }
+ return {false, false};
+ case QMetaType::Int: {
+ bool ok = false;
+ int i = value.toInt(&ok);
+ return {ok, ok && property.writeProperty(object, &i, flags)};
+ }
+ case QMetaType::UInt: {
+ bool ok = false;
+ uint u = value.toUInt(&ok);
+ return {ok, ok && property.writeProperty(object, &u, flags)};
+ }
+ case QMetaType::Double: {
+ bool ok = false;
+ double d = value.toDouble(&ok);
+ return {ok, ok && property.writeProperty(object, &d, flags)};
+ }
+ case QMetaType::Float: {
+ bool ok = false;
+ float f = value.toFloat(&ok);
+ return {ok, ok && property.writeProperty(object, &f, flags)};
+ }
+ case QMetaType::QString:
+ if (value.canConvert(propertyMetaType)) {
+ QString s = value.toString();
+ return {true, property.writeProperty(object, &s, flags)};
+ }
+ return {false, false};
+ case QMetaType::QVariantMap:
+ if (value.canConvert(propertyMetaType)) {
+ QVariantMap m = value.toMap();
+ return {true, property.writeProperty(object, &m, flags)};
+ }
+ return {false, false};
+ default: {
+ break;
+ }
}
- return rv;
+ QVariant converted = QQmlValueTypeProvider::createValueType(value, propertyMetaType);
+ if (!converted.isValid()) {
+ converted = QVariant(propertyMetaType);
+ if (!QMetaType::convert(value.metaType(), value.constData(),
+ propertyMetaType, converted.data())) {
+ return {false, false};
+ }
+ }
+ return {true, property.writeProperty(object, converted.data(), flags)};
+};
+
+template<typename Op>
+bool iterateQObjectContainer(QMetaType metaType, const void *data, Op op)
+{
+ QSequentialIterable iterable;
+ if (!QMetaType::convert(metaType, data, QMetaType::fromType<QSequentialIterable>(), &iterable))
+ return false;
+
+ const QMetaSequence metaSequence = iterable.metaContainer();
+
+ if (!metaSequence.hasConstIterator()
+ || !metaSequence.canGetValueAtConstIterator()
+ || !iterable.valueMetaType().flags().testFlag(QMetaType::PointerToQObject)) {
+ return false;
+ }
+
+ const void *container = iterable.constIterable();
+ void *it = metaSequence.constBegin(container);
+ const void *end = metaSequence.constEnd(container);
+ QObject *o = nullptr;
+ while (!metaSequence.compareConstIterator(it, end)) {
+ metaSequence.valueAtConstIterator(it, &o);
+ op(o);
+ metaSequence.advanceConstIterator(it, 1);
+ }
+ metaSequence.destroyConstIterator(it);
+ metaSequence.destroyConstIterator(end);
+ return true;
}
bool QQmlPropertyPrivate::write(
@@ -1250,14 +1475,15 @@ bool QQmlPropertyPrivate::write(
const QQmlRefPointer<QQmlContextData> &context, QQmlPropertyData::WriteFlags flags)
{
const QMetaType propertyMetaType = property.propType();
- const int propertyType = propertyMetaType.id();
- const int variantType = value.userType();
+ const QMetaType variantMetaType = value.metaType();
+
+ const BindingFixer bindingFixer(object, property, flags);
if (property.isEnum()) {
QMetaProperty prop = object->metaObject()->property(property.coreIndex());
QVariant v = value;
// Enum values come through the script engine as doubles
- if (variantType == QMetaType::Double) {
+ if (variantMetaType == QMetaType::fromType<double>()) {
double integral;
double fractional = std::modf(value.toDouble(), &integral);
if (qFuzzyIsNull(fractional))
@@ -1267,25 +1493,28 @@ bool QQmlPropertyPrivate::write(
}
QQmlEnginePrivate *enginePriv = QQmlEnginePrivate::get(context);
- const bool isUrl = propertyType == QMetaType::QUrl; // handled separately
+ const bool isUrl = propertyMetaType == QMetaType::fromType<QUrl>(); // handled separately
// The cases below are in approximate order of likelyhood:
- if (propertyType == variantType && !isUrl && propertyType != qMetaTypeId<QList<QUrl>>() && !property.isQList()) {
+ if (propertyMetaType == variantMetaType && !isUrl
+ && propertyMetaType != QMetaType::fromType<QList<QUrl>>() && !property.isQList()) {
return property.writeProperty(object, const_cast<void *>(value.constData()), flags);
} else if (property.isQObject()) {
QVariant val = value;
- int varType = variantType;
- if (variantType == QMetaType::Nullptr) {
+ QMetaType varType;
+ if (variantMetaType == QMetaType::fromType<std::nullptr_t>()) {
// This reflects the fact that you can assign a nullptr to a QObject pointer
// Without the change to QObjectStar, rawMetaObjectForType would not give us a QQmlMetaObject
- varType = QMetaType::QObjectStar;
- val = QVariant(QMetaType::fromType<QObject *>(), nullptr);
+ varType = QMetaType::fromType<QObject*>();
+ val = QVariant(varType, nullptr);
+ } else {
+ varType = variantMetaType;
}
- QQmlMetaObject valMo = rawMetaObjectForType(enginePriv, varType);
- if (valMo.isNull())
+ QQmlMetaObject valMo = rawMetaObjectForType(varType);
+ if (valMo.isNull() || !varType.flags().testFlag(QMetaType::PointerToQObject))
return false;
QObject *o = *static_cast<QObject *const *>(val.constData());
- QQmlMetaObject propMo = rawMetaObjectForType(enginePriv, propertyType);
+ QQmlMetaObject propMo = rawMetaObjectForType(propertyMetaType);
if (o)
valMo = o;
@@ -1300,166 +1529,189 @@ bool QQmlPropertyPrivate::write(
} else {
return false;
}
- } else if (value.canConvert(propertyMetaType)
- && !isUrl && variantType != QMetaType::QString
- && propertyType != qMetaTypeId<QList<QUrl>>() && !property.isQList()) {
- // common cases:
- switch (propertyType) {
- case QMetaType::Bool: {
- bool b = value.toBool();
- return property.writeProperty(object, &b, flags);
- }
- case QMetaType::Int: {
- int i = value.toInt();
- return property.writeProperty(object, &i, flags);
- }
- case QMetaType::Double: {
- double d = value.toDouble();
- return property.writeProperty(object, &d, flags);
- }
- case QMetaType::Float: {
- float f = value.toFloat();
- return property.writeProperty(object, &f, flags);
- }
- case QMetaType::QString: {
- QString s = value.toString();
- return property.writeProperty(object, &s, flags);
- }
- default: { // "fallback":
- QVariant v = value;
- v.convert(propertyMetaType);
- return property.writeProperty(object, const_cast<void *>(v.constData()), flags);
- }
- }
- } else if (propertyType == qMetaTypeId<QVariant>()) {
+ } else if (ConvertAndAssignResult result = tryConvertAndAssign(
+ object, property, value, flags, propertyMetaType, variantMetaType, isUrl)) {
+ return result.couldWrite;
+ } else if (propertyMetaType == QMetaType::fromType<QVariant>()) {
return property.writeProperty(object, const_cast<QVariant *>(&value), flags);
} else if (isUrl) {
QUrl u;
- if (variantType == QMetaType::QUrl)
+ if (variantMetaType == QMetaType::fromType<QUrl>()) {
u = value.toUrl();
- else if (variantType == QMetaType::QByteArray)
+ if (compatResolveUrlsOnAssigment() && context && u.isRelative() && !u.isEmpty())
+ u = context->resolvedUrl(u);
+ }
+ else if (variantMetaType == QMetaType::fromType<QByteArray>())
u = QUrl(QString::fromUtf8(value.toByteArray()));
- else if (variantType == QMetaType::QString)
+ else if (variantMetaType == QMetaType::fromType<QString>())
u = QUrl(value.toString());
else
return false;
return property.writeProperty(object, &u, flags);
- } else if (propertyType == qMetaTypeId<QList<QUrl>>()) {
- QList<QUrl> urlSeq = urlSequence(value).value<QList<QUrl>>();
+ } else if (propertyMetaType == QMetaType::fromType<QList<QUrl>>()) {
+ QList<QUrl> urlSeq = compatResolveUrlsOnAssigment()
+ ? urlSequence(value, context)
+ : urlSequence(value);
return property.writeProperty(object, &urlSeq, flags);
} else if (property.isQList()) {
- QQmlMetaObject listType;
-
- if (enginePriv) {
- listType = enginePriv->rawMetaObjectForType(QQmlMetaType::listType(propertyType));
- } else {
- QQmlType type = QQmlMetaType::qmlType(QQmlMetaType::listType(propertyType));
- if (!type.isValid())
+ if (propertyMetaType.flags() & QMetaType::IsQmlList) {
+ QMetaType listValueType = QQmlMetaType::listValueType(propertyMetaType);
+ QQmlMetaObject valueMetaObject = QQmlMetaType::rawMetaObjectForType(listValueType);
+ if (valueMetaObject.isNull())
return false;
- listType = type.baseMetaObject();
- }
- if (listType.isNull())
- return false;
- QQmlListProperty<void> prop;
- property.readProperty(object, &prop);
+ QQmlListProperty<QObject> prop;
+ property.readProperty(object, &prop);
- if (!prop.clear)
- return false;
+ if (!prop.clear || !prop.append)
+ return false;
- prop.clear(&prop);
+ const bool useNonsignalingListOps = prop.clear == &QQmlVMEMetaObject::list_clear
+ && prop.append == &QQmlVMEMetaObject::list_append;
- if (variantType == qMetaTypeId<QQmlListReference>()) {
- QQmlListReference qdlr = value.value<QQmlListReference>();
+ auto propClear =
+ useNonsignalingListOps ? &QQmlVMEMetaObject::list_clear_nosignal : prop.clear;
+ auto propAppend =
+ useNonsignalingListOps ? &QQmlVMEMetaObject::list_append_nosignal : prop.append;
- for (qsizetype ii = 0; ii < qdlr.count(); ++ii) {
- QObject *o = qdlr.at(ii);
- if (o && !QQmlMetaObject::canConvert(o, listType))
- o = nullptr;
- prop.append(&prop, o);
- }
- } else if (variantType == qMetaTypeId<QList<QObject *> >()) {
- const QList<QObject *> &list = qvariant_cast<QList<QObject *> >(value);
+ propClear(&prop);
- for (qsizetype ii = 0; ii < list.count(); ++ii) {
- QObject *o = list.at(ii);
- if (o && !QQmlMetaObject::canConvert(o, listType))
+ const auto doAppend = [&](QObject *o) {
+ if (o && !QQmlMetaObject::canConvert(o, valueMetaObject))
o = nullptr;
- prop.append(&prop, o);
+ propAppend(&prop, o);
+ };
+
+ if (variantMetaType == QMetaType::fromType<QQmlListReference>()) {
+ QQmlListReference qdlr = value.value<QQmlListReference>();
+ for (qsizetype ii = 0; ii < qdlr.count(); ++ii)
+ doAppend(qdlr.at(ii));
+ } else if (variantMetaType == QMetaType::fromType<QList<QObject *>>()) {
+ const QList<QObject *> &list = qvariant_cast<QList<QObject *> >(value);
+ for (qsizetype ii = 0; ii < list.size(); ++ii)
+ doAppend(list.at(ii));
+ } else if (variantMetaType == QMetaType::fromType<QList<QVariant>>()) {
+ const QList<QVariant> &list
+ = *static_cast<const QList<QVariant> *>(value.constData());
+ for (const QVariant &entry : list)
+ doAppend(QQmlMetaType::toQObject(entry));
+ } else if (!iterateQObjectContainer(variantMetaType, value.data(), doAppend)) {
+ doAppend(QQmlMetaType::toQObject(value));
+ }
+ if (useNonsignalingListOps) {
+ Q_ASSERT(QQmlVMEMetaObject::get(object));
+ QQmlVMEResolvedList(&prop).activateSignal();
}
+ } else if (variantMetaType == propertyMetaType) {
+ QVariant v = value;
+ property.writeProperty(object, v.data(), flags);
} else {
- QObject *o = QQmlMetaType::toQObject(value);
- if (o && !QQmlMetaObject::canConvert(o, listType))
- o = nullptr;
- prop.append(&prop, o);
+ QVariant list(propertyMetaType);
+ const QQmlType type = QQmlMetaType::qmlType(propertyMetaType);
+ const QMetaSequence sequence = type.listMetaSequence();
+ if (sequence.canAddValue())
+ sequence.addValue(list.data(), value.data());
+ property.writeProperty(object, list.data(), flags);
}
+ } else if (enginePriv && propertyMetaType == QMetaType::fromType<QJSValue>()) {
+ // We can convert everything into a QJSValue if we have an engine.
+ QJSValue jsValue = QJSValuePrivate::fromReturnedValue(
+ enginePriv->v4engine()->metaTypeToJS(variantMetaType, value.constData()));
+ return property.writeProperty(object, &jsValue, flags);
} else {
- Q_ASSERT(variantType != propertyType);
+ Q_ASSERT(variantMetaType != propertyMetaType);
bool ok = false;
QVariant v;
- if (variantType == QMetaType::QString)
- v = QQmlStringConverters::variantFromString(value.toString(), propertyType, &ok);
+ if (variantMetaType == QMetaType::fromType<QString>())
+ v = QQmlStringConverters::variantFromString(value.toString(), propertyMetaType, &ok);
if (!ok) {
v = value;
if (v.convert(propertyMetaType)) {
ok = true;
- } else if (static_cast<uint>(propertyType) >= QMetaType::User &&
- variantType == QMetaType::QString) {
- QQmlMetaType::StringConverter con = QQmlMetaType::customStringConverter(propertyType);
- if (con) {
- v = con(value.toString());
- if (v.userType() == propertyType)
- ok = true;
- }
}
}
if (!ok) {
// the only other options are that they are assigning a single value
- // to a sequence type property (eg, an int to a QList<int> property).
- // or that we encountered an interface type
+ // or a QVariantList to a sequence type property (eg, an int to a
+ // QList<int> property) or that we encountered an interface type.
// Note that we've already handled single-value assignment to QList<QUrl> properties.
- if (variantType == QMetaType::Int && propertyType == qMetaTypeId<QList<int> >()) {
- QList<int> list;
- list << value.toInt();
- v = QVariant::fromValue<QList<int> >(list);
- ok = true;
- } else if ((variantType == QMetaType::Double || variantType == QMetaType::Int)
- && (propertyType == qMetaTypeId<QList<qreal> >())) {
- QList<qreal> list;
- list << value.toReal();
- v = QVariant::fromValue<QList<qreal> >(list);
- ok = true;
- } else if (variantType == QMetaType::Bool && propertyType == qMetaTypeId<QList<bool> >()) {
- QList<bool> list;
- list << value.toBool();
- v = QVariant::fromValue<QList<bool> >(list);
- ok = true;
- } else if (variantType == QMetaType::QString && propertyType == qMetaTypeId<QList<QString> >()) {
- QList<QString> list;
- list << value.toString();
- v = QVariant::fromValue<QList<QString> >(list);
- ok = true;
- } else if (variantType == QMetaType::QString && propertyType == qMetaTypeId<QStringList>()) {
- QStringList list;
- list << value.toString();
- v = QVariant::fromValue<QStringList>(list);
- ok = true;
+ QSequentialIterable iterable;
+ v = QVariant(propertyMetaType);
+ if (QMetaType::view(
+ propertyMetaType, v.data(),
+ QMetaType::fromType<QSequentialIterable>(),
+ &iterable)) {
+ const QMetaSequence propertyMetaSequence = iterable.metaContainer();
+ if (propertyMetaSequence.canAddValueAtEnd()) {
+ const QMetaType elementMetaType = iterable.valueMetaType();
+ void *propertyContainer = iterable.mutableIterable();
+
+ if (variantMetaType == elementMetaType) {
+ propertyMetaSequence.addValueAtEnd(propertyContainer, value.constData());
+ ok = true;
+ } else if (variantMetaType == QMetaType::fromType<QVariantList>()) {
+ const QVariantList list = value.value<QVariantList>();
+ for (const QVariant &valueElement : list) {
+ if (valueElement.metaType() == elementMetaType) {
+ propertyMetaSequence.addValueAtEnd(
+ propertyContainer, valueElement.constData());
+ } else {
+ QVariant converted(elementMetaType);
+ QMetaType::convert(
+ valueElement.metaType(), valueElement.constData(),
+ elementMetaType, converted.data());
+ propertyMetaSequence.addValueAtEnd(
+ propertyContainer, converted.constData());
+ }
+ }
+ ok = true;
+ } else if (elementMetaType.flags().testFlag(QMetaType::PointerToQObject)) {
+ const QMetaObject *elementMetaObject = elementMetaType.metaObject();
+ Q_ASSERT(elementMetaObject);
+
+ const auto doAppend = [&](QObject *o) {
+ QObject *casted = elementMetaObject->cast(o);
+ propertyMetaSequence.addValueAtEnd(propertyContainer, &casted);
+ };
+
+ if (variantMetaType.flags().testFlag(QMetaType::PointerToQObject)) {
+ doAppend(*static_cast<QObject *const *>(value.data()));
+ ok = true;
+ } else if (variantMetaType == QMetaType::fromType<QQmlListReference>()) {
+ const QQmlListReference *reference
+ = static_cast<const QQmlListReference *>(value.constData());
+ Q_ASSERT(elementMetaObject);
+ for (int i = 0, end = reference->size(); i < end; ++i)
+ doAppend(reference->at(i));
+ ok = true;
+ } else if (!iterateQObjectContainer(
+ variantMetaType, value.data(), doAppend)) {
+ doAppend(QQmlMetaType::toQObject(value));
+ }
+ } else {
+ QVariant converted = value;
+ if (converted.convert(elementMetaType)) {
+ propertyMetaSequence.addValueAtEnd(propertyContainer, converted.constData());
+ ok = true;
+ }
+ }
+ }
}
}
- if (!ok && QQmlMetaType::isInterface(propertyType)) {
+ if (!ok && QQmlMetaType::isInterface(propertyMetaType)) {
auto valueAsQObject = qvariant_cast<QObject *>(value);
- if (void *interface = valueAsQObject
- ? valueAsQObject->qt_metacast(QQmlMetaType::interfaceIId(propertyType))
+ if (void *iface = valueAsQObject
+ ? valueAsQObject->qt_metacast(QQmlMetaType::interfaceIId(propertyMetaType))
: nullptr;
- interface) {
+ iface) {
// this case can occur when object has an interface type
// and the variant contains a type implementing the interface
- return property.writeProperty(object, &interface, flags);
+ return property.writeProperty(object, &iface, flags);
}
}
@@ -1473,17 +1725,22 @@ bool QQmlPropertyPrivate::write(
return true;
}
-QQmlMetaObject QQmlPropertyPrivate::rawMetaObjectForType(QQmlEnginePrivate *engine, int userType)
+bool QQmlPropertyPrivate::reset(
+ QObject *object, const QQmlPropertyData &property,
+ QQmlPropertyData::WriteFlags flags)
{
- QMetaType metaType(userType);
- if ((metaType.flags() & QMetaType::PointerToQObject) && metaType.metaObject())
- return metaType.metaObject();
- if (engine)
- return engine->rawMetaObjectForType(userType);
- QQmlType type = QQmlMetaType::qmlType(userType);
- if (type.isValid())
- return QQmlMetaObject(type.baseMetaObject());
- return QQmlMetaObject();
+ const BindingFixer bindingFixer(object, property, flags);
+ property.resetProperty(object, flags);
+ return true;
+}
+
+QQmlMetaObject QQmlPropertyPrivate::rawMetaObjectForType(QMetaType metaType)
+{
+ if (metaType.flags() & QMetaType::PointerToQObject) {
+ if (const QMetaObject *metaObject = metaType.metaObject())
+ return metaObject;
+ }
+ return QQmlMetaType::rawMetaObjectForType(metaType);
}
/*!
@@ -1699,9 +1956,8 @@ QMetaMethod QQmlPropertyPrivate::findSignalByName(const QMetaObject *mo, const Q
// If no signal is found, but the signal is of the form "onBlahChanged",
// return the notify signal for the property "Blah"
- if (name.endsWith("Changed")) {
- QByteArray propName = name.mid(0, name.length() - 7);
- int propIdx = mo->indexOfProperty(propName.constData());
+ if (auto propName = QQmlSignalNames::changedSignalNameToPropertyName(name)) {
+ int propIdx = mo->indexOfProperty(propName->constData());
if (propIdx >= 0) {
QMetaProperty prop = mo->property(propIdx);
if (prop.hasNotifySignal())
@@ -1712,6 +1968,16 @@ QMetaMethod QQmlPropertyPrivate::findSignalByName(const QMetaObject *mo, const Q
return QMetaMethod();
}
+/*!
+ Return the property corresponding to \a name
+*/
+QMetaProperty QQmlPropertyPrivate::findPropertyByName(const QMetaObject *mo, const QByteArray &name)
+{
+ Q_ASSERT(mo);
+ const int i = mo->indexOfProperty(name);
+ return i < 0 ? QMetaProperty() : mo->property(i);
+}
+
/*! \internal
If \a indexInSignalRange is true, \a index is treated as a signal index
(see QObjectPrivate::signalIndex()), otherwise it is treated as a
@@ -1721,7 +1987,7 @@ static inline void flush_vme_signal(const QObject *object, int index, bool index
{
QQmlData *data = QQmlData::get(object);
if (data && data->propertyCache) {
- QQmlPropertyData *property = indexInSignalRange ? data->propertyCache->signal(index)
+ const QQmlPropertyData *property = indexInSignalRange ? data->propertyCache->signal(index)
: data->propertyCache->method(index);
if (property && property->isVMESignal()) {
@@ -1764,3 +2030,5 @@ void QQmlPropertyPrivate::flushSignal(const QObject *sender, int signal_index)
}
QT_END_NAMESPACE
+
+#include "moc_qqmlproperty.cpp"
diff --git a/src/qml/qml/qqmlproperty.h b/src/qml/qml/qqmlproperty.h
index aa455101dc..0878034bab 100644
--- a/src/qml/qml/qqmlproperty.h
+++ b/src/qml/qml/qqmlproperty.h
@@ -1,47 +1,14 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLPROPERTY_H
#define QQMLPROPERTY_H
+#include <QtCore/qstring.h>
+#include <QtCore/qhashfunctions.h>
#include <QtQml/qtqmlglobal.h>
#include <QtCore/qmetaobject.h>
+#include <QtQml/qqmlregistration.h>
QT_BEGIN_NAMESPACE
@@ -54,6 +21,12 @@ class QQmlEngine;
class QQmlPropertyPrivate;
class Q_QML_EXPORT QQmlProperty
{
+ Q_GADGET
+ QML_ANONYMOUS
+ QML_ADDED_IN_VERSION(2, 15)
+
+ Q_PROPERTY(QObject *object READ object CONSTANT FINAL)
+ Q_PROPERTY(QString name READ name CONSTANT FINAL)
public:
enum PropertyTypeCategory {
InvalidCategory,
@@ -82,6 +55,10 @@ public:
QQmlProperty(const QQmlProperty &);
QQmlProperty &operator=(const QQmlProperty &);
+ QQmlProperty(QQmlProperty &&other) noexcept : d(std::exchange(other.d, nullptr)) {}
+ QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_MOVE_AND_SWAP(QQmlProperty)
+
+ void swap(QQmlProperty &other) noexcept { qt_ptr_swap(d, other.d); }
bool operator==(const QQmlProperty &) const;
Type type() const;
@@ -125,7 +102,7 @@ public:
private:
friend class QQmlPropertyPrivate;
- QQmlPropertyPrivate *d;
+ QQmlPropertyPrivate *d = nullptr;
};
typedef QList<QQmlProperty> QQmlProperties;
diff --git a/src/qml/qml/qqmlproperty_p.h b/src/qml/qml/qqmlproperty_p.h
index c54d066152..fd07547d60 100644
--- a/src/qml/qml/qqmlproperty_p.h
+++ b/src/qml/qml/qqmlproperty_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLPROPERTY_P_H
#define QQMLPROPERTY_P_H
@@ -52,14 +16,17 @@
//
#include "qqmlproperty.h"
-#include "qqmlengine.h"
#include <private/qobject_p.h>
-#include <private/qtqmlglobal_p.h>
-#include <private/qqmlrefcount_p.h>
#include <private/qqmlcontextdata_p.h>
#include <private/qqmlpropertydata_p.h>
#include <private/qqmlpropertyindex_p.h>
+#include <private/qqmlrefcount_p.h>
+#include <private/qtqmlglobal_p.h>
+
+#include <QtQml/qqmlengine.h>
+
+#include <QtCore/qpointer.h>
QT_BEGIN_NAMESPACE
@@ -70,9 +37,16 @@ class QQmlMetaObject;
class QQmlAbstractBinding;
class QQmlBoundSignalExpression;
-class Q_QML_PRIVATE_EXPORT QQmlPropertyPrivate : public QQmlRefCount
+class Q_QML_EXPORT QQmlPropertyPrivate final : public QQmlRefCounted<QQmlPropertyPrivate>
{
public:
+ enum class InitFlag {
+ None = 0x0,
+ AllowId = 0x1,
+ AllowSignal = 0x2
+ };
+ Q_DECLARE_FLAGS(InitFlags, InitFlag);
+
QQmlRefPointer<QQmlContextData> context;
QPointer<QQmlEngine> engine;
QPointer<QObject> object;
@@ -82,6 +56,9 @@ public:
QString nameCache;
+ // ### Qt7: Get rid of this.
+ static bool resolveUrlsOnAssignment();
+
QQmlPropertyPrivate() {}
QQmlPropertyIndex encodedIndex() const
@@ -91,7 +68,7 @@ public:
QQmlRefPointer<QQmlContextData> effectiveContext() const;
- void initProperty(QObject *obj, const QString &name);
+ void initProperty(QObject *obj, const QString &name, InitFlags flags = InitFlag::None);
void initDefault(QObject *obj);
bool isValueType() const;
@@ -102,16 +79,22 @@ public:
QVariant readValueProperty();
bool writeValueProperty(const QVariant &, QQmlPropertyData::WriteFlags);
- static QQmlMetaObject rawMetaObjectForType(QQmlEnginePrivate *, int);
+ static QQmlMetaObject rawMetaObjectForType(QMetaType metaType);
static bool writeEnumProperty(const QMetaProperty &prop, int idx, QObject *object,
const QVariant &value, int flags);
static bool writeValueProperty(QObject *,
const QQmlPropertyData &, const QQmlPropertyData &valueTypeData,
const QVariant &, const QQmlRefPointer<QQmlContextData> &,
QQmlPropertyData::WriteFlags flags = {});
+ static bool resetValueProperty(QObject *,
+ const QQmlPropertyData &, const QQmlPropertyData &valueTypeData,
+ const QQmlRefPointer<QQmlContextData> &,
+ QQmlPropertyData::WriteFlags flags = {});
static bool write(QObject *, const QQmlPropertyData &, const QVariant &,
const QQmlRefPointer<QQmlContextData> &,
QQmlPropertyData::WriteFlags flags = {});
+ static bool reset(QObject *, const QQmlPropertyData &,
+ QQmlPropertyData::WriteFlags flags = {});
static void findAliasTarget(QObject *, QQmlPropertyIndex, QObject **, QQmlPropertyIndex *);
struct ResolvedAlias
@@ -156,19 +139,24 @@ public:
static bool write(const QQmlProperty &that, const QVariant &, QQmlPropertyData::WriteFlags);
static QQmlPropertyIndex propertyIndex(const QQmlProperty &that);
static QMetaMethod findSignalByName(const QMetaObject *mo, const QByteArray &);
+ static QMetaProperty findPropertyByName(const QMetaObject *mo, const QByteArray &);
static bool connect(const QObject *sender, int signal_index,
const QObject *receiver, int method_index,
int type = 0, int *types = nullptr);
static void flushSignal(const QObject *sender, int signal_index);
- static QVariant urlSequence(const QVariant &value);
+ static QList<QUrl> urlSequence(const QVariant &value);
+ static QList<QUrl> urlSequence(
+ const QVariant &value, const QQmlRefPointer<QQmlContextData> &ctxt);
static QQmlProperty create(
QObject *target, const QString &propertyName,
- const QQmlRefPointer<QQmlContextData> &context);
+ const QQmlRefPointer<QQmlContextData> &context,
+ QQmlPropertyPrivate::InitFlags flags);
};
Q_DECLARE_OPERATORS_FOR_FLAGS(QQmlPropertyPrivate::BindingFlags)
+Q_DECLARE_OPERATORS_FOR_FLAGS(QQmlPropertyPrivate::InitFlags);
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlpropertybinding.cpp b/src/qml/qml/qqmlpropertybinding.cpp
index e600748be7..c8a7e6256a 100644
--- a/src/qml/qml/qqmlpropertybinding.cpp
+++ b/src/qml/qml/qqmlpropertybinding.cpp
@@ -1,92 +1,44 @@
-/****************************************************************************
-**
-** Copyright (C) 2020 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$
-**
-****************************************************************************/
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qqmlpropertybinding_p.h"
+
+#include <private/qqmlbinding_p.h>
+#include <private/qqmlglobal_p.h>
+#include <private/qqmlscriptstring_p.h>
#include <private/qv4functionobject_p.h>
#include <private/qv4jscall_p.h>
-#include <qqmlinfo.h>
+#include <private/qv4qmlcontext_p.h>
+
+#include <QtQml/qqmlinfo.h>
+
+#include <QtCore/qloggingcategory.h>
QT_BEGIN_NAMESPACE
-namespace {
-constexpr std::size_t jsExpressionOffsetLength() {
- struct composite { QQmlPropertyBinding b; QQmlPropertyBindingJS js; };
- QT_WARNING_PUSH QT_WARNING_DISABLE_INVALID_OFFSETOF
- return sizeof (QQmlPropertyBinding) - offsetof(composite, js);
- QT_WARNING_POP
-}
-}
+using namespace Qt::Literals::StringLiterals;
-const QQmlPropertyBindingJS *QQmlPropertyBinding::jsExpression() const
-{
- return std::launder(reinterpret_cast<QQmlPropertyBindingJS const *>(reinterpret_cast<std::byte const*>(this) + sizeof(QQmlPropertyBinding) + jsExpressionOffsetLength()));
-}
+Q_LOGGING_CATEGORY(lcQQPropertyBinding, "qt.qml.propertybinding");
QUntypedPropertyBinding QQmlPropertyBinding::create(const QQmlPropertyData *pd, QV4::Function *function,
QObject *obj, const QQmlRefPointer<QQmlContextData> &ctxt,
QV4::ExecutionContext *scope, QObject *target, QQmlPropertyIndex targetIndex)
{
- if (auto aotFunction = function->aotFunction; aotFunction && aotFunction->returnType == pd->propType()) {
- return QUntypedPropertyBinding(aotFunction->returnType,
- [
- aotFunction,
- unit = QQmlRefPointer<QV4::ExecutableCompilationUnit>(function->executableCompilationUnit()),
- scopeObject = QPointer<QObject>(obj),
- context = ctxt,
- engine = scope->engine()
- ](const QMetaType &, void *dataPtr) -> bool {
- QQmlPrivate::AOTCompiledContext aotContext;
- aotContext.qmlContext = context->asQQmlContext();
- aotContext.qmlScopeObject = scopeObject.data();
- aotContext.engine = engine->jsEngine();
- aotContext.compilationUnit = unit.data();
- aotFunction->functionPtr(&aotContext, dataPtr, nullptr);
- // ### Fixme: The aotFunction should do the check whether old and new value are the same and
- // return false in that case
- return true;
- },
- QPropertyBindingSourceLocation());
- }
+ Q_ASSERT(pd);
+ return create(pd->propType(), function, obj, ctxt, scope, target, targetIndex);
+}
- auto buffer = new std::byte[sizeof(QQmlPropertyBinding)+sizeof(QQmlPropertyBindingJS)+jsExpressionOffsetLength()]; // QQmlPropertyBinding uses delete[]
- auto binding = new(buffer) QQmlPropertyBinding(QMetaType(pd->propType()), target, targetIndex, false);
- auto js = new(buffer + sizeof(QQmlPropertyBinding) + jsExpressionOffsetLength()) QQmlPropertyBindingJS();
+QUntypedPropertyBinding QQmlPropertyBinding::create(QMetaType propertyType, QV4::Function *function,
+ QObject *obj,
+ const QQmlRefPointer<QQmlContextData> &ctxt,
+ QV4::ExecutionContext *scope, QObject *target,
+ QQmlPropertyIndex targetIndex)
+{
+ auto buffer = new std::byte[QQmlPropertyBinding::getSizeEnsuringAlignment()
+ + sizeof(QQmlPropertyBindingJS)+jsExpressionOffsetLength()]; // QQmlPropertyBinding uses delete[]
+ auto binding = new (buffer) QQmlPropertyBinding(propertyType, target, targetIndex,
+ TargetData::WithoutBoundFunction);
+ auto js = new(buffer + QQmlPropertyBinding::getSizeEnsuringAlignment() + jsExpressionOffsetLength()) QQmlPropertyBindingJS();
Q_ASSERT(binding->jsExpression() == js);
Q_ASSERT(js->asBinding() == binding);
Q_UNUSED(js);
@@ -99,9 +51,10 @@ QUntypedPropertyBinding QQmlPropertyBinding::create(const QQmlPropertyData *pd,
QUntypedPropertyBinding QQmlPropertyBinding::createFromCodeString(const QQmlPropertyData *pd, const QString& str, QObject *obj, const QQmlRefPointer<QQmlContextData> &ctxt, const QString &url, quint16 lineNumber, QObject *target, QQmlPropertyIndex targetIndex)
{
- auto buffer = new std::byte[sizeof(QQmlPropertyBinding)+sizeof(QQmlPropertyBindingJS)+jsExpressionOffsetLength()]; // QQmlPropertyBinding uses delete[]
- auto binding = new(buffer) QQmlPropertyBinding(QMetaType(pd->propType()), target, targetIndex, true);
- auto js = new(buffer + sizeof(QQmlPropertyBinding) + jsExpressionOffsetLength()) QQmlPropertyBindingJS();
+ auto buffer = new std::byte[QQmlPropertyBinding::getSizeEnsuringAlignment()
+ + sizeof(QQmlPropertyBindingJS)+jsExpressionOffsetLength()]; // QQmlPropertyBinding uses delete[]
+ auto binding = new(buffer) QQmlPropertyBinding(QMetaType(pd->propType()), target, targetIndex, TargetData::WithoutBoundFunction);
+ auto js = new(buffer + QQmlPropertyBinding::getSizeEnsuringAlignment() + jsExpressionOffsetLength()) QQmlPropertyBindingJS();
Q_ASSERT(binding->jsExpression() == js);
Q_ASSERT(js->asBinding() == binding);
Q_UNUSED(js);
@@ -111,11 +64,50 @@ QUntypedPropertyBinding QQmlPropertyBinding::createFromCodeString(const QQmlProp
return QUntypedPropertyBinding(static_cast<QPropertyBindingPrivate *>(QPropertyBindingPrivatePtr(binding).data()));
}
+QUntypedPropertyBinding QQmlPropertyBinding::createFromScriptString(const QQmlPropertyData *property, const QQmlScriptString &script, QObject *obj, QQmlContext *ctxt, QObject *target, QQmlPropertyIndex targetIndex)
+{
+ const QQmlScriptStringPrivate *scriptPrivate = script.d.data();
+ // without a valid context, we cannot create anything
+ if (!ctxt && (!scriptPrivate->context || !scriptPrivate->context->isValid())) {
+ return {};
+ }
+
+ auto scopeObject = obj ? obj : scriptPrivate->scope;
+
+ QV4::Function *runtimeFunction = nullptr;
+ QString url;
+ QQmlRefPointer<QQmlContextData> ctxtdata = QQmlContextData::get(scriptPrivate->context);
+ QQmlEnginePrivate *engine = QQmlEnginePrivate::get(scriptPrivate->context->engine());
+ if (engine && ctxtdata && !ctxtdata->urlString().isEmpty() && ctxtdata->typeCompilationUnit()) {
+ url = ctxtdata->urlString();
+ if (scriptPrivate->bindingId != QQmlBinding::Invalid)
+ runtimeFunction = ctxtdata->typeCompilationUnit()->runtimeFunctions.at(scriptPrivate->bindingId);
+ }
+ // Do we actually have a function in the script string? If not, this becomes createCodeFromString
+ if (!runtimeFunction)
+ return createFromCodeString(property, scriptPrivate->script, obj, ctxtdata, url, scriptPrivate->lineNumber, target, targetIndex);
+
+ auto buffer = new std::byte[QQmlPropertyBinding::getSizeEnsuringAlignment()
+ + sizeof(QQmlPropertyBindingJS)+jsExpressionOffsetLength()]; // QQmlPropertyBinding uses delete[]
+ auto binding = new(buffer) QQmlPropertyBinding(QMetaType(property->propType()), target, targetIndex, TargetData::WithoutBoundFunction);
+ auto js = new(buffer + QQmlPropertyBinding::getSizeEnsuringAlignment() + jsExpressionOffsetLength()) QQmlPropertyBindingJS();
+ Q_ASSERT(binding->jsExpression() == js);
+ Q_ASSERT(js->asBinding() == binding);
+ js->setContext(QQmlContextData::get(ctxt ? ctxt : scriptPrivate->context));
+
+ QV4::ExecutionEngine *v4 = engine->v4engine();
+ QV4::Scope scope(v4);
+ QV4::Scoped<QV4::QmlContext> qmlContext(scope, QV4::QmlContext::create(v4->rootContext(), ctxtdata, scopeObject));
+ js->setupFunction(qmlContext, runtimeFunction);
+ return QUntypedPropertyBinding(static_cast<QPropertyBindingPrivate *>(QPropertyBindingPrivatePtr(binding).data()));
+}
+
QUntypedPropertyBinding QQmlPropertyBinding::createFromBoundFunction(const QQmlPropertyData *pd, QV4::BoundFunction *function, QObject *obj, const QQmlRefPointer<QQmlContextData> &ctxt, QV4::ExecutionContext *scope, QObject *target, QQmlPropertyIndex targetIndex)
{
- auto buffer = new std::byte[sizeof(QQmlPropertyBinding)+sizeof(QQmlPropertyBindingJSForBoundFunction)+jsExpressionOffsetLength()]; // QQmlPropertyBinding uses delete[]
- auto binding = new(buffer) QQmlPropertyBinding(QMetaType(pd->propType()), target, targetIndex, true);
- auto js = new(buffer + sizeof(QQmlPropertyBinding) + jsExpressionOffsetLength()) QQmlPropertyBindingJSForBoundFunction();
+ auto buffer = new std::byte[QQmlPropertyBinding::getSizeEnsuringAlignment()
+ + sizeof(QQmlPropertyBindingJSForBoundFunction)+jsExpressionOffsetLength()]; // QQmlPropertyBinding uses delete[]
+ auto binding = new(buffer) QQmlPropertyBinding(QMetaType(pd->propType()), target, targetIndex, TargetData::HasBoundFunction);
+ auto js = new(buffer + QQmlPropertyBinding::getSizeEnsuringAlignment() + jsExpressionOffsetLength()) QQmlPropertyBindingJSForBoundFunction();
Q_ASSERT(binding->jsExpression() == js);
Q_ASSERT(js->asBinding() == binding);
Q_UNUSED(js);
@@ -127,10 +119,25 @@ QUntypedPropertyBinding QQmlPropertyBinding::createFromBoundFunction(const QQmlP
return QUntypedPropertyBinding(static_cast<QPropertyBindingPrivate *>(QPropertyBindingPrivatePtr(binding).data()));
}
+/*!
+ \fn bool QQmlPropertyBindingJS::hasDependencies()
+ \internal
+
+ Returns true if this binding has dependencies.
+ Dependencies can be either QProperty dependencies or dependencies of
+ the JS expression (aka activeGuards). Translations end up as a QProperty
+ dependency, so they do not need any special handling
+ Note that a QQmlPropertyBinding never stores qpropertyChangeTriggers.
+ */
+
+
void QQmlPropertyBindingJS::expressionChanged()
{
+ auto binding = asBinding();
+ if (!binding->propertyDataPtr)
+ return;
const auto currentTag = m_error.tag();
- if (currentTag & InEvaluationLoop) {
+ if (currentTag == InEvaluationLoop) {
QQmlError err;
auto location = QQmlJavaScriptExpression::sourceLocation();
err.setUrl(QUrl{location.sourceFile});
@@ -139,160 +146,142 @@ void QQmlPropertyBindingJS::expressionChanged()
const auto ctxt = context();
QQmlEngine *engine = ctxt ? ctxt->engine() : nullptr;
if (engine)
- err.setDescription(asBinding()->createBindingLoopErrorDescription(QQmlEnginePrivate::get(engine)));
+ err.setDescription(asBinding()->createBindingLoopErrorDescription());
else
err.setDescription(QString::fromLatin1("Binding loop detected"));
err.setObject(asBinding()->target());
qmlWarning(this->scopeObject(), err);
return;
}
- m_error.setTag(currentTag | InEvaluationLoop);
- asBinding()->markDirtyAndNotifyObservers();
- m_error.setTag(currentTag);
+ m_error.setTag(InEvaluationLoop);
+ PendingBindingObserverList bindingObservers;
+ binding->evaluateRecursive(bindingObservers);
+ binding->notifyNonRecursive(bindingObservers);
+ m_error.setTag(NoTag);
}
-const QQmlPropertyBinding *QQmlPropertyBindingJS::asBinding() const
-{
- return std::launder(reinterpret_cast<QQmlPropertyBinding const *>(reinterpret_cast<std::byte const*>(this) - sizeof(QQmlPropertyBinding) - jsExpressionOffsetLength()));
-}
-
-QQmlPropertyBinding::QQmlPropertyBinding(QMetaType mt, QObject *target, QQmlPropertyIndex targetIndex, bool hasBoundFunction)
+QQmlPropertyBinding::QQmlPropertyBinding(QMetaType mt, QObject *target, QQmlPropertyIndex targetIndex, TargetData::BoundFunction hasBoundFunction)
: QPropertyBindingPrivate(mt,
- &QtPrivate::bindingFunctionVTable<QQmlPropertyBinding>,
+ bindingFunctionVTableForQQmlPropertyBinding(mt),
QPropertyBindingSourceLocation(), true)
{
static_assert (std::is_trivially_destructible_v<TargetData>);
static_assert (sizeof(TargetData) + sizeof(DeclarativeErrorCallback) <= sizeof(QPropertyBindingSourceLocation));
static_assert (alignof(TargetData) <= alignof(QPropertyBindingSourceLocation));
- new (&declarativeExtraData) TargetData {target, targetIndex, hasBoundFunction};
+ const auto state = hasBoundFunction ? TargetData::HasBoundFunction : TargetData::WithoutBoundFunction;
+ new (&declarativeExtraData) TargetData {target, targetIndex, state};
errorCallBack = bindingErrorCallback;
}
-bool QQmlPropertyBinding::evaluate(QMetaType metaType, void *dataPtr)
+static QtPrivate::QPropertyBindingData *bindingDataFromPropertyData(QUntypedPropertyData *dataPtr, QMetaType type)
{
- const auto ctxt = jsExpression()->context();
- QQmlEngine *engine = ctxt ? ctxt->engine() : nullptr;
- if (!engine) {
- QPropertyBindingError error(QPropertyBindingError::EvaluationError);
- QPropertyBindingPrivate::currentlyEvaluatingBinding()->setError(std::move(error));
- return false;
- }
- QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine);
- ep->referenceScarceResources();
-
- bool isUndefined = false;
-
- QV4::Scope scope(engine->handle());
- QV4::ScopedValue result(scope, hasBoundFunction()
- ? static_cast<QQmlPropertyBindingJSForBoundFunction *>(jsExpression())->evaluate(&isUndefined)
- : jsExpression()->evaluate(&isUndefined));
-
- ep->dereferenceScarceResources();
-
- if (jsExpression()->hasError()) {
- QPropertyBindingError error(QPropertyBindingError::UnknownError, jsExpression()->delayedError()->error().description());
- QPropertyBindingPrivate::currentlyEvaluatingBinding()->setError(std::move(error));
- bindingErrorCallback(this);
- return false;
- }
+ // XXX Qt 7: We need a clean way to access the binding data
+ /* This function makes the (dangerous) assumption that if we could not get the binding data
+ from the binding storage, we must have been handed a QProperty.
+ This does hold for anything a user could write, as there the only ways of providing a bindable property
+ are to use the Q_X_BINDABLE macros, or to directly expose a QProperty.
+ As long as we can ensure that any "fancier" property we implement is not resettable, we should be fine.
+ We procede to calculate the address of the binding data pointer from the address of the data pointer
+ */
+ Q_ASSERT(dataPtr);
+ std::byte *qpropertyPointer = reinterpret_cast<std::byte *>(dataPtr);
+ qpropertyPointer += type.sizeOf();
+ constexpr auto alignment = alignof(QtPrivate::QPropertyBindingData *);
+ auto aligned = (quintptr(qpropertyPointer) + alignment - 1) & ~(alignment - 1); // ensure pointer alignment
+ return reinterpret_cast<QtPrivate::QPropertyBindingData *>(aligned);
+}
- int propertyType = metaType.id();
+void QQmlPropertyBinding::handleUndefinedAssignment(QQmlEnginePrivate *ep, void *dataPtr)
+{
+ const QQmlPropertyData *propertyData = nullptr;
+ QQmlPropertyData valueTypeData;
+ QQmlData *data = QQmlData::get(target(), false);
+ Q_ASSERT(data);
+ if (Q_UNLIKELY(!data->propertyCache))
+ data->propertyCache = QQmlMetaType::propertyCache(target()->metaObject());
- switch (propertyType) {
- case QMetaType::Bool: {
- bool b;
- if (result->isBoolean())
- b = result->booleanValue();
- else
- b = result->toBoolean();
- if (b == *static_cast<bool *>(dataPtr))
- return false;
- *static_cast<bool *>(dataPtr) = b;
- return true;
- }
- case QMetaType::Int: {
- int i;
- if (result->isInteger())
- i = result->integerValue();
- else if (result->isNumber()) {
- i = QV4::StaticValue::toInteger(result->doubleValue());
- } else {
- break;
- }
- if (i == *static_cast<int *>(dataPtr))
- return false;
- *static_cast<int *>(dataPtr) = i;
- return true;
- }
- case QMetaType::Double:
- if (result->isNumber()) {
- double d = result->asDouble();
- if (d == *static_cast<double *>(dataPtr))
- return false;
- *static_cast<double *>(dataPtr) = d;
- return true;
- }
- break;
- case QMetaType::Float:
- if (result->isNumber()) {
- float d = float(result->asDouble());
- if (d == *static_cast<float *>(dataPtr))
- return false;
- *static_cast<float *>(dataPtr) = d;
- return true;
+ propertyData = data->propertyCache->property(targetIndex().coreIndex());
+ Q_ASSERT(propertyData);
+ Q_ASSERT(!targetIndex().hasValueTypeIndex());
+ QQmlProperty prop = QQmlPropertyPrivate::restore(target(), *propertyData, &valueTypeData, nullptr);
+ // helper function for writing back value into dataPtr
+ // this is necessary for QObjectCompatProperty, which doesn't give us the "real" dataPtr
+ // if we don't write the correct value, we would otherwise set the default constructed value
+ auto writeBackCurrentValue = [&](QVariant &&currentValue) {
+ if (currentValue.metaType() != valueMetaType())
+ currentValue.convert(valueMetaType());
+ auto metaType = valueMetaType();
+ metaType.destruct(dataPtr);
+ metaType.construct(dataPtr, currentValue.constData());
+ };
+ if (prop.isResettable()) {
+ // Normally a reset would remove any existing binding; but now we need to keep the binding alive
+ // to handle the case where this binding becomes defined again
+ // We therefore detach the binding, call reset, and reattach again
+ const auto storage = qGetBindingStorage(target());
+ auto bindingData = storage->bindingData(propertyDataPtr);
+ if (!bindingData)
+ bindingData = bindingDataFromPropertyData(propertyDataPtr, propertyData->propType());
+ QPropertyBindingDataPointer bindingDataPointer{bindingData};
+ auto firstObserver = takeObservers();
+ bindingData->d_ref() = 0;
+ if (firstObserver) {
+ bindingDataPointer.setObservers(firstObserver.ptr);
}
- break;
- case QMetaType::QString:
- if (result->isString()) {
- QString s = result->toQStringNoThrow();
- if (s == *static_cast<QString *>(dataPtr))
- return false;
- *static_cast<QString *>(dataPtr) = s;
- return true;
+ Q_ASSERT(!bindingData->hasBinding());
+ setIsUndefined(true);
+ //suspend binding evaluation state for reset and subsequent read
+ auto state = QtPrivate::suspendCurrentBindingStatus();
+ prop.reset(); // May re-allocate the bindingData
+ QVariant currentValue = QVariant(prop.propertyMetaType(), propertyDataPtr);
+ QtPrivate::restoreBindingStatus(state);
+ writeBackCurrentValue(std::move(currentValue));
+
+ // Re-fetch binding data
+ bindingData = storage->bindingData(propertyDataPtr);
+ if (!bindingData)
+ bindingData = bindingDataFromPropertyData(propertyDataPtr, propertyData->propType());
+ bindingDataPointer = QPropertyBindingDataPointer {bindingData};
+
+ // reattach the binding (without causing a new notification)
+ if (Q_UNLIKELY(bindingData->d() & QtPrivate::QPropertyBindingData::BindingBit)) {
+ qCWarning(lcQQPropertyBinding) << "Resetting " << prop.name() << "due to the binding becoming undefined caused a new binding to be installed\n"
+ << "The old binding binding will be abandoned";
+ deref();
+ return;
}
- break;
- default:
- break;
+ // reset might have changed observers (?), so refresh firstObserver
+ firstObserver = bindingDataPointer.firstObserver();
+ bindingData->d_ref() = reinterpret_cast<quintptr>(this) | QtPrivate::QPropertyBindingData::BindingBit;
+ if (firstObserver)
+ prependObserver(firstObserver);
+ } else {
+ QQmlError qmlError;
+ auto location = jsExpression()->sourceLocation();
+ qmlError.setColumn(location.column);
+ qmlError.setLine(location.line);
+ qmlError.setUrl(QUrl {location.sourceFile});
+ const QString description = QStringLiteral(R"(QML %1: Unable to assign [undefined] to "%2")").arg(QQmlMetaType::prettyTypeName(target()) , prop.name());
+ qmlError.setDescription(description);
+ qmlError.setObject(target());
+ ep->warning(qmlError);
}
-
- QVariant resultVariant(scope.engine->toVariant(result, metaType.id()));
- resultVariant.convert(metaType);
- const bool hasChanged = !metaType.equals(resultVariant.constData(), dataPtr);
- metaType.destruct(dataPtr);
- metaType.construct(dataPtr, resultVariant.constData());
- return hasChanged;
}
-QString QQmlPropertyBinding::createBindingLoopErrorDescription(QJSEnginePrivate *ep)
+QString QQmlPropertyBinding::createBindingLoopErrorDescription()
{
- QQmlPropertyData *propertyData = nullptr;
+ const QQmlPropertyData *propertyData = nullptr;
QQmlPropertyData valueTypeData;
QQmlData *data = QQmlData::get(target(), false);
Q_ASSERT(data);
- if (Q_UNLIKELY(!data->propertyCache)) {
- data->propertyCache = ep->cache(target()->metaObject());
- data->propertyCache->addref();
- }
+ if (Q_UNLIKELY(!data->propertyCache))
+ data->propertyCache = QQmlMetaType::propertyCache(target()->metaObject());
+
propertyData = data->propertyCache->property(targetIndex().coreIndex());
Q_ASSERT(propertyData);
Q_ASSERT(!targetIndex().hasValueTypeIndex());
QQmlProperty prop = QQmlPropertyPrivate::restore(target(), *propertyData, &valueTypeData, nullptr);
- return QStringLiteral(R"(QML %1: Binding loop detected for property "%2")").arg(QQmlMetaType::prettyTypeName(target()) , prop.name());
-}
-
-QObject *QQmlPropertyBinding::target()
-{
- return std::launder(reinterpret_cast<TargetData *>(&declarativeExtraData))->target;
-}
-
-QQmlPropertyIndex QQmlPropertyBinding::targetIndex()
-{
- return std::launder(reinterpret_cast<TargetData *>(&declarativeExtraData))->targetIndex;
-}
-
-bool QQmlPropertyBinding::hasBoundFunction()
-{
- return std::launder(reinterpret_cast<TargetData *>(&declarativeExtraData))->hasBoundFunction;
+ return R"(QML %1: Binding loop detected for property "%2")"_L1.arg(QQmlMetaType::prettyTypeName(target()) , prop.name());
}
void QQmlPropertyBinding::bindingErrorCallback(QPropertyBindingPrivate *that)
@@ -302,7 +291,6 @@ void QQmlPropertyBinding::bindingErrorCallback(QPropertyBindingPrivate *that)
auto engine = qmlEngine(target);
if (!engine)
return;
- auto ep = QQmlEnginePrivate::get(engine);
auto error = This->bindingError();
QQmlError qmlError;
@@ -312,21 +300,24 @@ void QQmlPropertyBinding::bindingErrorCallback(QPropertyBindingPrivate *that)
qmlError.setUrl(QUrl {location.sourceFile});
auto description = error.description();
if (error.type() == QPropertyBindingError::BindingLoop) {
- description = This->createBindingLoopErrorDescription(ep);
+ description = This->createBindingLoopErrorDescription();
}
qmlError.setDescription(description);
qmlError.setObject(target);
- ep->warning(qmlError);
+ QQmlEnginePrivate::get(engine)->warning(qmlError);
}
-QUntypedPropertyBinding QQmlTranslationPropertyBinding::create(const QQmlPropertyData *pd, const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit, const QV4::CompiledData::Binding *binding)
+template<typename TranslateWithUnit>
+auto qQmlTranslationPropertyBindingCreateBinding(
+ const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit,
+ TranslateWithUnit &&translateWithUnit)
{
- auto translationBinding = [compilationUnit, binding](const QMetaType &metaType, void *dataPtr) -> bool {
- // Create a dependency to the uiLanguage
- QJSEnginePrivate::get(compilationUnit->engine)->uiLanguage.value();
+ return [compilationUnit, translateWithUnit](QMetaType metaType, void *dataPtr) -> bool {
+ // Create a dependency to the translationLanguage
+ QQmlEnginePrivate::get(compilationUnit->engine)->translationLanguage.value();
- QVariant resultVariant(compilationUnit->bindingValueAsString(binding));
- if (metaType.id() != QMetaType::QString)
+ QVariant resultVariant(translateWithUnit(compilationUnit));
+ if (metaType != QMetaType::fromType<QString>())
resultVariant.convert(metaType);
const bool hasChanged = !metaType.equals(resultVariant.constData(), dataPtr);
@@ -334,8 +325,38 @@ QUntypedPropertyBinding QQmlTranslationPropertyBinding::create(const QQmlPropert
metaType.construct(dataPtr, resultVariant.constData());
return hasChanged;
};
+}
- return QUntypedPropertyBinding(QMetaType(pd->propType()), translationBinding, QPropertyBindingSourceLocation());
+QUntypedPropertyBinding QQmlTranslationPropertyBinding::create(
+ const QQmlPropertyData *pd,
+ const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit,
+ const QV4::CompiledData::Binding *binding)
+{
+ auto translationBinding = qQmlTranslationPropertyBindingCreateBinding(
+ compilationUnit,
+ [binding](const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit) {
+ return compilationUnit->bindingValueAsString(binding);
+ });
+
+ return QUntypedPropertyBinding(QMetaType(pd->propType()), translationBinding,
+ QPropertyBindingSourceLocation());
+}
+
+QUntypedPropertyBinding QQmlTranslationPropertyBinding::create(
+ const QMetaType &propertyType,
+ const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit,
+ const QQmlTranslation &translationData)
+{
+ auto translationBinding = qQmlTranslationPropertyBindingCreateBinding(
+ compilationUnit,
+ [translationData](
+ const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit) {
+ Q_UNUSED(compilationUnit);
+ return translationData.translate();
+ });
+
+ return QUntypedPropertyBinding(propertyType, translationBinding,
+ QPropertyBindingSourceLocation());
}
QV4::ReturnedValue QQmlPropertyBindingJSForBoundFunction::evaluate(bool *isUndefined)
@@ -345,7 +366,7 @@ QV4::ReturnedValue QQmlPropertyBindingJSForBoundFunction::evaluate(bool *isUndef
const QV4::Value *argv = nullptr;
const QV4::Value *thisObject = nullptr;
QV4::BoundFunction *b = nullptr;
- if ((b = static_cast<QV4::BoundFunction *>(m_boundFunction.valueRef()))) {
+ if ((b = m_boundFunction.as<QV4::BoundFunction>())) {
QV4::Heap::MemberData *args = b->boundArgs();
if (args) {
argc = args->values.size;
@@ -354,9 +375,9 @@ QV4::ReturnedValue QQmlPropertyBindingJSForBoundFunction::evaluate(bool *isUndef
thisObject = &b->d()->boundThis;
}
QV4::Scope scope(v4);
- QV4::JSCallData jsCall(scope, argc, argv, thisObject);
+ QV4::JSCallData jsCall(thisObject, argv, argc);
- return QQmlJavaScriptExpression::evaluate(jsCall.callData(), isUndefined);
+ return QQmlJavaScriptExpression::evaluate(jsCall.callData(scope), isUndefined);
}
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlpropertybinding_p.h b/src/qml/qml/qqmlpropertybinding_p.h
index 7c7fac866a..840239285e 100644
--- a/src/qml/qml/qqmlpropertybinding_p.h
+++ b/src/qml/qml/qqmlpropertybinding_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2020 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$
-**
-****************************************************************************/
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLPROPERTYBINDING_P_H
#define QQMLPROPERTYBINDING_P_H
@@ -51,11 +15,12 @@
// We mean it.
//
-#include <QtCore/qproperty.h>
-#include <QtCore/private/qproperty_p.h>
+#include <private/qqmljavascriptexpression_p.h>
+#include <private/qqmlpropertydata_p.h>
+#include <private/qv4alloca_p.h>
+#include <private/qqmltranslation_p.h>
-#include "qqmlpropertydata_p.h"
-#include "qqmljavascriptexpression_p.h"
+#include <QtCore/qproperty.h>
#include <memory>
@@ -66,76 +31,151 @@ namespace QV4 {
}
class QQmlPropertyBinding;
+class QQmlScriptString;
-class Q_QML_PRIVATE_EXPORT QQmlPropertyBindingJS : public QQmlJavaScriptExpression
+class Q_QML_EXPORT QQmlPropertyBindingJS : public QQmlJavaScriptExpression
{
+ bool mustCaptureBindableProperty() const final {return false;}
+
friend class QQmlPropertyBinding;
void expressionChanged() override;
QQmlPropertyBinding *asBinding()
{
return const_cast<QQmlPropertyBinding *>(static_cast<const QQmlPropertyBindingJS *>(this)->asBinding());
}
- QQmlPropertyBinding const *asBinding() const;;
+
+ inline QQmlPropertyBinding const *asBinding() const;
};
-class Q_QML_PRIVATE_EXPORT QQmlPropertyBindingJSForBoundFunction : public QQmlPropertyBindingJS
+class Q_QML_EXPORT QQmlPropertyBindingJSForBoundFunction : public QQmlPropertyBindingJS
{
public:
QV4::ReturnedValue evaluate(bool *isUndefined);
QV4::PersistentValue m_boundFunction;
};
-class Q_QML_PRIVATE_EXPORT QQmlPropertyBinding : public QPropertyBindingPrivate
+class Q_QML_EXPORT QQmlPropertyBinding : public QPropertyBindingPrivate
{
friend class QQmlPropertyBindingJS;
+
+ static constexpr std::size_t jsExpressionOffsetLength() {
+ struct composite { QQmlPropertyBinding b; QQmlPropertyBindingJS js; };
+ QT_WARNING_PUSH QT_WARNING_DISABLE_INVALID_OFFSETOF
+ return sizeof (QQmlPropertyBinding) - offsetof(composite, js);
+ QT_WARNING_POP
+ }
+
public:
QQmlPropertyBindingJS *jsExpression()
{
return const_cast<QQmlPropertyBindingJS *>(static_cast<const QQmlPropertyBinding *>(this)->jsExpression());
}
- QQmlPropertyBindingJS const *jsExpression() const;
+
+ QQmlPropertyBindingJS const *jsExpression() const
+ {
+ return std::launder(reinterpret_cast<QQmlPropertyBindingJS const *>(
+ reinterpret_cast<std::byte const*>(this)
+ + QPropertyBindingPrivate::getSizeEnsuringAlignment()
+ + jsExpressionOffsetLength()));
+ }
static QUntypedPropertyBinding create(const QQmlPropertyData *pd, QV4::Function *function,
QObject *obj, const QQmlRefPointer<QQmlContextData> &ctxt,
QV4::ExecutionContext *scope, QObject *target,
QQmlPropertyIndex targetIndex);
+ static QUntypedPropertyBinding create(QMetaType propertyType, QV4::Function *function,
+ QObject *obj, const QQmlRefPointer<QQmlContextData> &ctxt,
+ QV4::ExecutionContext *scope, QObject *target,
+ QQmlPropertyIndex targetIndex);
static QUntypedPropertyBinding createFromCodeString(const QQmlPropertyData *property,
const QString &str, QObject *obj,
const QQmlRefPointer<QQmlContextData> &ctxt,
const QString &url, quint16 lineNumber,
QObject *target, QQmlPropertyIndex targetIndex);
+ static QUntypedPropertyBinding createFromScriptString(const QQmlPropertyData *property,
+ const QQmlScriptString& script, QObject *obj,
+ QQmlContext *ctxt, QObject *target,
+ QQmlPropertyIndex targetIndex);
static QUntypedPropertyBinding createFromBoundFunction(const QQmlPropertyData *pd, QV4::BoundFunction *function,
QObject *obj, const QQmlRefPointer<QQmlContextData> &ctxt,
QV4::ExecutionContext *scope, QObject *target,
QQmlPropertyIndex targetIndex);
+ static bool isUndefined(const QUntypedPropertyBinding &binding)
+ {
+ return isUndefined(QPropertyBindingPrivate::get(binding));
+ }
+
+ static bool isUndefined(const QPropertyBindingPrivate *binding)
+ {
+ if (!(binding && binding->hasCustomVTable()))
+ return false;
+ return static_cast<const QQmlPropertyBinding *>(binding)->isUndefined();
+ }
+ template<QMetaType::Type type>
static bool doEvaluate(QMetaType metaType, QUntypedPropertyData *dataPtr, void *f) {
auto address = static_cast<std::byte*>(f);
- address -= sizeof (QPropertyBindingPrivate); // f now points to QPropertyBindingPrivate suboject
+ address -= QPropertyBindingPrivate::getSizeEnsuringAlignment(); // f now points to QPropertyBindingPrivate suboject
// and that has the same address as QQmlPropertyBinding
- return reinterpret_cast<QQmlPropertyBinding *>(address)->evaluate(metaType, dataPtr);
+ return reinterpret_cast<QQmlPropertyBinding *>(address)->evaluate<type>(metaType, dataPtr);
}
-private:
- QQmlPropertyBinding(QMetaType metaType, QObject *target, QQmlPropertyIndex targetIndex, bool hasBoundFunction);
+ bool hasDependencies()
+ {
+ return (dependencyObserverCount > 0) || !jsExpression()->activeGuards.isEmpty();
+ }
+private:
+ template <QMetaType::Type type>
bool evaluate(QMetaType metaType, void *dataPtr);
- QString createBindingLoopErrorDescription(QJSEnginePrivate *ep);
+ Q_NEVER_INLINE void handleUndefinedAssignment(QQmlEnginePrivate *ep, void *dataPtr);
+
+ QString createBindingLoopErrorDescription();
struct TargetData {
+ enum BoundFunction : bool {
+ WithoutBoundFunction = false,
+ HasBoundFunction = true,
+ };
+ TargetData(QObject *target, QQmlPropertyIndex index, BoundFunction state)
+ : target(target), targetIndex(index), hasBoundFunction(state)
+ {}
QObject *target;
QQmlPropertyIndex targetIndex;
bool hasBoundFunction;
+ bool isUndefined = false;
};
+ QQmlPropertyBinding(QMetaType metaType, QObject *target, QQmlPropertyIndex targetIndex, TargetData::BoundFunction hasBoundFunction);
+
+ QObject *target()
+ {
+ return std::launder(reinterpret_cast<TargetData *>(&declarativeExtraData))->target;
+ }
+
+ QQmlPropertyIndex targetIndex()
+ {
+ return std::launder(reinterpret_cast<TargetData *>(&declarativeExtraData))->targetIndex;
+ }
+
+ bool hasBoundFunction()
+ {
+ return std::launder(reinterpret_cast<TargetData *>(&declarativeExtraData))->hasBoundFunction;
+ }
+
+ bool isUndefined() const
+ {
+ return std::launder(reinterpret_cast<TargetData const *>(&declarativeExtraData))->isUndefined;
+ }
- QObject *target();
- QQmlPropertyIndex targetIndex();
- bool hasBoundFunction();
+ void setIsUndefined(bool isUndefined)
+ {
+ std::launder(reinterpret_cast<TargetData *>(&declarativeExtraData))->isUndefined = isUndefined;
+ }
static void bindingErrorCallback(QPropertyBindingPrivate *);
};
@@ -144,9 +184,9 @@ template <auto I>
struct Print {};
namespace QtPrivate {
-template<>
-inline constexpr BindingFunctionVTable bindingFunctionVTable<QQmlPropertyBinding> = {
- &QQmlPropertyBinding::doEvaluate,
+template<QMetaType::Type type>
+inline constexpr BindingFunctionVTable bindingFunctionVTableForQQmlPropertyBinding = {
+ &QQmlPropertyBinding::doEvaluate<type>,
[](void *qpropertyBinding){
QQmlPropertyBinding *binding = reinterpret_cast<QQmlPropertyBinding *>(qpropertyBinding);
binding->jsExpression()->~QQmlPropertyBindingJS();
@@ -159,14 +199,223 @@ inline constexpr BindingFunctionVTable bindingFunctionVTable<QQmlPropertyBinding
};
}
+inline const QtPrivate::BindingFunctionVTable *bindingFunctionVTableForQQmlPropertyBinding(QMetaType type)
+{
+#define FOR_TYPE(TYPE) \
+ case TYPE: return &QtPrivate::bindingFunctionVTableForQQmlPropertyBinding<TYPE>
+ switch (type.id()) {
+ FOR_TYPE(QMetaType::Int);
+ FOR_TYPE(QMetaType::QString);
+ FOR_TYPE(QMetaType::Double);
+ FOR_TYPE(QMetaType::Float);
+ FOR_TYPE(QMetaType::Bool);
+ default:
+ if (type.flags() & QMetaType::PointerToQObject)
+ return &QtPrivate::bindingFunctionVTableForQQmlPropertyBinding<QMetaType::QObjectStar>;
+ return &QtPrivate::bindingFunctionVTableForQQmlPropertyBinding<QMetaType::UnknownType>;
+ }
+#undef FOR_TYPE
+}
+
class QQmlTranslationPropertyBinding
{
public:
- static QUntypedPropertyBinding Q_QML_PRIVATE_EXPORT create(const QQmlPropertyData *pd,
+ static QUntypedPropertyBinding Q_QML_EXPORT create(const QQmlPropertyData *pd,
const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit,
const QV4::CompiledData::Binding *binding);
+ static QUntypedPropertyBinding Q_QML_EXPORT
+ create(const QMetaType &pd,
+ const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit,
+ const QQmlTranslation &translationData);
};
+inline const QQmlPropertyBinding *QQmlPropertyBindingJS::asBinding() const
+{
+ return std::launder(reinterpret_cast<QQmlPropertyBinding const *>(
+ reinterpret_cast<std::byte const*>(this)
+ - QPropertyBindingPrivate::getSizeEnsuringAlignment()
+ - QQmlPropertyBinding::jsExpressionOffsetLength()));
+}
+
+static_assert(sizeof(QQmlPropertyBinding) == sizeof(QPropertyBindingPrivate)); // else the whole offset computatation will break
+template<typename T>
+bool compareAndAssign(void *dataPtr, const void *result)
+{
+ if (*static_cast<const T *>(result) == *static_cast<const T *>(dataPtr))
+ return false;
+ *static_cast<T *>(dataPtr) = *static_cast<const T *>(result);
+ return true;
+}
+
+template <QMetaType::Type type>
+bool QQmlPropertyBinding::evaluate(QMetaType metaType, void *dataPtr)
+{
+ const auto ctxt = jsExpression()->context();
+ QQmlEngine *engine = ctxt ? ctxt->engine() : nullptr;
+ if (!engine) {
+ QPropertyBindingError error(QPropertyBindingError::EvaluationError);
+ if (auto currentBinding = QPropertyBindingPrivate::currentlyEvaluatingBinding())
+ currentBinding->setError(std::move(error));
+ return false;
+ }
+ QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine);
+ ep->referenceScarceResources();
+
+ const auto handleErrorAndUndefined = [&](bool evaluatedToUndefined) {
+ ep->dereferenceScarceResources();
+ if (jsExpression()->hasError()) {
+ QPropertyBindingError error(QPropertyBindingError::UnknownError,
+ jsExpression()->delayedError()->error().description());
+ QPropertyBindingPrivate::currentlyEvaluatingBinding()->setError(std::move(error));
+ bindingErrorCallback(this);
+ return false;
+ }
+
+ if (evaluatedToUndefined) {
+ handleUndefinedAssignment(ep, dataPtr);
+ // if property has been changed due to reset, reset is responsible for
+ // notifying observers
+ return false;
+ } else if (isUndefined()) {
+ setIsUndefined(false);
+ }
+
+ return true;
+ };
+
+ if (!hasBoundFunction()) {
+ Q_ASSERT(metaType.sizeOf() > 0);
+
+ using Tuple = std::tuple<qsizetype, bool, bool>;
+ const auto [size, needsConstruction, needsDestruction] = [&]() -> Tuple {
+ switch (type) {
+ case QMetaType::QObjectStar: return Tuple(sizeof(QObject *), false, false);
+ case QMetaType::Bool: return Tuple(sizeof(bool), false, false);
+ case QMetaType::Int: return Tuple(sizeof(int), false, false);
+ case QMetaType::Double: return Tuple(sizeof(double), false, false);
+ case QMetaType::Float: return Tuple(sizeof(float), false, false);
+ case QMetaType::QString: return Tuple(sizeof(QString), true, true);
+ default: {
+ const auto flags = metaType.flags();
+ return Tuple(
+ metaType.sizeOf(),
+ flags & QMetaType::NeedsConstruction,
+ flags & QMetaType::NeedsDestruction);
+ }
+ }
+ }();
+ Q_ALLOCA_VAR(void, result, size);
+ if (needsConstruction)
+ metaType.construct(result);
+
+ const bool evaluatedToUndefined = !jsExpression()->evaluate(&result, &metaType, 0);
+ if (!handleErrorAndUndefined(evaluatedToUndefined))
+ return false;
+
+ switch (type) {
+ case QMetaType::QObjectStar:
+ return compareAndAssign<QObject *>(dataPtr, result);
+ case QMetaType::Bool:
+ return compareAndAssign<bool>(dataPtr, result);
+ case QMetaType::Int:
+ return compareAndAssign<int>(dataPtr, result);
+ case QMetaType::Double:
+ return compareAndAssign<double>(dataPtr, result);
+ case QMetaType::Float:
+ return compareAndAssign<float>(dataPtr, result);
+ case QMetaType::QString: {
+ const bool hasChanged = compareAndAssign<QString>(dataPtr, result);
+ static_cast<QString *>(result)->~QString();
+ return hasChanged;
+ }
+ default:
+ break;
+ }
+
+ const bool hasChanged = !metaType.equals(result, dataPtr);
+ if (hasChanged) {
+ if (needsDestruction)
+ metaType.destruct(dataPtr);
+ metaType.construct(dataPtr, result);
+ }
+ if (needsDestruction)
+ metaType.destruct(result);
+ return hasChanged;
+ }
+
+ bool evaluatedToUndefined = false;
+ QV4::Scope scope(engine->handle());
+ QV4::ScopedValue result(scope, static_cast<QQmlPropertyBindingJSForBoundFunction *>(
+ jsExpression())->evaluate(&evaluatedToUndefined));
+
+ if (!handleErrorAndUndefined(evaluatedToUndefined))
+ return false;
+
+ switch (type) {
+ case QMetaType::Bool: {
+ bool b;
+ if (result->isBoolean())
+ b = result->booleanValue();
+ else
+ b = result->toBoolean();
+ if (b == *static_cast<bool *>(dataPtr))
+ return false;
+ *static_cast<bool *>(dataPtr) = b;
+ return true;
+ }
+ case QMetaType::Int: {
+ int i;
+ if (result->isInteger())
+ i = result->integerValue();
+ else if (result->isNumber()) {
+ i = QV4::StaticValue::toInteger(result->doubleValue());
+ } else {
+ break;
+ }
+ if (i == *static_cast<int *>(dataPtr))
+ return false;
+ *static_cast<int *>(dataPtr) = i;
+ return true;
+ }
+ case QMetaType::Double:
+ if (result->isNumber()) {
+ double d = result->asDouble();
+ if (d == *static_cast<double *>(dataPtr))
+ return false;
+ *static_cast<double *>(dataPtr) = d;
+ return true;
+ }
+ break;
+ case QMetaType::Float:
+ if (result->isNumber()) {
+ float d = float(result->asDouble());
+ if (d == *static_cast<float *>(dataPtr))
+ return false;
+ *static_cast<float *>(dataPtr) = d;
+ return true;
+ }
+ break;
+ case QMetaType::QString:
+ if (result->isString()) {
+ QString s = result->toQStringNoThrow();
+ if (s == *static_cast<QString *>(dataPtr))
+ return false;
+ *static_cast<QString *>(dataPtr) = s;
+ return true;
+ }
+ break;
+ default:
+ break;
+ }
+
+ QVariant resultVariant(QV4::ExecutionEngine::toVariant(result, metaType));
+ resultVariant.convert(metaType);
+ const bool hasChanged = !metaType.equals(resultVariant.constData(), dataPtr);
+ metaType.destruct(dataPtr);
+ metaType.construct(dataPtr, resultVariant.constData());
+ return hasChanged;
+}
+
QT_END_NAMESPACE
#endif // QQMLPROPERTYBINDING_P_H
diff --git a/src/qml/qml/qqmlpropertycache.cpp b/src/qml/qml/qqmlpropertycache.cpp
index 8ffdc42d82..a225f94a3f 100644
--- a/src/qml/qml/qqmlpropertycache.cpp
+++ b/src/qml/qml/qqmlpropertycache.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qqmlpropertycache_p.h"
@@ -46,13 +10,14 @@
#include <private/qmetaobject_p.h>
#include <private/qmetaobjectbuilder_p.h>
#include <private/qqmlpropertycachemethodarguments_p.h>
+#include <private/qqmlsignalnames_p.h>
#include <private/qv4value_p.h>
#include <QtCore/qdebug.h>
#include <QtCore/QCryptographicHash>
+#include <QtCore/private/qtools_p.h>
-#include <ctype.h> // for toupper
#include <limits.h>
#include <algorithm>
@@ -89,19 +54,13 @@ QQmlPropertyData::flagsForProperty(const QMetaProperty &p)
const QMetaType metaType = p.metaType();
int propType = metaType.id();
if (p.isEnumType()) {
- flags.type = QQmlPropertyData::Flags::EnumType;
+ flags.setType(QQmlPropertyData::Flags::EnumType);
} else if (metaType.flags() & QMetaType::PointerToQObject) {
- flags.type = QQmlPropertyData::Flags::QObjectDerivedType;
+ flags.setType(QQmlPropertyData::Flags::QObjectDerivedType);
} else if (propType == QMetaType::QVariant) {
- flags.type = QQmlPropertyData::Flags::QVariantType;
- } else if (propType < static_cast<int>(QMetaType::User)) {
- // nothing to do
- } else if (propType == qMetaTypeId<QQmlBinding *>()) {
- flags.type = QQmlPropertyData::Flags::QmlBindingType;
- } else if (propType == qMetaTypeId<QJSValue>()) {
- flags.type = QQmlPropertyData::Flags::QJSValueType;
+ flags.setType(QQmlPropertyData::Flags::QVariantType);
} else if (metaType.flags() & QMetaType::IsQmlList) {
- flags.type = QQmlPropertyData::Flags::QListType;
+ flags.setType(QQmlPropertyData::Flags::QListType);
}
return flags;
@@ -121,51 +80,67 @@ void QQmlPropertyData::load(const QMetaProperty &p)
void QQmlPropertyData::load(const QMetaMethod &m)
{
setCoreIndex(m.methodIndex());
- setArguments(nullptr);
+ m_flags.setType(Flags::FunctionType);
- setPropType(m.returnMetaType());
+ // We need to set the constructor, signal, constant, arguments, V4Function, cloned flags.
+ // These are specific to methods and change with each method.
+ // The same QQmlPropertyData may be loaded with multiple methods in sequence.
- m_flags.type = Flags::FunctionType;
- if (m.methodType() == QMetaMethod::Signal) {
+ switch (m.methodType()) {
+ case QMetaMethod::Signal:
m_flags.setIsSignal(true);
- } else if (m.methodType() == QMetaMethod::Constructor) {
+ m_flags.setIsConstructor(false);
+ setPropType(m.returnMetaType());
+ break;
+ case QMetaMethod::Constructor:
+ m_flags.setIsSignal(false);
m_flags.setIsConstructor(true);
setPropType(QMetaType::fromType<QObject *>());
+ break;
+ default:
+ m_flags.setIsSignal(false);
+ m_flags.setIsConstructor(false);
+ setPropType(m.returnMetaType());
+ break;
}
+ m_flags.setIsConstant(m.isConst());
+
const int paramCount = m.parameterCount();
if (paramCount) {
m_flags.setHasArguments(true);
- if ((paramCount == 1) && (m.parameterTypes().constFirst() == "QQmlV4Function*"))
- m_flags.setIsV4Function(true);
+ m_flags.setIsV4Function(
+ paramCount == 1 &&
+ m.parameterMetaType(0) == QMetaType::fromType<QQmlV4FunctionPtr>());
+ } else {
+ m_flags.setHasArguments(false);
+ m_flags.setIsV4Function(false);
}
- if (m.attributes() & QMetaMethod::Cloned)
- m_flags.setIsCloned(true);
+ m_flags.setIsCloned(m.attributes() & QMetaMethod::Cloned);
Q_ASSERT(m.revision() <= std::numeric_limits<quint16>::max());
setRevision(QTypeRevision::fromEncodedVersion(m.revision()));
}
/*!
-Creates a new empty QQmlPropertyCache.
+ Creates a standalone QQmlPropertyCache of \a metaObject. It is separate from the usual
+ QQmlPropertyCache hierarchy. It's parent is not equal to any other QQmlPropertyCache
+ created from QObject::staticMetaObject, for example.
*/
-QQmlPropertyCache::QQmlPropertyCache()
- : propertyIndexCacheStart(0), _parent(nullptr),
- argumentsCache(nullptr), methodIndexCacheStart(0), signalHandlerIndexCacheStart(0),
- _jsFactoryMethodIndex(-1), _hasPropertyOverrides(false)
-{
-}
-
-/*!
-Creates a new QQmlPropertyCache of \a metaObject.
-*/
-QQmlPropertyCache::QQmlPropertyCache(const QMetaObject *metaObject, QTypeRevision metaObjectRevision)
- : QQmlPropertyCache()
+QQmlPropertyCache::Ptr QQmlPropertyCache::createStandalone(
+ const QMetaObject *metaObject, QTypeRevision metaObjectRevision)
{
Q_ASSERT(metaObject);
- update(metaObject);
+ Ptr result;
+ if (const QMetaObject *super = metaObject->superClass()) {
+ result = createStandalone(
+ super, metaObjectRevision)->copyAndAppend(metaObject, metaObjectRevision);
+ } else {
+ result.adopt(new QQmlPropertyCache(metaObject));
+ result->update(metaObject);
+ }
if (metaObjectRevision.isValid() && metaObjectRevision != QTypeRevision::zero()) {
// Set the revision of the meta object that this cache describes to be
@@ -173,9 +148,13 @@ QQmlPropertyCache::QQmlPropertyCache(const QMetaObject *metaObject, QTypeRevisio
// from a type that was created directly in C++, and not through QML. For such
// types, the revision for each recorded QMetaObject would normally be zero, which
// would exclude any revisioned properties.
- for (int metaObjectOffset = 0; metaObjectOffset < allowedRevisionCache.size(); ++metaObjectOffset)
- allowedRevisionCache[metaObjectOffset] = metaObjectRevision;
+ for (int metaObjectOffset = 0; metaObjectOffset < result->allowedRevisionCache.size();
+ ++metaObjectOffset) {
+ result->allowedRevisionCache[metaObjectOffset] = metaObjectRevision;
+ }
}
+
+ return result;
}
QQmlPropertyCache::~QQmlPropertyCache()
@@ -191,42 +170,38 @@ QQmlPropertyCache::~QQmlPropertyCache()
// We must clear this prior to releasing the parent incase it is a
// linked hash
stringCache.clear();
- if (_parent) _parent->release();
-
- _parent = nullptr;
}
-QQmlPropertyCache *QQmlPropertyCache::copy(int reserve)
+QQmlPropertyCache::Ptr QQmlPropertyCache::copy(const QQmlMetaObjectPointer &mo, int reserve) const
{
- QQmlPropertyCache *cache = new QQmlPropertyCache();
- cache->_parent = this;
- cache->_parent->addref();
- cache->propertyIndexCacheStart = propertyIndexCache.count() + propertyIndexCacheStart;
- cache->methodIndexCacheStart = methodIndexCache.count() + methodIndexCacheStart;
- cache->signalHandlerIndexCacheStart = signalHandlerIndexCache.count() + signalHandlerIndexCacheStart;
+ QQmlPropertyCache::Ptr cache = QQmlPropertyCache::Ptr(
+ new QQmlPropertyCache(mo), QQmlPropertyCache::Ptr::Adopt);
+ cache->_parent.reset(this);
+ cache->propertyIndexCacheStart = propertyIndexCache.size() + propertyIndexCacheStart;
+ cache->methodIndexCacheStart = methodIndexCache.size() + methodIndexCacheStart;
+ cache->signalHandlerIndexCacheStart = signalHandlerIndexCache.size() + signalHandlerIndexCacheStart;
cache->stringCache.linkAndReserve(stringCache, reserve);
cache->allowedRevisionCache = allowedRevisionCache;
- cache->_metaObject = _metaObject;
cache->_defaultPropertyName = _defaultPropertyName;
+ cache->_listPropertyAssignBehavior = _listPropertyAssignBehavior;
return cache;
}
-QQmlPropertyCache *QQmlPropertyCache::copy()
+QQmlPropertyCache::Ptr QQmlPropertyCache::copy() const
{
- return copy(0);
+ return copy(_metaObject, 0);
}
-QQmlPropertyCache *QQmlPropertyCache::copyAndReserve(int propertyCount, int methodCount,
- int signalCount, int enumCount)
+QQmlPropertyCache::Ptr QQmlPropertyCache::copyAndReserve(
+ int propertyCount, int methodCount, int signalCount, int enumCount) const
{
- QQmlPropertyCache *rv = copy(propertyCount + methodCount + signalCount);
+ QQmlPropertyCache::Ptr rv = copy(
+ QQmlMetaObjectPointer(), propertyCount + methodCount + signalCount);
rv->propertyIndexCache.reserve(propertyCount);
rv->methodIndexCache.reserve(methodCount);
rv->signalHandlerIndexCache.reserve(signalCount);
rv->enumCache.reserve(enumCount);
- rv->_metaObject = RefCountedMetaObject();
-
return rv;
}
@@ -246,18 +221,18 @@ void QQmlPropertyCache::appendProperty(const QString &name, QQmlPropertyData::Fl
data.setFlags(flags);
data.setTypeVersion(version);
- QQmlPropertyData *old = findNamedProperty(name);
- if (old)
- data.markAsOverrideOf(old);
+ const OverrideResult overrideResult = handleOverride(name, &data);
+ if (overrideResult == InvalidOverride)
+ return;
- int index = propertyIndexCache.count();
+ int index = propertyIndexCache.size();
propertyIndexCache.append(data);
- setNamedProperty(name, index + propertyOffset(), propertyIndexCache.data() + index, (old != nullptr));
+ setNamedProperty(name, index + propertyOffset(), propertyIndexCache.data() + index);
}
void QQmlPropertyCache::appendSignal(const QString &name, QQmlPropertyData::Flags flags,
- int coreIndex, const int *types,
+ int coreIndex, const QMetaType *types,
const QList<QByteArray> &names)
{
QQmlPropertyData data;
@@ -270,56 +245,55 @@ void QQmlPropertyCache::appendSignal(const QString &name, QQmlPropertyData::Flag
handler.m_flags.setIsSignalHandler(true);
if (types) {
- int argumentCount = *types;
+ const auto argumentCount = names.size();
QQmlPropertyCacheMethodArguments *args = createArgumentsObject(argumentCount, names);
- ::memcpy(args->arguments, types, (argumentCount + 1) * sizeof(int));
- args->argumentsValid = true;
+ new (args->types) QMetaType; // Invalid return type
+ ::memcpy(args->types + 1, types, argumentCount * sizeof(QMetaType));
data.setArguments(args);
}
- QQmlPropertyData *old = findNamedProperty(name);
- if (old)
- data.markAsOverrideOf(old);
+ const OverrideResult overrideResult = handleOverride(name, &data);
+ if (overrideResult == InvalidOverride)
+ return;
- int methodIndex = methodIndexCache.count();
+ int methodIndex = methodIndexCache.size();
methodIndexCache.append(data);
- int signalHandlerIndex = signalHandlerIndexCache.count();
+ int signalHandlerIndex = signalHandlerIndexCache.size();
signalHandlerIndexCache.append(handler);
- QString handlerName = QLatin1String("on") + name;
- handlerName[2] = handlerName.at(2).toUpper();
+ const QString handlerName = QQmlSignalNames::signalNameToHandlerName(name);
- setNamedProperty(name, methodIndex + methodOffset(), methodIndexCache.data() + methodIndex, (old != nullptr));
- setNamedProperty(handlerName, signalHandlerIndex + signalOffset(), signalHandlerIndexCache.data() + signalHandlerIndex, (old != nullptr));
+ setNamedProperty(name, methodIndex + methodOffset(), methodIndexCache.data() + methodIndex);
+ setNamedProperty(handlerName, signalHandlerIndex + signalOffset(),
+ signalHandlerIndexCache.data() + signalHandlerIndex);
}
void QQmlPropertyCache::appendMethod(const QString &name, QQmlPropertyData::Flags flags,
- int coreIndex, int returnType, const QList<QByteArray> &names,
- const QVector<int> &parameterTypes)
+ int coreIndex, QMetaType returnType,
+ const QList<QByteArray> &names,
+ const QVector<QMetaType> &parameterTypes)
{
- int argumentCount = names.count();
+ int argumentCount = names.size();
QQmlPropertyData data;
- data.setPropType(QMetaType(returnType));
+ data.setPropType(returnType);
data.setCoreIndex(coreIndex);
+ data.setFlags(flags);
+ const OverrideResult overrideResult = handleOverride(name, &data);
+ if (overrideResult == InvalidOverride)
+ return;
QQmlPropertyCacheMethodArguments *args = createArgumentsObject(argumentCount, names);
+ new (args->types) QMetaType(returnType);
for (int ii = 0; ii < argumentCount; ++ii)
- args->arguments[ii + 1] = parameterTypes.at(ii);
- args->argumentsValid = true;
+ new (args->types + ii + 1) QMetaType(parameterTypes.at(ii));
data.setArguments(args);
- data.setFlags(flags);
-
- QQmlPropertyData *old = findNamedProperty(name);
- if (old)
- data.markAsOverrideOf(old);
-
- int methodIndex = methodIndexCache.count();
+ int methodIndex = methodIndexCache.size();
methodIndexCache.append(data);
- setNamedProperty(name, methodIndex + methodOffset(), methodIndexCache.data() + methodIndex, (old != nullptr));
+ setNamedProperty(name, methodIndex + methodOffset(), methodIndexCache.data() + methodIndex);
}
void QQmlPropertyCache::appendEnum(const QString &name, const QVector<QQmlEnumValue> &values)
@@ -331,77 +305,83 @@ void QQmlPropertyCache::appendEnum(const QString &name, const QVector<QQmlEnumVa
}
// Returns this property cache's metaObject, creating it if necessary.
-const QMetaObject *QQmlPropertyCache::createMetaObject()
+const QMetaObject *QQmlPropertyCache::createMetaObject() const
{
- if (!_metaObject) {
+ if (_metaObject.isNull()) {
QMetaObjectBuilder builder;
toMetaObjectBuilder(builder);
builder.setSuperClass(_parent->createMetaObject());
- _metaObject = RefCountedMetaObject(builder.toMetaObject(), RefCountedMetaObject::SharedMetaObject);
+ _metaObject.setSharedOnce(builder.toMetaObject());
}
- return _metaObject;
+ return _metaObject.metaObject();
}
-QQmlPropertyData *QQmlPropertyCache::maybeUnresolvedProperty(int index) const
+const QQmlPropertyData *QQmlPropertyCache::maybeUnresolvedProperty(int index) const
{
- if (index < 0 || index >= (propertyIndexCacheStart + propertyIndexCache.count()))
+ if (index < 0 || index >= propertyCount())
return nullptr;
- QQmlPropertyData *rv = nullptr;
+ const QQmlPropertyData *rv = nullptr;
if (index < propertyIndexCacheStart)
return _parent->maybeUnresolvedProperty(index);
else
- rv = const_cast<QQmlPropertyData *>(&propertyIndexCache.at(index - propertyIndexCacheStart));
+ rv = const_cast<const QQmlPropertyData *>(&propertyIndexCache.at(index - propertyIndexCacheStart));
return rv;
}
-QQmlPropertyData *QQmlPropertyCache::defaultProperty() const
+const QQmlPropertyData *QQmlPropertyCache::defaultProperty() const
{
return property(defaultPropertyName(), nullptr, nullptr);
}
-void QQmlPropertyCache::setParent(QQmlPropertyCache *newParent)
+void QQmlPropertyCache::setParent(QQmlPropertyCache::ConstPtr newParent)
{
- if (_parent == newParent)
- return;
- if (_parent)
- _parent->release();
- _parent = newParent;
- _parent->addref();
+ if (_parent != newParent)
+ _parent = std::move(newParent);
}
-QQmlPropertyCache *
+QQmlPropertyCache::Ptr
QQmlPropertyCache::copyAndAppend(const QMetaObject *metaObject,
QTypeRevision typeVersion,
QQmlPropertyData::Flags propertyFlags,
QQmlPropertyData::Flags methodFlags,
- QQmlPropertyData::Flags signalFlags)
+ QQmlPropertyData::Flags signalFlags) const
{
Q_ASSERT(QMetaObjectPrivate::get(metaObject)->revision >= 4);
// Reserve enough space in the name hash for all the methods (including signals), all the
// signal handlers and all the properties. This assumes no name clashes, but this is the
// common case.
- QQmlPropertyCache *rv = copy(QMetaObjectPrivate::get(metaObject)->methodCount +
- QMetaObjectPrivate::get(metaObject)->signalCount +
- QMetaObjectPrivate::get(metaObject)->propertyCount);
+ QQmlPropertyCache::Ptr rv = copy(
+ metaObject,
+ QMetaObjectPrivate::get(metaObject)->methodCount
+ + QMetaObjectPrivate::get(metaObject)->signalCount
+ + QMetaObjectPrivate::get(metaObject)->propertyCount);
rv->append(metaObject, typeVersion, propertyFlags, methodFlags, signalFlags);
return rv;
}
+static QHashedString signalNameToHandlerName(const QHashedString &methodName)
+{
+ return QQmlSignalNames::signalNameToHandlerName(methodName);
+}
+
+static QHashedString signalNameToHandlerName(const QHashedCStringRef &methodName)
+{
+ return QQmlSignalNames::signalNameToHandlerName(
+ QLatin1StringView{ methodName.constData(), methodName.length() });
+}
+
+
void QQmlPropertyCache::append(const QMetaObject *metaObject,
QTypeRevision typeVersion,
QQmlPropertyData::Flags propertyFlags,
QQmlPropertyData::Flags methodFlags,
QQmlPropertyData::Flags signalFlags)
{
- _metaObject = RefCountedMetaObject(metaObject, RefCountedMetaObject::StaticMetaObject);
-
- bool dynamicMetaObject = isDynamicMetaObject(metaObject);
-
allowedRevisionCache.append(QTypeRevision::zero());
int methodCount = metaObject->methodCount();
@@ -422,6 +402,8 @@ void QQmlPropertyCache::append(const QMetaObject *metaObject,
_jsFactoryMethodIndex = metaObject->indexOfSlot(factoryMethod);
if (_jsFactoryMethodIndex != -1)
_jsFactoryMethodIndex -= metaObject->methodOffset();
+ } else if (0 == qstrcmp(name, "QML.ListPropertyAssignBehavior")) {
+ _listPropertyAssignBehavior = mci.value();
}
}
}
@@ -470,10 +452,9 @@ void QQmlPropertyCache::append(const QMetaObject *metaObject,
data->setFlags(methodFlags);
data->load(m);
- data->m_flags.setIsDirect(!dynamicMetaObject);
- Q_ASSERT((allowedRevisionCache.count() - 1) < Q_INT16_MAX);
- data->setMetaObjectOffset(allowedRevisionCache.count() - 1);
+ Q_ASSERT((allowedRevisionCache.size() - 1) < Q_INT16_MAX);
+ data->setMetaObjectOffset(allowedRevisionCache.size() - 1);
if (data->isSignal()) {
sigdata = &signalHandlerIndexCache[signalHandlerIndex - signalHandlerIndexCacheStart];
@@ -483,47 +464,29 @@ void QQmlPropertyCache::append(const QMetaObject *metaObject,
QQmlPropertyData *old = nullptr;
- if (utf8) {
- QHashedString methodName(QString::fromUtf8(rawName, cptr - rawName));
- if (StringCache::mapped_type *it = stringCache.value(methodName))
- old = it->second;
- setNamedProperty(methodName, ii, data, (old != nullptr));
-
- if (data->isSignal()) {
- QHashedString on(QLatin1String("on") % methodName.at(0).toUpper() % QStringView{methodName}.mid(1));
- setNamedProperty(on, ii, sigdata, (old != nullptr));
- ++signalHandlerIndex;
+ const auto doSetNamedProperty = [&](const auto &methodName) {
+ if (StringCache::mapped_type *it = stringCache.value(methodName)) {
+ if (handleOverride(methodName, data, (old = it->second)) == InvalidOverride)
+ return;
}
- } else {
- QHashedCStringRef methodName(rawName, cptr - rawName);
- if (StringCache::mapped_type *it = stringCache.value(methodName))
- old = it->second;
- setNamedProperty(methodName, ii, data, (old != nullptr));
+
+ setNamedProperty(methodName, ii, data);
if (data->isSignal()) {
- int length = methodName.length();
-
- QVarLengthArray<char, 128> str(length+3);
- str[0] = 'o';
- str[1] = 'n';
- str[2] = toupper(rawName[0]);
- if (length > 1)
- memcpy(&str[3], &rawName[1], length - 1);
- str[length + 2] = '\0';
-
- QHashedString on(QString::fromLatin1(str.data()));
- setNamedProperty(on, ii, data, (old != nullptr));
+
+ // TODO: Remove this once we can. Signals should not be overridable.
+ if (!utf8)
+ data->m_flags.setIsOverridableSignal(true);
+
+ setNamedProperty(signalNameToHandlerName(methodName), ii, sigdata);
++signalHandlerIndex;
}
- }
-
- if (old) {
- // We only overload methods in the same class, exactly like C++
- if (old->isFunction() && old->coreIndex() >= methodOffset)
- data->m_flags.setIsOverload(true);
+ };
- data->markAsOverrideOf(old);
- }
+ if (utf8)
+ doSetNamedProperty(QHashedString(QString::fromUtf8(rawName, cptr - rawName)));
+ else
+ doSetNamedProperty(QHashedCStringRef(rawName, cptr - rawName));
}
int propCount = metaObject->propertyCount();
@@ -551,23 +514,25 @@ void QQmlPropertyCache::append(const QMetaObject *metaObject,
data->load(p);
data->setTypeVersion(typeVersion);
- data->m_flags.setIsDirect(!dynamicMetaObject);
-
- Q_ASSERT((allowedRevisionCache.count() - 1) < Q_INT16_MAX);
- data->setMetaObjectOffset(allowedRevisionCache.count() - 1);
+ Q_ASSERT((allowedRevisionCache.size() - 1) < Q_INT16_MAX);
+ data->setMetaObjectOffset(allowedRevisionCache.size() - 1);
QQmlPropertyData *old = nullptr;
if (utf8) {
QHashedString propName(QString::fromUtf8(str, cptr - str));
- if (StringCache::mapped_type *it = stringCache.value(propName))
- old = it->second;
- setNamedProperty(propName, ii, data, (old != nullptr));
+ if (StringCache::mapped_type *it = stringCache.value(propName)) {
+ if (handleOverride(propName, data, (old = it->second)) == InvalidOverride)
+ continue;
+ }
+ setNamedProperty(propName, ii, data);
} else {
QHashedCStringRef propName(str, cptr - str);
- if (StringCache::mapped_type *it = stringCache.value(propName))
- old = it->second;
- setNamedProperty(propName, ii, data, (old != nullptr));
+ if (StringCache::mapped_type *it = stringCache.value(propName)) {
+ if (handleOverride(propName, data, (old = it->second)) == InvalidOverride)
+ continue;
+ }
+ setNamedProperty(propName, ii, data);
}
bool isGadget = true;
@@ -576,25 +541,12 @@ void QQmlPropertyCache::append(const QMetaObject *metaObject,
isGadget = false;
}
- if (isGadget) // always dispatch over a 'normal' meta-call so the QQmlValueType can intercept
- data->m_flags.setIsDirect(false);
- else
+ // otherwise always dispatch over a 'normal' meta-call so the QQmlValueType can intercept
+ if (!isGadget)
data->trySetStaticMetaCallFunction(metaObject->d.static_metacall, ii - propOffset);
- if (old)
- data->markAsOverrideOf(old);
}
}
-void QQmlPropertyCache::updateRecur(const QMetaObject *metaObject)
-{
- if (!metaObject)
- return;
-
- updateRecur(metaObject->superClass());
-
- append(metaObject, QTypeRevision());
-}
-
void QQmlPropertyCache::update(const QMetaObject *metaObject)
{
Q_ASSERT(metaObject);
@@ -614,7 +566,8 @@ void QQmlPropertyCache::update(const QMetaObject *metaObject)
// cached in a parent cache.
stringCache.reserve(pc + mc + sc);
- updateRecur(metaObject);
+ if (metaObject)
+ append(metaObject, QTypeRevision());
}
/*! \internal
@@ -627,7 +580,6 @@ void QQmlPropertyCache::invalidate(const QMetaObject *metaObject)
methodIndexCache.clear();
signalHandlerIndexCache.clear();
- _hasPropertyOverrides = false;
argumentsCache = nullptr;
int pc = metaObject->propertyCount();
@@ -636,9 +588,9 @@ void QQmlPropertyCache::invalidate(const QMetaObject *metaObject)
int reserve = pc + mc + sc;
if (parent()) {
- propertyIndexCacheStart = parent()->propertyIndexCache.count() + parent()->propertyIndexCacheStart;
- methodIndexCacheStart = parent()->methodIndexCache.count() + parent()->methodIndexCacheStart;
- signalHandlerIndexCacheStart = parent()->signalHandlerIndexCache.count() + parent()->signalHandlerIndexCacheStart;
+ propertyIndexCacheStart = parent()->propertyIndexCache.size() + parent()->propertyIndexCacheStart;
+ methodIndexCacheStart = parent()->methodIndexCache.size() + parent()->methodIndexCacheStart;
+ signalHandlerIndexCacheStart = parent()->signalHandlerIndexCache.size() + parent()->signalHandlerIndexCacheStart;
stringCache.linkAndReserve(parent()->stringCache, reserve);
append(metaObject, QTypeRevision());
} else {
@@ -649,7 +601,7 @@ void QQmlPropertyCache::invalidate(const QMetaObject *metaObject)
}
}
-QQmlPropertyData *QQmlPropertyCache::findProperty(
+const QQmlPropertyData *QQmlPropertyCache::findProperty(
StringCache::ConstIterator it, QObject *object,
const QQmlRefPointer<QQmlContextData> &context) const
{
@@ -668,10 +620,11 @@ inline bool contextHasNoExtensions(const QQmlRefPointer<QQmlContextData> &contex
{
// This context has no extension if its parent is the engine's rootContext,
// which has children but no imports
- return (!context->parent() || !context->parent()->imports());
+ const QQmlRefPointer<QQmlContextData> parent = context->parent();
+ return (!parent || !parent->imports());
}
-inline int maximumIndexForProperty(QQmlPropertyData *prop, const int methodCount, const int signalCount, const int propertyCount)
+inline int maximumIndexForProperty(const QQmlPropertyData *prop, const int methodCount, const int signalCount, const int propertyCount)
{
return prop->isFunction() ? methodCount
: prop->isSignalHandler() ? signalCount
@@ -680,14 +633,14 @@ inline int maximumIndexForProperty(QQmlPropertyData *prop, const int methodCount
}
-QQmlPropertyData *QQmlPropertyCache::findProperty(
+const QQmlPropertyData *QQmlPropertyCache::findProperty(
StringCache::ConstIterator it, const QQmlVMEMetaObject *vmemo,
const QQmlRefPointer<QQmlContextData> &context) const
{
StringCache::ConstIterator end = stringCache.end();
if (it != end) {
- QQmlPropertyData *result = it.value().second;
+ const QQmlPropertyData *result = it.value().second;
// If there exists a typed property (not a function or signal handler), of the
// right name available to the specified context, we need to return that
@@ -757,21 +710,24 @@ QString QQmlPropertyData::name(const QMetaObject *metaObject) const
}
}
-void QQmlPropertyData::markAsOverrideOf(QQmlPropertyData *predecessor)
+bool QQmlPropertyData::markAsOverrideOf(QQmlPropertyData *predecessor)
{
+ Q_ASSERT(predecessor != this);
+ if (predecessor->isFinal())
+ return false;
+
setOverrideIndexIsProperty(!predecessor->isFunction());
setOverrideIndex(predecessor->coreIndex());
-
predecessor->m_flags.setIsOverridden(true);
+ Q_ASSERT(predecessor->isOverridden());
+ return true;
}
-QQmlPropertyCacheMethodArguments *QQmlPropertyCache::createArgumentsObject(int argc, const QList<QByteArray> &names)
+QQmlPropertyCacheMethodArguments *QQmlPropertyCache::createArgumentsObject(
+ int argc, const QList<QByteArray> &names)
{
typedef QQmlPropertyCacheMethodArguments A;
- A *args = static_cast<A *>(malloc(sizeof(A) + (argc) * sizeof(int)));
- args->arguments[0] = argc;
- args->argumentsValid = false;
- args->parameterError = false;
+ A *args = static_cast<A *>(malloc(sizeof(A) + argc * sizeof(QMetaType)));
args->names = argc ? new QList<QByteArray>(names) : nullptr;
args->next = argumentsCache;
argumentsCache = args;
@@ -784,13 +740,17 @@ QString QQmlPropertyCache::signalParameterStringForJS(QV4::ExecutionEngine *engi
const QSet<QString> &illegalNames = engine->illegalNames();
QString parameters;
- for (int i = 0; i < parameterNameList.count(); ++i) {
+ const qsizetype count = parameterNameList.size();
+ if (count > std::numeric_limits<quint16>::max())
+ *errorString = QCoreApplication::translate("QQmlRewrite", "Signal has an excessive number of parameters: %1").arg(count);
+
+ for (qsizetype i = 0; i < count; ++i) {
if (i > 0)
parameters += QLatin1Char(',');
const QByteArray &param = parameterNameList.at(i);
- if (param.isEmpty())
+ if (param.isEmpty()) {
unnamedParameter = true;
- else if (unnamedParameter) {
+ } else if (unnamedParameter) {
if (errorString)
*errorString = QCoreApplication::translate("QQmlRewrite", "Signal uses unnamed parameter followed by named parameter.");
return QString();
@@ -805,7 +765,7 @@ QString QQmlPropertyCache::signalParameterStringForJS(QV4::ExecutionEngine *engi
return parameters;
}
-int QQmlPropertyCache::originalClone(int index)
+int QQmlPropertyCache::originalClone(int index) const
{
while (signal(index)->isCloned())
--index;
@@ -814,10 +774,10 @@ int QQmlPropertyCache::originalClone(int index)
int QQmlPropertyCache::originalClone(const QObject *object, int index)
{
- QQmlData *data = QQmlData::get(object, false);
+ QQmlData *data = QQmlData::get(object);
if (data && data->propertyCache) {
- QQmlPropertyCache *cache = data->propertyCache;
- QQmlPropertyData *sig = cache->signal(index);
+ const QQmlPropertyCache *cache = data->propertyCache.data();
+ const QQmlPropertyData *sig = cache->signal(index);
while (sig && sig->isCloned()) {
--index;
sig = cache->signal(index);
@@ -904,27 +864,23 @@ static inline QByteArray qQmlPropertyCacheToString(const QV4::String *string)
}
template<typename T>
-QQmlPropertyData *
-qQmlPropertyCacheProperty(QJSEngine *engine, QObject *obj, T name,
- const QQmlRefPointer<QQmlContextData> &context, QQmlPropertyData *local)
+const QQmlPropertyData *
+qQmlPropertyCacheProperty(QObject *obj, T name, const QQmlRefPointer<QQmlContextData> &context,
+ QQmlPropertyData *local)
{
- QQmlPropertyCache *cache = nullptr;
+ const QQmlPropertyCache *cache = nullptr;
QQmlData *ddata = QQmlData::get(obj, false);
if (ddata && ddata->propertyCache) {
- cache = ddata->propertyCache;
- } else if (engine) {
- QJSEnginePrivate *ep = QJSEnginePrivate::get(engine);
- cache = ep->cache(obj);
- if (cache) {
- ddata = QQmlData::get(obj, true);
- cache->addref();
- ddata->propertyCache = cache;
- }
+ cache = ddata->propertyCache.data();
+ } else if (auto newCache = QQmlMetaType::propertyCache(obj)) {
+ cache = newCache.data();
+ ddata = QQmlData::get(obj, true);
+ ddata->propertyCache = std::move(newCache);
}
- QQmlPropertyData *rv = nullptr;
+ const QQmlPropertyData *rv = nullptr;
if (cache) {
rv = cache->property(name, obj, context);
@@ -937,31 +893,28 @@ qQmlPropertyCacheProperty(QJSEngine *engine, QObject *obj, T name,
return rv;
}
-QQmlPropertyData *
-QQmlPropertyCache::property(QJSEngine *engine, QObject *obj, const QV4::String *name,
- const QQmlRefPointer<QQmlContextData> &context, QQmlPropertyData *local)
+const QQmlPropertyData *QQmlPropertyCache::property(
+ QObject *obj, const QV4::String *name, const QQmlRefPointer<QQmlContextData> &context,
+ QQmlPropertyData *local)
{
- return qQmlPropertyCacheProperty<const QV4::String *>(engine, obj, name, context, local);
+ return qQmlPropertyCacheProperty<const QV4::String *>(obj, name, context, local);
}
-QQmlPropertyData *
-QQmlPropertyCache::property(QJSEngine *engine, QObject *obj, QStringView name,
- const QQmlRefPointer<QQmlContextData> &context, QQmlPropertyData *local)
+const QQmlPropertyData *QQmlPropertyCache::property(
+ QObject *obj, QStringView name, const QQmlRefPointer<QQmlContextData> &context,
+ QQmlPropertyData *local)
{
- return qQmlPropertyCacheProperty<const QStringView &>(engine, obj, name, context, local);
+ return qQmlPropertyCacheProperty<const QStringView &>(obj, name, context, local);
}
-QQmlPropertyData *
-QQmlPropertyCache::property(QJSEngine *engine, QObject *obj, const QLatin1String &name,
- const QQmlRefPointer<QQmlContextData> &context, QQmlPropertyData *local)
+const QQmlPropertyData *QQmlPropertyCache::property(
+ QObject *obj, const QLatin1String &name, const QQmlRefPointer<QQmlContextData> &context,
+ QQmlPropertyData *local)
{
- return qQmlPropertyCacheProperty<const QLatin1String &>(engine, obj, name, context, local);
+ return qQmlPropertyCacheProperty<const QLatin1String &>(obj, name, context, local);
}
-// these two functions are copied from qmetaobject.cpp
-static inline const QMetaObjectPrivate *priv(const uint* data)
-{ return reinterpret_cast<const QMetaObjectPrivate*>(data); }
-
+// this function is copied from qmetaobject.cpp
static inline const QByteArray stringData(const QMetaObject *mo, int index)
{
uint offset = mo->d.stringdata[2*index];
@@ -970,30 +923,25 @@ static inline const QByteArray stringData(const QMetaObject *mo, int index)
return QByteArray::fromRawData(string, length);
}
-bool QQmlPropertyCache::isDynamicMetaObject(const QMetaObject *mo)
-{
- return priv(mo->d.data)->flags & DynamicMetaObject;
-}
-
const char *QQmlPropertyCache::className() const
{
- if (_metaObject)
- return _metaObject->className();
+ if (const QMetaObject *mo = _metaObject.metaObject())
+ return mo->className();
else
return _dynamicClassName.constData();
}
-void QQmlPropertyCache::toMetaObjectBuilder(QMetaObjectBuilder &builder)
+void QQmlPropertyCache::toMetaObjectBuilder(QMetaObjectBuilder &builder) const
{
- struct Sort { static bool lt(const QPair<QString, QQmlPropertyData *> &lhs,
- const QPair<QString, QQmlPropertyData *> &rhs) {
+ struct Sort { static bool lt(const QPair<QString, const QQmlPropertyData *> &lhs,
+ const QPair<QString, const QQmlPropertyData *> &rhs) {
return lhs.second->coreIndex() < rhs.second->coreIndex();
} };
- struct Insert { static void in(QQmlPropertyCache *This,
- QList<QPair<QString, QQmlPropertyData *> > &properties,
- QList<QPair<QString, QQmlPropertyData *> > &methods,
- StringCache::ConstIterator iter, QQmlPropertyData *data) {
+ struct Insert { static void in(const QQmlPropertyCache *This,
+ QList<QPair<QString, const QQmlPropertyData *> > &properties,
+ QList<QPair<QString, const QQmlPropertyData *> > &methods,
+ StringCache::ConstIterator iter, const QQmlPropertyData *data) {
if (data->isSignalHandler())
return;
@@ -1001,7 +949,7 @@ void QQmlPropertyCache::toMetaObjectBuilder(QMetaObjectBuilder &builder)
if (data->coreIndex() < This->methodIndexCacheStart)
return;
- QPair<QString, QQmlPropertyData *> entry = qMakePair((QString)iter.key(), data);
+ QPair<QString, const QQmlPropertyData *> entry = qMakePair((QString)iter.key(), data);
// Overrides can cause the entry to already exist
if (!methods.contains(entry)) methods.append(entry);
@@ -1011,7 +959,7 @@ void QQmlPropertyCache::toMetaObjectBuilder(QMetaObjectBuilder &builder)
if (data->coreIndex() < This->propertyIndexCacheStart)
return;
- QPair<QString, QQmlPropertyData *> entry = qMakePair((QString)iter.key(), data);
+ QPair<QString, const QQmlPropertyData *> entry = qMakePair((QString)iter.key(), data);
// Overrides can cause the entry to already exist
if (!properties.contains(entry)) properties.append(entry);
@@ -1023,20 +971,20 @@ void QQmlPropertyCache::toMetaObjectBuilder(QMetaObjectBuilder &builder)
builder.setClassName(_dynamicClassName);
- QList<QPair<QString, QQmlPropertyData *> > properties;
- QList<QPair<QString, QQmlPropertyData *> > methods;
+ QList<QPair<QString, const QQmlPropertyData *> > properties;
+ QList<QPair<QString, const QQmlPropertyData *> > methods;
for (StringCache::ConstIterator iter = stringCache.begin(), cend = stringCache.end(); iter != cend; ++iter)
Insert::in(this, properties, methods, iter, iter.value().second);
- Q_ASSERT(properties.count() == propertyIndexCache.count());
- Q_ASSERT(methods.count() == methodIndexCache.count());
+ Q_ASSERT(properties.size() == propertyIndexCache.size());
+ Q_ASSERT(methods.size() == methodIndexCache.size());
std::sort(properties.begin(), properties.end(), Sort::lt);
std::sort(methods.begin(), methods.end(), Sort::lt);
- for (int ii = 0; ii < properties.count(); ++ii) {
- QQmlPropertyData *data = properties.at(ii).second;
+ for (int ii = 0; ii < properties.size(); ++ii) {
+ const QQmlPropertyData *data = properties.at(ii).second;
int notifierId = -1;
if (data->notifyIndex() != -1)
@@ -1051,10 +999,11 @@ void QQmlPropertyCache::toMetaObjectBuilder(QMetaObjectBuilder &builder)
property.setWritable(data->isWritable());
property.setResettable(data->isResettable());
property.setBindable(data->isBindable());
+ property.setAlias(data->isAlias());
}
- for (int ii = 0; ii < methods.count(); ++ii) {
- QQmlPropertyData *data = methods.at(ii).second;
+ for (int ii = 0; ii < methods.size(); ++ii) {
+ const QQmlPropertyData *data = methods.at(ii).second;
QByteArray returnType;
if (data->propType().isValid())
@@ -1066,11 +1015,12 @@ void QQmlPropertyCache::toMetaObjectBuilder(QMetaObjectBuilder &builder)
QQmlPropertyCacheMethodArguments *arguments = nullptr;
if (data->hasArguments()) {
- arguments = (QQmlPropertyCacheMethodArguments *)data->arguments();
- Q_ASSERT(arguments->argumentsValid);
- for (int ii = 0; ii < arguments->arguments[0]; ++ii) {
- if (ii != 0) signature.append(',');
- signature.append(QMetaType(arguments->arguments[1 + ii]).name());
+ arguments = data->arguments();
+ for (int ii = 0, end = arguments->names ? arguments->names->size() : 0;
+ ii < end; ++ii) {
+ if (ii != 0)
+ signature.append(',');
+ signature.append(arguments->types[1 + ii].name());
}
}
@@ -1091,23 +1041,26 @@ void QQmlPropertyCache::toMetaObjectBuilder(QMetaObjectBuilder &builder)
method.setReturnType(returnType);
}
- for (int ii = 0; ii < enumCache.count(); ++ii) {
+ for (int ii = 0; ii < enumCache.size(); ++ii) {
const QQmlEnumData &enumData = enumCache.at(ii);
QMetaEnumBuilder enumeration = builder.addEnumerator(enumData.name.toUtf8());
enumeration.setIsScoped(true);
- for (int jj = 0; jj < enumData.values.count(); ++jj) {
+ for (int jj = 0; jj < enumData.values.size(); ++jj) {
const QQmlEnumValue &value = enumData.values.at(jj);
enumeration.addKey(value.namedValue.toUtf8(), value.value);
}
}
if (!_defaultPropertyName.isEmpty()) {
- QQmlPropertyData *dp = property(_defaultPropertyName, nullptr, nullptr);
+ const QQmlPropertyData *dp = property(_defaultPropertyName, nullptr, nullptr);
if (dp && dp->coreIndex() >= propertyIndexCacheStart) {
Q_ASSERT(!dp->isFunction());
builder.addClassInfo("DefaultProperty", _defaultPropertyName.toUtf8());
}
}
+
+ if (!_listPropertyAssignBehavior.isEmpty())
+ builder.addClassInfo("QML.ListPropertyAssignBehavior", _listPropertyAssignBehavior);
}
namespace {
@@ -1237,11 +1190,13 @@ int countMetaObjectFields(const QMetaObject &mo, StringVisitor stringVisitor)
} // anonymous namespace
+static_assert(QMetaObjectPrivate::OutputRevision == 12, "Check and adjust determineMetaObjectSizes");
+
bool QQmlPropertyCache::determineMetaObjectSizes(const QMetaObject &mo, int *fieldCount,
int *stringCount)
{
const QMetaObjectPrivate *priv = reinterpret_cast<const QMetaObjectPrivate*>(mo.d.data);
- if (priv->revision != 9)
+ if (priv->revision != QMetaObjectPrivate::OutputRevision)
return false;
uint highestStringIndex = 0;
@@ -1263,7 +1218,7 @@ bool QQmlPropertyCache::addToHash(QCryptographicHash &hash, const QMetaObject &m
return false;
}
- hash.addData(reinterpret_cast<const char *>(mo.d.data), fieldCount * sizeof(uint));
+ hash.addData({reinterpret_cast<const char *>(mo.d.data), qsizetype(fieldCount * sizeof(uint))});
for (int i = 0; i < stringCount; ++i) {
hash.addData(stringData(&mo, i));
}
@@ -1271,35 +1226,41 @@ bool QQmlPropertyCache::addToHash(QCryptographicHash &hash, const QMetaObject &m
return true;
}
-QByteArray QQmlPropertyCache::checksum(bool *ok)
+QByteArray QQmlPropertyCache::checksum(QHash<quintptr, QByteArray> *checksums, bool *ok) const
{
- if (!_checksum.isEmpty()) {
+ auto it = checksums->constFind(quintptr(this));
+ if (it != checksums->constEnd()) {
*ok = true;
- return _checksum;
+ return *it;
}
// Generate a checksum on the meta-object data only on C++ types.
- if (!_metaObject || _metaObject.isShared()) {
+ if (_metaObject.isShared()) {
*ok = false;
- return _checksum;
+ return QByteArray();
}
QCryptographicHash hash(QCryptographicHash::Md5);
if (_parent) {
- hash.addData(_parent->checksum(ok));
+ hash.addData(_parent->checksum(checksums, ok));
if (!*ok)
return QByteArray();
}
- if (!addToHash(hash, *createMetaObject())) {
+ if (!addToHash(hash, *_metaObject.metaObject())) {
*ok = false;
return QByteArray();
}
- _checksum = hash.result();
- *ok = !_checksum.isEmpty();
- return _checksum;
+ const QByteArray result = hash.result();
+ if (result.isEmpty()) {
+ *ok = false;
+ } else {
+ *ok = true;
+ checksums->insert(quintptr(this), result);
+ }
+ return result;
}
/*! \internal
@@ -1308,7 +1269,7 @@ QByteArray QQmlPropertyCache::checksum(bool *ok)
*/
QList<QByteArray> QQmlPropertyCache::signalParameterNames(int index) const
{
- QQmlPropertyData *signalData = signal(index);
+ const QQmlPropertyData *signalData = signal(index);
if (signalData && signalData->hasArguments()) {
QQmlPropertyCacheMethodArguments *args = (QQmlPropertyCacheMethodArguments *)signalData->arguments();
if (args && args->names)
diff --git a/src/qml/qml/qqmlpropertycache_p.h b/src/qml/qml/qqmlpropertycache_p.h
index 93661caf91..7ff499460d 100644
--- a/src/qml/qml/qqmlpropertycache_p.h
+++ b/src/qml/qml/qqmlpropertycache_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLPROPERTYCACHE_P_H
#define QQMLPROPERTYCACHE_P_H
@@ -51,21 +15,16 @@
// We mean it.
//
+#include <private/qlinkedstringhash_p.h>
+#include <private/qqmlenumdata_p.h>
+#include <private/qqmlenumvalue_p.h>
+#include <private/qqmlpropertydata_p.h>
#include <private/qqmlrefcount_p.h>
-#include <private/qflagpointer_p.h>
-#include "qqmlnotifier_p.h"
-#include <private/qqmlpropertyindex_p.h>
-#include <private/qlinkedstringhash_p.h>
#include <QtCore/qvarlengtharray.h>
#include <QtCore/qvector.h>
#include <QtCore/qversionnumber.h>
-#include <private/qv4value_p.h>
-#include <private/qqmlpropertydata_p.h>
-#include <private/qqmlenumdata_p.h>
-#include <private/qqmlenumvalue_p.h>
-
#include <limits>
QT_BEGIN_NAMESPACE
@@ -73,129 +32,175 @@ QT_BEGIN_NAMESPACE
class QCryptographicHash;
class QJSEngine;
class QMetaObjectBuilder;
-class QQmlVMEMetaObject;
+class QQmlContextData;
+class QQmlPropertyCache;
class QQmlPropertyCacheMethodArguments;
+class QQmlVMEMetaObject;
-class RefCountedMetaObject {
+class QQmlMetaObjectPointer
+{
public:
- enum OwnershipMode {
- StaticMetaObject,
- SharedMetaObject
- };
+ Q_NODISCARD_CTOR QQmlMetaObjectPointer() = default;
+
+ Q_NODISCARD_CTOR QQmlMetaObjectPointer(const QMetaObject *staticMetaObject)
+ : d(quintptr(staticMetaObject))
+ {
+ Q_ASSERT((d.loadRelaxed() & Shared) == 0);
+ }
- struct Data {
- ~Data() { if (mode == SharedMetaObject) ::free(const_cast<QMetaObject *>(mo)); }
- const QMetaObject *mo = nullptr;
- int ref = 1;
- OwnershipMode mode;
- } *d;
-
- RefCountedMetaObject()
- : d(nullptr)
- {}
-
- RefCountedMetaObject(const QMetaObject *mo, OwnershipMode mode)
- : d(new Data) {
- d->mo = mo;
- d->mode = mode;
+ ~QQmlMetaObjectPointer()
+ {
+ const auto dd = d.loadAcquire();
+ if (dd & Shared)
+ reinterpret_cast<SharedHolder *>(dd ^ Shared)->release();
+ }
+
+private:
+ friend class QQmlPropertyCache;
+ Q_NODISCARD_CTOR QQmlMetaObjectPointer(const QQmlMetaObjectPointer &other)
+ : d(other.d.loadRelaxed())
+ {
+ // other has to survive until this ctor is done. So d cannot disappear before.
+ const auto od = other.d.loadRelaxed();
+ if (od & Shared)
+ reinterpret_cast<SharedHolder *>(od ^ Shared)->addref();
+ }
+
+ QQmlMetaObjectPointer(QQmlMetaObjectPointer &&other) = delete;
+ QQmlMetaObjectPointer &operator=(QQmlMetaObjectPointer &&other) = delete;
+ QQmlMetaObjectPointer &operator=(const QQmlMetaObjectPointer &other) = delete;
+
+public:
+ void setSharedOnce(QMetaObject *shared) const
+ {
+ SharedHolder *holder = new SharedHolder(shared);
+ if (!d.testAndSetRelease(0, quintptr(holder) | Shared))
+ holder->release();
}
- ~RefCountedMetaObject() {
- if (d && !--d->ref)
- delete d;
+
+ const QMetaObject *metaObject() const
+ {
+ const auto dd = d.loadAcquire();
+ if (dd & Shared)
+ return reinterpret_cast<SharedHolder *>(dd ^ Shared)->metaObject;
+ return reinterpret_cast<const QMetaObject *>(dd);
}
- RefCountedMetaObject(const RefCountedMetaObject &other)
- : d(other.d)
+
+ bool isShared() const
{
- if (d && d->ref > 0)
- ++d->ref;
+ // This works because static metaobjects need to be set in the ctor and once a shared
+ // metaobject has been set, it cannot be removed anymore.
+ const auto dd = d.loadRelaxed();
+ return !dd || (dd & Shared);
}
- RefCountedMetaObject &operator =(const RefCountedMetaObject &other)
+
+ bool isNull() const
{
- if (d == other.d)
- return *this;
- if (d && !--d->ref)
- delete d;
- d = other.d;
- if (d && d->ref > 0)
- ++d->ref;
- return *this;
+ return d.loadRelaxed() == 0;
}
- operator const QMetaObject *() const { return d ? d->mo : nullptr; }
- const QMetaObject * operator ->() const { return d ? d->mo : nullptr; }
- bool isShared() const { return d && d->mode == SharedMetaObject; }
+
+private:
+ enum Tag {
+ Static = 0,
+ Shared = 1
+ };
+
+ struct SharedHolder final : public QQmlRefCounted<SharedHolder>
+ {
+ Q_DISABLE_COPY_MOVE(SharedHolder)
+ SharedHolder(QMetaObject *shared) : metaObject(shared) {}
+ ~SharedHolder() { free(metaObject); }
+ QMetaObject *metaObject;
+ };
+
+ mutable QBasicAtomicInteger<quintptr> d = 0;
};
-class Q_QML_PRIVATE_EXPORT QQmlPropertyCache : public QQmlRefCount
+class Q_QML_EXPORT QQmlPropertyCache final
+ : public QQmlRefCounted<QQmlPropertyCache>
{
public:
- QQmlPropertyCache();
- QQmlPropertyCache(const QMetaObject *, QTypeRevision metaObjectRevision = QTypeRevision::zero());
- ~QQmlPropertyCache() override;
+ using Ptr = QQmlRefPointer<QQmlPropertyCache>;
+
+ struct ConstPtr : public QQmlRefPointer<const QQmlPropertyCache>
+ {
+ using QQmlRefPointer<const QQmlPropertyCache>::QQmlRefPointer;
+
+ ConstPtr(const Ptr &ptr) : ConstPtr(ptr.data(), AddRef) {}
+ ConstPtr(Ptr &&ptr) : ConstPtr(ptr.take(), Adopt) {}
+ ConstPtr &operator=(const Ptr &ptr) { return operator=(ConstPtr(ptr)); }
+ ConstPtr &operator=(Ptr &&ptr) { return operator=(ConstPtr(std::move(ptr))); }
+ };
+
+ static Ptr createStandalone(
+ const QMetaObject *, QTypeRevision metaObjectRevision = QTypeRevision::zero());
+
+ QQmlPropertyCache() = default;
+ ~QQmlPropertyCache();
void update(const QMetaObject *);
void invalidate(const QMetaObject *);
- QQmlPropertyCache *copy();
+ QQmlPropertyCache::Ptr copy() const;
- QQmlPropertyCache *copyAndAppend(
+ QQmlPropertyCache::Ptr copyAndAppend(
const QMetaObject *, QTypeRevision typeVersion,
QQmlPropertyData::Flags propertyFlags = QQmlPropertyData::Flags(),
QQmlPropertyData::Flags methodFlags = QQmlPropertyData::Flags(),
- QQmlPropertyData::Flags signalFlags = QQmlPropertyData::Flags());
+ QQmlPropertyData::Flags signalFlags = QQmlPropertyData::Flags()) const;
- QQmlPropertyCache *copyAndReserve(int propertyCount,
- int methodCount, int signalCount, int enumCount);
+ QQmlPropertyCache::Ptr copyAndReserve(
+ int propertyCount, int methodCount, int signalCount, int enumCount) const;
void appendProperty(const QString &, QQmlPropertyData::Flags flags, int coreIndex,
QMetaType propType, QTypeRevision revision, int notifyIndex);
void appendSignal(const QString &, QQmlPropertyData::Flags, int coreIndex,
- const int *types = nullptr, const QList<QByteArray> &names = QList<QByteArray>());
- void appendMethod(const QString &, QQmlPropertyData::Flags flags, int coreIndex, int returnType,
- const QList<QByteArray> &names, const QVector<int> &parameterTypes);
+ const QMetaType *types = nullptr,
+ const QList<QByteArray> &names = QList<QByteArray>());
+ void appendMethod(const QString &, QQmlPropertyData::Flags flags, int coreIndex,
+ QMetaType returnType, const QList<QByteArray> &names,
+ const QVector<QMetaType> &parameterTypes);
void appendEnum(const QString &, const QVector<QQmlEnumValue> &);
const QMetaObject *metaObject() const;
- const QMetaObject *createMetaObject();
+ const QMetaObject *createMetaObject() const;
const QMetaObject *firstCppMetaObject() const;
template<typename K>
- QQmlPropertyData *property(const K &key, QObject *object,
+ const QQmlPropertyData *property(const K &key, QObject *object,
const QQmlRefPointer<QQmlContextData> &context) const
{
return findProperty(stringCache.find(key), object, context);
}
- QQmlPropertyData *property(int) const;
- QQmlPropertyData *maybeUnresolvedProperty(int) const;
- QQmlPropertyData *method(int) const;
- QQmlPropertyData *signal(int index) const;
+ const QQmlPropertyData *property(int) const;
+ const QQmlPropertyData *maybeUnresolvedProperty(int) const;
+ const QQmlPropertyData *method(int) const;
+ const QQmlPropertyData *signal(int index) const;
QQmlEnumData *qmlEnum(int) const;
int methodIndexToSignalIndex(int) const;
QString defaultPropertyName() const;
- QQmlPropertyData *defaultProperty() const;
- inline QQmlPropertyCache *parent() const;
- // is used by the Qml Designer
- void setParent(QQmlPropertyCache *newParent);
+ const QQmlPropertyData *defaultProperty() const;
- inline QQmlPropertyData *overrideData(QQmlPropertyData *) const;
- inline bool isAllowedInRevision(QQmlPropertyData *) const;
+ // Return a reference here so that we don't have to addref/release all the time
+ inline const QQmlPropertyCache::ConstPtr &parent() const;
- static QQmlPropertyData *property(QJSEngine *, QObject *, QStringView,
- const QQmlRefPointer<QQmlContextData> &, QQmlPropertyData *);
- static QQmlPropertyData *property(QJSEngine *, QObject *, const QLatin1String &,
- const QQmlRefPointer<QQmlContextData> &, QQmlPropertyData *);
- static QQmlPropertyData *property(QJSEngine *, QObject *, const QV4::String *,
- const QQmlRefPointer<QQmlContextData> &, QQmlPropertyData *);
+ // is used by the Qml Designer
+ void setParent(QQmlPropertyCache::ConstPtr newParent);
- static QQmlPropertyData *property(QJSEngine *engine, QObject *obj, const QString &name,
- const QQmlRefPointer<QQmlContextData> &context,
- QQmlPropertyData *local)
- {
- return property(engine, obj, QStringView(name), context, local);
- }
+ inline const QQmlPropertyData *overrideData(const QQmlPropertyData *) const;
+ inline bool isAllowedInRevision(const QQmlPropertyData *) const;
+
+ static const QQmlPropertyData *property(
+ QObject *, QStringView, const QQmlRefPointer<QQmlContextData> &,
+ QQmlPropertyData *);
+ static const QQmlPropertyData *property(QObject *, const QLatin1String &, const QQmlRefPointer<QQmlContextData> &,
+ QQmlPropertyData *);
+ static const QQmlPropertyData *property(QObject *, const QV4::String *, const QQmlRefPointer<QQmlContextData> &,
+ QQmlPropertyData *);
//see QMetaObjectPrivate::originalClone
- int originalClone(int index);
+ int originalClone(int index) const;
static int originalClone(const QObject *, int index);
QList<QByteArray> signalParameterNames(int index) const;
@@ -211,16 +216,14 @@ public:
inline int signalOffset() const;
inline int qmlEnumCount() const;
- static bool isDynamicMetaObject(const QMetaObject *);
-
- void toMetaObjectBuilder(QMetaObjectBuilder &);
+ void toMetaObjectBuilder(QMetaObjectBuilder &) const;
inline bool callJSFactoryMethod(QObject *object, void **args) const;
static bool determineMetaObjectSizes(const QMetaObject &mo, int *fieldCount, int *stringCount);
static bool addToHash(QCryptographicHash &hash, const QMetaObject &mo);
- QByteArray checksum(bool *ok);
+ QByteArray checksum(QHash<quintptr, QByteArray> *checksums, bool *ok) const;
QTypeRevision allowedRevision(int index) const { return allowedRevisionCache[index]; }
void setAllowedRevision(int index, QTypeRevision allowed) { allowedRevisionCache[index] = allowed; }
@@ -230,10 +233,12 @@ private:
friend class QQmlCompiler;
template <typename T> friend class QQmlPropertyCacheCreator;
template <typename T> friend class QQmlPropertyCacheAliasCreator;
- friend class QQmlComponentAndAliasResolver;
+ template <typename T> friend class QQmlComponentAndAliasResolver;
friend class QQmlMetaObject;
- inline QQmlPropertyCache *copy(int reserve);
+ QQmlPropertyCache(const QQmlMetaObjectPointer &metaObject) : _metaObject(metaObject) {}
+
+ inline QQmlPropertyCache::Ptr copy(const QQmlMetaObjectPointer &mo, int reserve) const;
void append(const QMetaObject *, QTypeRevision typeVersion,
QQmlPropertyData::Flags propertyFlags = QQmlPropertyData::Flags(),
@@ -246,13 +251,11 @@ private:
typedef QLinkedStringMultiHash<QPair<int, QQmlPropertyData *> > StringCache;
typedef QVector<QTypeRevision> AllowedRevisionCache;
- QQmlPropertyData *findProperty(StringCache::ConstIterator it, QObject *,
+ const QQmlPropertyData *findProperty(StringCache::ConstIterator it, QObject *,
const QQmlRefPointer<QQmlContextData> &) const;
- QQmlPropertyData *findProperty(StringCache::ConstIterator it, const QQmlVMEMetaObject *,
+ const QQmlPropertyData *findProperty(StringCache::ConstIterator it, const QQmlVMEMetaObject *,
const QQmlRefPointer<QQmlContextData> &) const;
- void updateRecur(const QMetaObject *);
-
template<typename K>
QQmlPropertyData *findNamedProperty(const K &key) const
{
@@ -261,15 +264,36 @@ private:
}
template<typename K>
- void setNamedProperty(const K &key, int index, QQmlPropertyData *data, bool isOverride)
+ void setNamedProperty(const K &key, int index, QQmlPropertyData *data)
{
stringCache.insert(key, qMakePair(index, data));
- _hasPropertyOverrides |= isOverride;
}
private:
- int propertyIndexCacheStart; // placed here to avoid gap between QQmlRefCount and _parent
- QQmlPropertyCache *_parent;
+ enum OverrideResult { NoOverride, InvalidOverride, ValidOverride };
+
+ template<typename String>
+ OverrideResult handleOverride(const String &name, QQmlPropertyData *data, QQmlPropertyData *old)
+ {
+ if (!old)
+ return NoOverride;
+
+ if (data->markAsOverrideOf(old))
+ return ValidOverride;
+
+ qWarning("Final member %s is overridden in class %s. The override won't be used.",
+ qPrintable(name), className());
+ return InvalidOverride;
+ }
+
+ template<typename String>
+ OverrideResult handleOverride(const String &name, QQmlPropertyData *data)
+ {
+ return handleOverride(name, data, findNamedProperty(name));
+ }
+
+ int propertyIndexCacheStart = 0; // placed here to avoid gap between QQmlRefCount and _parent
+ QQmlPropertyCache::ConstPtr _parent;
IndexCache propertyIndexCache;
IndexCache methodIndexCache;
@@ -278,23 +302,21 @@ private:
AllowedRevisionCache allowedRevisionCache;
QVector<QQmlEnumData> enumCache;
- RefCountedMetaObject _metaObject;
+ QQmlMetaObjectPointer _metaObject;
QByteArray _dynamicClassName;
QByteArray _dynamicStringData;
+ QByteArray _listPropertyAssignBehavior;
QString _defaultPropertyName;
- QQmlPropertyCacheMethodArguments *argumentsCache;
- QByteArray _checksum;
- int methodIndexCacheStart;
- int signalHandlerIndexCacheStart;
- int _jsFactoryMethodIndex;
- bool _hasPropertyOverrides;
- bool _ownMetaObject;
+ QQmlPropertyCacheMethodArguments *argumentsCache = nullptr;
+ int methodIndexCacheStart = 0;
+ int signalHandlerIndexCacheStart = 0;
+ int _jsFactoryMethodIndex = -1;
};
// Returns this property cache's metaObject. May be null if it hasn't been created yet.
inline const QMetaObject *QQmlPropertyCache::metaObject() const
{
- return _metaObject;
+ return _metaObject.metaObject();
}
// Returns the first C++ type's QMetaObject - that is, the first QMetaObject not created by
@@ -302,53 +324,53 @@ inline const QMetaObject *QQmlPropertyCache::metaObject() const
inline const QMetaObject *QQmlPropertyCache::firstCppMetaObject() const
{
const QQmlPropertyCache *p = this;
- while (!p->_metaObject || p->_metaObject.isShared())
- p = p->parent();
- return p->_metaObject;
+ while (p->_metaObject.isShared())
+ p = p->parent().data();
+ return p->_metaObject.metaObject();
}
-inline QQmlPropertyData *QQmlPropertyCache::property(int index) const
+inline const QQmlPropertyData *QQmlPropertyCache::property(int index) const
{
- if (index < 0 || index >= (propertyIndexCacheStart + propertyIndexCache.count()))
+ if (index < 0 || index >= propertyCount())
return nullptr;
if (index < propertyIndexCacheStart)
return _parent->property(index);
- return const_cast<QQmlPropertyData *>(&propertyIndexCache.at(index - propertyIndexCacheStart));
+ return &propertyIndexCache.at(index - propertyIndexCacheStart);
}
-inline QQmlPropertyData *QQmlPropertyCache::method(int index) const
+inline const QQmlPropertyData *QQmlPropertyCache::method(int index) const
{
- if (index < 0 || index >= (methodIndexCacheStart + methodIndexCache.count()))
+ if (index < 0 || index >= (methodIndexCacheStart + methodIndexCache.size()))
return nullptr;
if (index < methodIndexCacheStart)
return _parent->method(index);
- return const_cast<QQmlPropertyData *>(&methodIndexCache.at(index - methodIndexCacheStart));
+ return const_cast<const QQmlPropertyData *>(&methodIndexCache.at(index - methodIndexCacheStart));
}
/*! \internal
\a index MUST be in the signal index range (see QObjectPrivate::signalIndex()).
This is different from QMetaMethod::methodIndex().
*/
-inline QQmlPropertyData *QQmlPropertyCache::signal(int index) const
+inline const QQmlPropertyData *QQmlPropertyCache::signal(int index) const
{
- if (index < 0 || index >= (signalHandlerIndexCacheStart + signalHandlerIndexCache.count()))
+ if (index < 0 || index >= (signalHandlerIndexCacheStart + signalHandlerIndexCache.size()))
return nullptr;
if (index < signalHandlerIndexCacheStart)
return _parent->signal(index);
- QQmlPropertyData *rv = const_cast<QQmlPropertyData *>(&methodIndexCache.at(index - signalHandlerIndexCacheStart));
+ const QQmlPropertyData *rv = const_cast<const QQmlPropertyData *>(&methodIndexCache.at(index - signalHandlerIndexCacheStart));
Q_ASSERT(rv->isSignal() || rv->coreIndex() == -1);
return rv;
}
inline QQmlEnumData *QQmlPropertyCache::qmlEnum(int index) const
{
- if (index < 0 || index >= enumCache.count())
+ if (index < 0 || index >= enumCache.size())
return nullptr;
return const_cast<QQmlEnumData *>(&enumCache.at(index));
@@ -356,7 +378,7 @@ inline QQmlEnumData *QQmlPropertyCache::qmlEnum(int index) const
inline int QQmlPropertyCache::methodIndexToSignalIndex(int index) const
{
- if (index < 0 || index >= (methodIndexCacheStart + methodIndexCache.count()))
+ if (index < 0 || index >= (methodIndexCacheStart + methodIndexCache.size()))
return index;
if (index < methodIndexCacheStart)
@@ -371,13 +393,13 @@ inline QString QQmlPropertyCache::defaultPropertyName() const
return _defaultPropertyName;
}
-inline QQmlPropertyCache *QQmlPropertyCache::parent() const
+inline const QQmlPropertyCache::ConstPtr &QQmlPropertyCache::parent() const
{
return _parent;
}
-QQmlPropertyData *
-QQmlPropertyCache::overrideData(QQmlPropertyData *data) const
+const QQmlPropertyData *
+QQmlPropertyCache::overrideData(const QQmlPropertyData *data) const
{
if (!data->hasOverride())
return nullptr;
@@ -388,7 +410,7 @@ QQmlPropertyCache::overrideData(QQmlPropertyData *data) const
return method(data->overrideIndex());
}
-bool QQmlPropertyCache::isAllowedInRevision(QQmlPropertyData *data) const
+bool QQmlPropertyCache::isAllowedInRevision(const QQmlPropertyData *data) const
{
const QTypeRevision requested = data->revision();
const int offset = data->metaObjectOffset();
@@ -396,7 +418,7 @@ bool QQmlPropertyCache::isAllowedInRevision(QQmlPropertyData *data) const
return true;
Q_ASSERT(offset >= 0);
- Q_ASSERT(offset < allowedRevisionCache.length());
+ Q_ASSERT(offset < allowedRevisionCache.size());
const QTypeRevision allowed = allowedRevisionCache[offset];
if (requested.hasMajorVersion()) {
@@ -411,7 +433,7 @@ bool QQmlPropertyCache::isAllowedInRevision(QQmlPropertyData *data) const
int QQmlPropertyCache::propertyCount() const
{
- return propertyIndexCacheStart + propertyIndexCache.count();
+ return propertyIndexCacheStart + int(propertyIndexCache.size());
}
int QQmlPropertyCache::propertyOffset() const
@@ -421,7 +443,7 @@ int QQmlPropertyCache::propertyOffset() const
int QQmlPropertyCache::methodCount() const
{
- return methodIndexCacheStart + methodIndexCache.count();
+ return methodIndexCacheStart + int(methodIndexCache.size());
}
int QQmlPropertyCache::methodOffset() const
@@ -431,7 +453,7 @@ int QQmlPropertyCache::methodOffset() const
int QQmlPropertyCache::signalCount() const
{
- return signalHandlerIndexCacheStart + signalHandlerIndexCache.count();
+ return signalHandlerIndexCacheStart + int(signalHandlerIndexCache.size());
}
int QQmlPropertyCache::signalOffset() const
@@ -441,14 +463,18 @@ int QQmlPropertyCache::signalOffset() const
int QQmlPropertyCache::qmlEnumCount() const
{
- return enumCache.count();
+ return int(enumCache.size());
}
bool QQmlPropertyCache::callJSFactoryMethod(QObject *object, void **args) const
{
if (_jsFactoryMethodIndex != -1) {
- _metaObject->d.static_metacall(object, QMetaObject::InvokeMetaMethod, _jsFactoryMethodIndex, args);
- return true;
+ if (const QMetaObject *mo = _metaObject.metaObject()) {
+ mo->d.static_metacall(object, QMetaObject::InvokeMetaMethod,
+ _jsFactoryMethodIndex, args);
+ return true;
+ }
+ return false;
}
if (_parent)
return _parent->callJSFactoryMethod(object, args);
diff --git a/src/qml/qml/qqmlpropertycachecreator.cpp b/src/qml/qml/qqmlpropertycachecreator.cpp
index 5b44bd4f9d..06b405c7e4 100644
--- a/src/qml/qml/qqmlpropertycachecreator.cpp
+++ b/src/qml/qml/qqmlpropertycachecreator.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the tools applications 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qqmlpropertycachecreator_p.h"
@@ -45,62 +9,61 @@ QT_BEGIN_NAMESPACE
QAtomicInt QQmlPropertyCacheCreatorBase::classIndexCounter(0);
-
-QMetaType QQmlPropertyCacheCreatorBase::metaTypeForPropertyType(QV4::CompiledData::BuiltinType type)
-{
- // TODO: we cannot depend on GUI types in declarative, so we'll have to do the id lookup
- switch (type) {
- case QV4::CompiledData::BuiltinType::Var: return QMetaType::fromType<QVariant>();
- case QV4::CompiledData::BuiltinType::Int: return QMetaType::fromType<int>();
- case QV4::CompiledData::BuiltinType::Bool: return QMetaType::fromType<bool>();
- case QV4::CompiledData::BuiltinType::Real: return QMetaType::fromType<qreal>();
- case QV4::CompiledData::BuiltinType::String: return QMetaType::fromType<QString>();
- case QV4::CompiledData::BuiltinType::Url: return QMetaType::fromType<QUrl>();
- case QV4::CompiledData::BuiltinType::Color: return QMetaType(QMetaType::QColor);
- case QV4::CompiledData::BuiltinType::Font: return QMetaType(QMetaType::QFont);
- case QV4::CompiledData::BuiltinType::Time: return QMetaType::fromType<QTime>();
- case QV4::CompiledData::BuiltinType::Date: return QMetaType::fromType<QDate>();
- case QV4::CompiledData::BuiltinType::DateTime: return QMetaType::fromType<QDateTime>();
- case QV4::CompiledData::BuiltinType::Rect: return QMetaType::fromType<QRectF>();
- case QV4::CompiledData::BuiltinType::Point: return QMetaType::fromType<QPointF>();
- case QV4::CompiledData::BuiltinType::Size: return QMetaType::fromType<QSizeF>();
- case QV4::CompiledData::BuiltinType::Vector2D: return QMetaType(QMetaType::QVector2D);
- case QV4::CompiledData::BuiltinType::Vector3D: return QMetaType(QMetaType::QVector3D);
- case QV4::CompiledData::BuiltinType::Vector4D: return QMetaType(QMetaType::QVector4D);
- case QV4::CompiledData::BuiltinType::Matrix4x4: return QMetaType(QMetaType::QMatrix4x4);
- case QV4::CompiledData::BuiltinType::Quaternion: return QMetaType(QMetaType::QQuaternion);
- case QV4::CompiledData::BuiltinType::InvalidBuiltin: break;
- };
- return QMetaType {};
-}
-
-QByteArray QQmlPropertyCacheCreatorBase::createClassNameTypeByUrl(const QUrl &url)
+template<typename BaseNameHandler, typename FailHandler>
+auto processUrlForClassName(
+ const QUrl &url, BaseNameHandler &&baseNameHandler, FailHandler &&failHandler)
{
const QString path = url.path();
- int lastSlash = path.lastIndexOf(QLatin1Char('/'));
+
// Not a reusable type if we don't have an absolute Url
+ const qsizetype lastSlash = path.lastIndexOf(QLatin1Char('/'));
if (lastSlash <= -1)
- return QByteArray();
+ return failHandler();
+
// ### this might not be correct for .ui.qml files
- const QStringView nameBase = QStringView{path}.mid(lastSlash + 1, path.length() - lastSlash - 5);
+ const QStringView baseName = QStringView{path}.mid(lastSlash + 1, path.size() - lastSlash - 5);
+
// Not a reusable type if it doesn't start with a upper case letter.
- if (nameBase.isEmpty() || !nameBase.at(0).isUpper())
- return QByteArray();
- return nameBase.toUtf8() + "_QMLTYPE_" +
- QByteArray::number(classIndexCounter.fetchAndAddRelaxed(1));
+ return (!baseName.isEmpty() && baseName.at(0).isUpper())
+ ? baseNameHandler(baseName)
+ : failHandler();
+}
+
+bool QQmlPropertyCacheCreatorBase::canCreateClassNameTypeByUrl(const QUrl &url)
+{
+ return processUrlForClassName(url, [](QStringView) {
+ return true;
+ }, []() {
+ return false;
+ });
+}
+
+QByteArray QQmlPropertyCacheCreatorBase::createClassNameTypeByUrl(const QUrl &url)
+{
+ return processUrlForClassName(url, [](QStringView nameBase) {
+ return nameBase.toUtf8() + QByteArray("_QMLTYPE_");
+ }, []() {
+ return QByteArray("ANON_QML_TYPE_");
+ }) + QByteArray::number(classIndexCounter.fetchAndAddRelaxed(1));
}
-QByteArray QQmlPropertyCacheCreatorBase::createClassNameForInlineComponent(const QUrl &baseUrl, int icId)
+QByteArray QQmlPropertyCacheCreatorBase::createClassNameForInlineComponent(
+ const QUrl &baseUrl, const QString &name)
{
- QByteArray baseName = createClassNameTypeByUrl(baseUrl);
- if (baseName.isEmpty())
- baseName = QByteArray("ANON_QML_IC_") + QByteArray::number(classIndexCounter.fetchAndAddRelaxed(1));
- baseName += "_" + QByteArray::number(icId);
- return baseName;
+ QByteArray baseName = processUrlForClassName(baseUrl, [](QStringView nameBase) {
+ return QByteArray(nameBase.toUtf8() + "_QMLTYPE_");
+ }, []() {
+ return QByteArray("ANON_QML_IC_");
+ });
+ return baseName + name.toUtf8() + '_'
+ + QByteArray::number(classIndexCounter.fetchAndAddRelaxed(1));
}
-QQmlBindingInstantiationContext::QQmlBindingInstantiationContext(int referencingObjectIndex, const QV4::CompiledData::Binding *instantiatingBinding,
- const QString &instantiatingPropertyName, QQmlPropertyCache *referencingObjectPropertyCache)
+QQmlBindingInstantiationContext::QQmlBindingInstantiationContext(
+ int referencingObjectIndex,
+ const QV4::CompiledData::Binding *instantiatingBinding,
+ const QString &instantiatingPropertyName,
+ const QQmlPropertyCache::ConstPtr &referencingObjectPropertyCache)
: referencingObjectIndex(referencingObjectIndex)
, instantiatingBinding(instantiatingBinding)
, instantiatingPropertyName(instantiatingPropertyName)
@@ -110,11 +73,15 @@ QQmlBindingInstantiationContext::QQmlBindingInstantiationContext(int referencing
bool QQmlBindingInstantiationContext::resolveInstantiatingProperty()
{
- if (!instantiatingBinding || instantiatingBinding->type != QV4::CompiledData::Binding::Type_GroupProperty)
+ if (!instantiatingBinding
+ || instantiatingBinding->type() != QV4::CompiledData::Binding::Type_GroupProperty) {
return true;
+ }
+
+ if (!referencingObjectPropertyCache)
+ return false;
Q_ASSERT(referencingObjectIndex >= 0);
- Q_ASSERT(referencingObjectPropertyCache);
Q_ASSERT(instantiatingBinding->propertyNameIndex != 0);
bool notInRevision = false;
@@ -124,22 +91,34 @@ bool QQmlBindingInstantiationContext::resolveInstantiatingProperty()
return instantiatingProperty != nullptr;
}
-QQmlRefPointer<QQmlPropertyCache> QQmlBindingInstantiationContext::instantiatingPropertyCache(QQmlEnginePrivate *enginePrivate) const
+QQmlPropertyCache::ConstPtr QQmlBindingInstantiationContext::instantiatingPropertyCache() const
{
if (instantiatingProperty) {
if (instantiatingProperty->isQObject()) {
// rawPropertyCacheForType assumes a given unspecified version means "any version".
// There is another overload that takes no version, which we shall not use here.
- return enginePrivate->rawPropertyCacheForType(instantiatingProperty->propType().id(),
- instantiatingProperty->typeVersion());
- } else if (const QMetaObject *vtmo = QQmlMetaType::metaObjectForMetaType(instantiatingProperty->propType())) {
- return enginePrivate->cache(vtmo, instantiatingProperty->typeVersion());
+ auto result = QQmlMetaType::rawPropertyCacheForType(instantiatingProperty->propType(),
+ instantiatingProperty->typeVersion());
+ if (result)
+ return result;
+ /* We might end up here if there's a grouped property, and the type hasn't been registered.
+ Still try to get a property cache, as long as the type of the property is well-behaved
+ (i.e., not dynamic)*/
+ if (auto metaObject = instantiatingProperty->propType().metaObject(); metaObject) {
+ // we'll warn about dynamic meta-object later in the property validator
+ if (!(QMetaObjectPrivate::get(metaObject)->flags & DynamicMetaObject))
+ return QQmlMetaType::propertyCache(metaObject);
+ }
+ // fall through intentional
+ } else if (const QMetaObject *vtmo = QQmlMetaType::metaObjectForValueType(instantiatingProperty->propType())) {
+ return QQmlMetaType::propertyCache(vtmo, instantiatingProperty->typeVersion());
}
}
- return QQmlRefPointer<QQmlPropertyCache>();
+ return QQmlPropertyCache::ConstPtr();
}
-void QQmlPendingGroupPropertyBindings::resolveMissingPropertyCaches(QQmlEnginePrivate *enginePrivate, QQmlPropertyCacheVector *propertyCaches) const
+void QQmlPendingGroupPropertyBindings::resolveMissingPropertyCaches(
+ QQmlPropertyCacheVector *propertyCaches) const
{
for (QQmlBindingInstantiationContext pendingBinding: *this) {
const int groupPropertyObjectIndex = pendingBinding.instantiatingBinding->value.objectIndex;
@@ -147,10 +126,16 @@ void QQmlPendingGroupPropertyBindings::resolveMissingPropertyCaches(QQmlEnginePr
if (propertyCaches->at(groupPropertyObjectIndex))
continue;
+ Q_ASSERT(!pendingBinding.instantiatingPropertyName.isEmpty());
+
+ if (!pendingBinding.referencingObjectPropertyCache) {
+ pendingBinding.referencingObjectPropertyCache
+ = propertyCaches->at(pendingBinding.referencingObjectIndex);
+ }
+
if (!pendingBinding.resolveInstantiatingProperty())
continue;
-
- auto cache = pendingBinding.instantiatingPropertyCache(enginePrivate);
+ auto cache = pendingBinding.instantiatingPropertyCache();
propertyCaches->set(groupPropertyObjectIndex, cache);
}
}
diff --git a/src/qml/qml/qqmlpropertycachecreator_p.h b/src/qml/qml/qqmlpropertycachecreator_p.h
index ca2f2effcd..4d49ca6ed4 100644
--- a/src/qml/qml/qqmlpropertycachecreator_p.h
+++ b/src/qml/qml/qqmlpropertycachecreator_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the tools applications 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLPROPERTYCACHECREATOR_P_H
#define QQMLPROPERTYCACHECREATOR_P_H
@@ -57,8 +21,14 @@
#include <private/qqmltypedata_p.h>
#include <private/inlinecomponentutils_p.h>
#include <private/qqmlsourcecoordinate_p.h>
+#include <private/qqmlsignalnames_p.h>
#include <QScopedValueRollback>
+
+#if QT_CONFIG(regularexpression)
+#include <QtCore/qregularexpression.h>
+#endif
+
#include <vector>
QT_BEGIN_NAMESPACE
@@ -67,60 +37,139 @@ inline QQmlError qQmlCompileError(const QV4::CompiledData::Location &location,
const QString &description)
{
QQmlError error;
- error.setLine(qmlConvertSourceCoordinate<quint32, int>(location.line));
- error.setColumn(qmlConvertSourceCoordinate<quint32, int>(location.column));
+ error.setLine(qmlConvertSourceCoordinate<quint32, int>(location.line()));
+ error.setColumn(qmlConvertSourceCoordinate<quint32, int>(location.column()));
error.setDescription(description);
return error;
}
struct QQmlBindingInstantiationContext {
QQmlBindingInstantiationContext() {}
- QQmlBindingInstantiationContext(int referencingObjectIndex,
- const QV4::CompiledData::Binding *instantiatingBinding,
- const QString &instantiatingPropertyName,
- QQmlPropertyCache *referencingObjectPropertyCache);
+ QQmlBindingInstantiationContext(
+ int referencingObjectIndex, const QV4::CompiledData::Binding *instantiatingBinding,
+ const QString &instantiatingPropertyName,
+ const QQmlPropertyCache::ConstPtr &referencingObjectPropertyCache);
bool resolveInstantiatingProperty();
- QQmlRefPointer<QQmlPropertyCache> instantiatingPropertyCache(QQmlEnginePrivate *enginePrivate) const;
+ QQmlPropertyCache::ConstPtr instantiatingPropertyCache() const;
int referencingObjectIndex = -1;
const QV4::CompiledData::Binding *instantiatingBinding = nullptr;
QString instantiatingPropertyName;
- QQmlRefPointer<QQmlPropertyCache> referencingObjectPropertyCache;
- QQmlPropertyData *instantiatingProperty = nullptr;
+ QQmlPropertyCache::ConstPtr referencingObjectPropertyCache;
+ const QQmlPropertyData *instantiatingProperty = nullptr;
};
struct QQmlPendingGroupPropertyBindings : public QVector<QQmlBindingInstantiationContext>
{
- void resolveMissingPropertyCaches(QQmlEnginePrivate *enginePrivate, QQmlPropertyCacheVector *propertyCaches) const;
+ void resolveMissingPropertyCaches(
+ QQmlPropertyCacheVector *propertyCaches) const;
};
struct QQmlPropertyCacheCreatorBase
{
Q_DECLARE_TR_FUNCTIONS(QQmlPropertyCacheCreatorBase)
public:
- static QAtomicInt classIndexCounter;
+ static QAtomicInt Q_AUTOTEST_EXPORT classIndexCounter;
+
+ static QMetaType metaTypeForPropertyType(QV4::CompiledData::CommonType type)
+ {
+ switch (type) {
+ case QV4::CompiledData::CommonType::Void: return QMetaType();
+ case QV4::CompiledData::CommonType::Var: return QMetaType::fromType<QVariant>();
+ case QV4::CompiledData::CommonType::Int: return QMetaType::fromType<int>();
+ case QV4::CompiledData::CommonType::Bool: return QMetaType::fromType<bool>();
+ case QV4::CompiledData::CommonType::Real: return QMetaType::fromType<qreal>();
+ case QV4::CompiledData::CommonType::String: return QMetaType::fromType<QString>();
+ case QV4::CompiledData::CommonType::Url: return QMetaType::fromType<QUrl>();
+ case QV4::CompiledData::CommonType::Time: return QMetaType::fromType<QTime>();
+ case QV4::CompiledData::CommonType::Date: return QMetaType::fromType<QDate>();
+ case QV4::CompiledData::CommonType::DateTime: return QMetaType::fromType<QDateTime>();
+#if QT_CONFIG(regularexpression)
+ case QV4::CompiledData::CommonType::RegExp: return QMetaType::fromType<QRegularExpression>();
+#else
+ case QV4::CompiledData::CommonType::RegExp: return QMetaType();
+#endif
+ case QV4::CompiledData::CommonType::Rect: return QMetaType::fromType<QRectF>();
+ case QV4::CompiledData::CommonType::Point: return QMetaType::fromType<QPointF>();
+ case QV4::CompiledData::CommonType::Size: return QMetaType::fromType<QSizeF>();
+ case QV4::CompiledData::CommonType::Invalid: break;
+ };
+ return QMetaType {};
+ }
- static QMetaType metaTypeForPropertyType(QV4::CompiledData::BuiltinType type);
+ static QMetaType listTypeForPropertyType(QV4::CompiledData::CommonType type)
+ {
+ switch (type) {
+ case QV4::CompiledData::CommonType::Void: return QMetaType();
+ case QV4::CompiledData::CommonType::Var: return QMetaType::fromType<QList<QVariant>>();
+ case QV4::CompiledData::CommonType::Int: return QMetaType::fromType<QList<int>>();
+ case QV4::CompiledData::CommonType::Bool: return QMetaType::fromType<QList<bool>>();
+ case QV4::CompiledData::CommonType::Real: return QMetaType::fromType<QList<qreal>>();
+ case QV4::CompiledData::CommonType::String: return QMetaType::fromType<QList<QString>>();
+ case QV4::CompiledData::CommonType::Url: return QMetaType::fromType<QList<QUrl>>();
+ case QV4::CompiledData::CommonType::Time: return QMetaType::fromType<QList<QTime>>();
+ case QV4::CompiledData::CommonType::Date: return QMetaType::fromType<QList<QDate>>();
+ case QV4::CompiledData::CommonType::DateTime: return QMetaType::fromType<QList<QDateTime>>();
+#if QT_CONFIG(regularexpression)
+ case QV4::CompiledData::CommonType::RegExp: return QMetaType::fromType<QList<QRegularExpression>>();
+#else
+ case QV4::CompiledData::CommonType::RegExp: return QMetaType();
+#endif
+ case QV4::CompiledData::CommonType::Rect: return QMetaType::fromType<QList<QRectF>>();
+ case QV4::CompiledData::CommonType::Point: return QMetaType::fromType<QList<QPointF>>();
+ case QV4::CompiledData::CommonType::Size: return QMetaType::fromType<QList<QSizeF>>();
+ case QV4::CompiledData::CommonType::Invalid: break;
+ };
+ return QMetaType {};
+ }
+ static bool canCreateClassNameTypeByUrl(const QUrl &url);
static QByteArray createClassNameTypeByUrl(const QUrl &url);
- static QByteArray createClassNameForInlineComponent(const QUrl &baseUrl, int icId);
+ static QByteArray createClassNameForInlineComponent(const QUrl &baseUrl, const QString &name);
+
+ struct IncrementalResult {
+ // valid if and only if an error occurred
+ QQmlError error;
+ // true if there was no error and there are still components left to process
+ bool canResume = false;
+ // the object index of the last processed (inline) component root.
+ int processedRoot = 0;
+ };
};
template <typename ObjectContainer>
class QQmlPropertyCacheCreator : public QQmlPropertyCacheCreatorBase
{
public:
- typedef typename ObjectContainer::CompiledObject CompiledObject;
+ using CompiledObject = typename ObjectContainer::CompiledObject;
+ using InlineComponent = typename std::remove_reference<decltype (*(std::declval<CompiledObject>().inlineComponentsBegin()))>::type;
QQmlPropertyCacheCreator(QQmlPropertyCacheVector *propertyCaches,
QQmlPendingGroupPropertyBindings *pendingGroupPropertyBindings,
QQmlEnginePrivate *enginePrivate,
const ObjectContainer *objectContainer, const QQmlImports *imports,
const QByteArray &typeClassName);
+ ~QQmlPropertyCacheCreator() { propertyCaches->seal(); }
+
+
+ /*!
+ \internal
+ Creates the property cache for the CompiledObjects of objectContainer,
+ one (inline) root component at a time.
+
+ \note Later compiler passes might modify those property caches. Therefore,
+ the actual metaobjects are not created yet.
+ */
+ IncrementalResult buildMetaObjectsIncrementally();
- QQmlError buildMetaObjects();
+ /*!
+ \internal
+ Returns a valid error if the inline components of the objectContainer
+ form a cycle. Otherwise an invalid error is returned
+ */
+ QQmlError verifyNoICCycle();
enum class VMEMetaObjectIsRequired {
Maybe,
@@ -128,8 +177,8 @@ public:
};
protected:
QQmlError buildMetaObjectRecursively(int objectIndex, const QQmlBindingInstantiationContext &context, VMEMetaObjectIsRequired isVMERequired);
- QQmlRefPointer<QQmlPropertyCache> propertyCacheForObject(const CompiledObject *obj, const QQmlBindingInstantiationContext &context, QQmlError *error) const;
- QQmlError createMetaObject(int objectIndex, const CompiledObject *obj, const QQmlRefPointer<QQmlPropertyCache> &baseTypeCache);
+ QQmlPropertyCache::ConstPtr propertyCacheForObject(const CompiledObject *obj, const QQmlBindingInstantiationContext &context, QQmlError *error) const;
+ QQmlError createMetaObject(int objectIndex, const CompiledObject *obj, const QQmlPropertyCache::ConstPtr &baseTypeCache);
QMetaType metaTypeForParameter(const QV4::CompiledData::ParameterType &param, QString *customTypeName = nullptr);
@@ -142,6 +191,12 @@ protected:
QQmlPendingGroupPropertyBindings *pendingGroupPropertyBindings;
QByteArray typeClassName; // not const as we temporarily chang it for inline components
unsigned int currentRoot; // set to objectID of inline component root when handling inline components
+
+ QQmlBindingInstantiationContext m_context;
+ std::vector<InlineComponent> allICs;
+ std::vector<icutils::Node> nodesSorted;
+ std::vector<icutils::Node>::reverse_iterator nodeIt = nodesSorted.rbegin();
+ bool hasCycle = false;
};
template <typename ObjectContainer>
@@ -158,18 +213,12 @@ inline QQmlPropertyCacheCreator<ObjectContainer>::QQmlPropertyCacheCreator(QQmlP
, typeClassName(typeClassName)
, currentRoot(-1)
{
- propertyCaches->resize(objectContainer->objectCount());
-}
+ propertyCaches->resetAndResize(objectContainer->objectCount());
-template <typename ObjectContainer>
-inline QQmlError QQmlPropertyCacheCreator<ObjectContainer>::buildMetaObjects()
-{
using namespace icutils;
- QQmlBindingInstantiationContext context;
// get a list of all inline components
- using InlineComponent = typename std::remove_reference<decltype (*(std::declval<CompiledObject>().inlineComponentsBegin()))>::type;
- std::vector<InlineComponent> allICs {};
+
for (int i=0; i != objectContainer->objectCount(); ++i) {
const CompiledObject *obj = objectContainer->objectAt(i);
for (auto it = obj->inlineComponentsBegin(); it != obj->inlineComponentsEnd(); ++it) {
@@ -178,41 +227,57 @@ inline QQmlError QQmlPropertyCacheCreator<ObjectContainer>::buildMetaObjects()
}
// create a graph on inline components referencing inline components
- std::vector<Node> nodes;
+ std::vector<icutils::Node> nodes;
nodes.resize(allICs.size());
std::iota(nodes.begin(), nodes.end(), 0);
AdjacencyList adjacencyList;
adjacencyList.resize(nodes.size());
fillAdjacencyListForInlineComponents(objectContainer, adjacencyList, nodes, allICs);
- bool hasCycle = false;
- auto nodesSorted = topoSort(nodes, adjacencyList, hasCycle);
+ nodesSorted = topoSort(nodes, adjacencyList, hasCycle);
+ nodeIt = nodesSorted.rbegin();
+}
+template <typename ObjectContainer>
+inline QQmlError QQmlPropertyCacheCreator<ObjectContainer>::verifyNoICCycle()
+{
if (hasCycle) {
QQmlError diag;
diag.setDescription(QLatin1String("Inline components form a cycle!"));
return diag;
}
+ return {};
+}
+
+template <typename ObjectContainer>
+inline QQmlPropertyCacheCreatorBase::IncrementalResult
+QQmlPropertyCacheCreator<ObjectContainer>::buildMetaObjectsIncrementally()
+{
+ // needs to be checked with verifyNoICCycle before this function is called
+ Q_ASSERT(!hasCycle);
// create meta objects for inline components before compiling actual root component
- for (auto nodeIt = nodesSorted.rbegin(); nodeIt != nodesSorted.rend(); ++nodeIt) {
- const auto &ic = allICs[nodeIt->index];
+ if (nodeIt != nodesSorted.rend()) {
+ const auto &ic = allICs[nodeIt->index()];
QV4::ResolvedTypeReference *typeRef = objectContainer->resolvedType(ic.nameIndex);
- Q_ASSERT(propertyCaches->at(ic.objectIndex) == nullptr);
+ Q_ASSERT(propertyCaches->at(ic.objectIndex).isNull());
Q_ASSERT(typeRef->typePropertyCache().isNull()); // not set yet
QByteArray icTypeName { objectContainer->stringAt(ic.nameIndex).toUtf8() };
QScopedValueRollback<QByteArray> nameChange {typeClassName, icTypeName};
QScopedValueRollback<unsigned int> rootChange {currentRoot, ic.objectIndex};
- QQmlError diag = buildMetaObjectRecursively(ic.objectIndex, context, VMEMetaObjectIsRequired::Always);
+ ++nodeIt;
+ QQmlError diag = buildMetaObjectRecursively(ic.objectIndex, m_context, VMEMetaObjectIsRequired::Always);
if (diag.isValid()) {
- return diag;
+ return {diag, false, 0};
}
typeRef->setTypePropertyCache(propertyCaches->at(ic.objectIndex));
Q_ASSERT(!typeRef->typePropertyCache().isNull());
+ return { QQmlError(), true, int(ic.objectIndex) };
}
- return buildMetaObjectRecursively(/*root object*/0, context, VMEMetaObjectIsRequired::Maybe);
+ auto diag = buildMetaObjectRecursively(/*root object*/0, m_context, VMEMetaObjectIsRequired::Maybe);
+ return {diag, false, 0};
}
template <typename ObjectContainer>
@@ -226,7 +291,7 @@ inline QQmlError QQmlPropertyCacheCreator<ObjectContainer>::buildMetaObjectRecur
const CompiledObject *obj = objectContainer->objectAt(objectIndex);
bool needVMEMetaObject = isVMERequired == VMEMetaObjectIsRequired::Always || obj->propertyCount() != 0 || obj->aliasCount() != 0
|| obj->signalCount() != 0 || obj->functionCount() != 0 || obj->enumCount() != 0
- || (((obj->flags & QV4::CompiledData::Object::IsComponent)
+ || ((obj->hasFlag(QV4::CompiledData::Object::IsComponent)
|| (objectIndex == 0 && isAddressable(objectContainer->url())))
&& !objectContainer->resolvedType(obj->inheritedTypeNameIndex)->isFullyDynamicType());
@@ -234,7 +299,8 @@ inline QQmlError QQmlPropertyCacheCreator<ObjectContainer>::buildMetaObjectRecur
auto binding = obj->bindingsBegin();
auto end = obj->bindingsEnd();
for ( ; binding != end; ++binding) {
- if (binding->type == QV4::CompiledData::Binding::Type_Object && (binding->flags & QV4::CompiledData::Binding::IsOnAssignment)) {
+ if (binding->type() == QV4::CompiledData::Binding::Type_Object
+ && (binding->flags() & QV4::CompiledData::Binding::IsOnAssignment)) {
// If the on assignment is inside a group property, we need to distinguish between QObject based
// group properties and value type group properties. For the former the base type is derived from
// the property that references us, for the latter we only need a meta-object on the referencing object
@@ -244,8 +310,11 @@ inline QQmlError QQmlPropertyCacheCreator<ObjectContainer>::buildMetaObjectRecur
const CompiledObject *obj = objectContainer->objectAt(context.referencingObjectIndex);
auto *typeRef = objectContainer->resolvedType(obj->inheritedTypeNameIndex);
Q_ASSERT(typeRef);
- QQmlRefPointer<QQmlPropertyCache> baseTypeCache = typeRef->createPropertyCache(QQmlEnginePrivate::get(enginePrivate));
- QQmlError error = createMetaObject(context.referencingObjectIndex, obj, baseTypeCache);
+ QQmlPropertyCache::ConstPtr baseTypeCache = typeRef->createPropertyCache();
+ QQmlError error = baseTypeCache
+ ? createMetaObject(context.referencingObjectIndex, obj, baseTypeCache)
+ : qQmlCompileError(binding->location, QQmlPropertyCacheCreatorBase::tr(
+ "Type cannot be used for 'on' assignment"));
if (error.isValid())
return error;
}
@@ -258,7 +327,7 @@ inline QQmlError QQmlPropertyCacheCreator<ObjectContainer>::buildMetaObjectRecur
}
}
- QQmlRefPointer<QQmlPropertyCache> baseTypeCache;
+ QQmlPropertyCache::ConstPtr baseTypeCache;
{
QQmlError error;
baseTypeCache = propertyCacheForObject(obj, context, &error);
@@ -276,24 +345,35 @@ inline QQmlError QQmlPropertyCacheCreator<ObjectContainer>::buildMetaObjectRecur
}
}
- if (QQmlPropertyCache *thisCache = propertyCaches->at(objectIndex)) {
- auto binding = obj->bindingsBegin();
- auto end = obj->bindingsEnd();
- for ( ; binding != end; ++binding)
- if (binding->type >= QV4::CompiledData::Binding::Type_Object) {
- QQmlBindingInstantiationContext context(objectIndex, &(*binding), stringAt(binding->propertyNameIndex), thisCache);
-
- // Binding to group property where we failed to look up the type of the
- // property? Possibly a group property that is an alias that's not resolved yet.
- // Let's attempt to resolve it after we're done with the aliases and fill in the
- // propertyCaches entry then.
- if (!context.resolveInstantiatingProperty())
- pendingGroupPropertyBindings->append(context);
-
- QQmlError error = buildMetaObjectRecursively(binding->value.objectIndex, context, VMEMetaObjectIsRequired::Maybe);
- if (error.isValid())
- return error;
- }
+ QQmlPropertyCache::ConstPtr thisCache = propertyCaches->at(objectIndex);
+ auto binding = obj->bindingsBegin();
+ auto end = obj->bindingsEnd();
+ for (; binding != end; ++binding) {
+ switch (binding->type()) {
+ case QV4::CompiledData::Binding::Type_Object:
+ case QV4::CompiledData::Binding::Type_GroupProperty:
+ case QV4::CompiledData::Binding::Type_AttachedProperty:
+ // We can always resolve object, group, and attached properties.
+ break;
+ default:
+ // Everything else is of no interest here.
+ continue;
+ }
+
+ QQmlBindingInstantiationContext context(
+ objectIndex, &(*binding), stringAt(binding->propertyNameIndex), thisCache);
+
+ // Binding to group property where we failed to look up the type of the
+ // property? Possibly a group property that is an alias that's not resolved yet.
+ // Let's attempt to resolve it after we're done with the aliases and fill in the
+ // propertyCaches entry then.
+ if (!thisCache || !context.resolveInstantiatingProperty())
+ pendingGroupPropertyBindings->append(context);
+
+ QQmlError error = buildMetaObjectRecursively(
+ binding->value.objectIndex, context, VMEMetaObjectIsRequired::Maybe);
+ if (error.isValid())
+ return error;
}
QQmlError noError;
@@ -301,10 +381,10 @@ inline QQmlError QQmlPropertyCacheCreator<ObjectContainer>::buildMetaObjectRecur
}
template <typename ObjectContainer>
-inline QQmlRefPointer<QQmlPropertyCache> QQmlPropertyCacheCreator<ObjectContainer>::propertyCacheForObject(const CompiledObject *obj, const QQmlBindingInstantiationContext &context, QQmlError *error) const
+inline QQmlPropertyCache::ConstPtr QQmlPropertyCacheCreator<ObjectContainer>::propertyCacheForObject(const CompiledObject *obj, const QQmlBindingInstantiationContext &context, QQmlError *error) const
{
if (context.instantiatingProperty) {
- return context.instantiatingPropertyCache(enginePrivate);
+ return context.instantiatingPropertyCache();
} else if (obj->inheritedTypeNameIndex != 0) {
auto *typeRef = objectContainer->resolvedType(obj->inheritedTypeNameIndex);
Q_ASSERT(typeRef);
@@ -324,36 +404,48 @@ inline QQmlRefPointer<QQmlPropertyCache> QQmlPropertyCacheCreator<ObjectContaine
}
}
- return typeRef->createPropertyCache(QQmlEnginePrivate::get(enginePrivate));
- } else if (context.instantiatingBinding && context.instantiatingBinding->isAttachedProperty()) {
- auto *typeRef = objectContainer->resolvedType(
- context.instantiatingBinding->propertyNameIndex);
- Q_ASSERT(typeRef);
- QQmlType qmltype = typeRef->type();
- if (!qmltype.isValid()) {
- imports->resolveType(stringAt(context.instantiatingBinding->propertyNameIndex),
- &qmltype, nullptr, nullptr, nullptr);
- }
+ if (QQmlPropertyCache::ConstPtr propertyCache = typeRef->createPropertyCache())
+ return propertyCache;
+ *error = qQmlCompileError(
+ obj->location,
+ QQmlPropertyCacheCreatorBase::tr("Type '%1' cannot declare new members.")
+ .arg(stringAt(obj->inheritedTypeNameIndex)));
+ return nullptr;
+ } else if (const QV4::CompiledData::Binding *binding = context.instantiatingBinding) {
+ if (binding->isAttachedProperty()) {
+ auto *typeRef = objectContainer->resolvedType(
+ binding->propertyNameIndex);
+ Q_ASSERT(typeRef);
+ QQmlType qmltype = typeRef->type();
+ if (!qmltype.isValid()) {
+ imports->resolveType(
+ QQmlTypeLoader::get(enginePrivate), stringAt(binding->propertyNameIndex),
+ &qmltype, nullptr, nullptr);
+ }
- const QMetaObject *attachedMo = qmltype.attachedPropertiesType(enginePrivate);
- if (!attachedMo) {
- *error = qQmlCompileError(context.instantiatingBinding->location, QQmlPropertyCacheCreatorBase::tr("Non-existent attached object"));
- return nullptr;
+ const QMetaObject *attachedMo = qmltype.attachedPropertiesType(enginePrivate);
+ if (!attachedMo) {
+ *error = qQmlCompileError(binding->location, QQmlPropertyCacheCreatorBase::tr("Non-existent attached object"));
+ return nullptr;
+ }
+ return QQmlMetaType::propertyCache(attachedMo);
}
- return enginePrivate->cache(attachedMo);
}
return nullptr;
}
template <typename ObjectContainer>
-inline QQmlError QQmlPropertyCacheCreator<ObjectContainer>::createMetaObject(int objectIndex, const CompiledObject *obj, const QQmlRefPointer<QQmlPropertyCache> &baseTypeCache)
+inline QQmlError QQmlPropertyCacheCreator<ObjectContainer>::createMetaObject(
+ int objectIndex, const CompiledObject *obj,
+ const QQmlPropertyCache::ConstPtr &baseTypeCache)
{
- QQmlRefPointer<QQmlPropertyCache> cache;
- cache.adopt(baseTypeCache->copyAndReserve(obj->propertyCount() + obj->aliasCount(),
- obj->functionCount() + obj->propertyCount() + obj->aliasCount() + obj->signalCount(),
- obj->signalCount() + obj->propertyCount() + obj->aliasCount(), obj->enumCount()));
+ QQmlPropertyCache::Ptr cache = baseTypeCache->copyAndReserve(
+ obj->propertyCount() + obj->aliasCount(),
+ obj->functionCount() + obj->propertyCount() + obj->aliasCount() + obj->signalCount(),
+ obj->signalCount() + obj->propertyCount() + obj->aliasCount(),
+ obj->enumCount());
- propertyCaches->set(objectIndex, cache);
+ propertyCaches->setOwn(objectIndex, cache);
propertyCaches->setNeedsVMEMetaObject(objectIndex);
QByteArray newClassName;
@@ -362,20 +454,32 @@ inline QQmlError QQmlPropertyCacheCreator<ObjectContainer>::createMetaObject(int
newClassName = typeClassName;
}
if (newClassName.isEmpty()) {
- newClassName = QQmlMetaObject(baseTypeCache.data()).className();
+ newClassName = QQmlMetaObject(baseTypeCache).className();
newClassName.append("_QML_");
newClassName.append(QByteArray::number(classIndexCounter.fetchAndAddRelaxed(1)));
}
cache->_dynamicClassName = newClassName;
+ using ListPropertyAssignBehavior = typename ObjectContainer::ListPropertyAssignBehavior;
+ switch (objectContainer->listPropertyAssignBehavior()) {
+ case ListPropertyAssignBehavior::ReplaceIfNotDefault:
+ cache->_listPropertyAssignBehavior = "ReplaceIfNotDefault";
+ break;
+ case ListPropertyAssignBehavior::Replace:
+ cache->_listPropertyAssignBehavior = "Replace";
+ break;
+ case ListPropertyAssignBehavior::Append:
+ break;
+ }
+
QQmlPropertyResolver resolver(baseTypeCache);
auto p = obj->propertiesBegin();
auto pend = obj->propertiesEnd();
for ( ; p != pend; ++p) {
bool notInRevision = false;
- QQmlPropertyData *d = resolver.property(stringAt(p->nameIndex), &notInRevision);
+ const QQmlPropertyData *d = resolver.property(stringAt(p->nameIndex), &notInRevision);
if (d && d->isFinal())
return qQmlCompileError(p->location, QQmlPropertyCacheCreatorBase::tr("Cannot override FINAL property"));
}
@@ -384,7 +488,7 @@ inline QQmlError QQmlPropertyCacheCreator<ObjectContainer>::createMetaObject(int
auto aend = obj->aliasesEnd();
for ( ; a != aend; ++a) {
bool notInRevision = false;
- QQmlPropertyData *d = resolver.property(stringAt(a->nameIndex), &notInRevision);
+ const QQmlPropertyData *d = resolver.property(stringAt(a->nameIndex()), &notInRevision);
if (d && d->isFinal())
return qQmlCompileError(a->location, QQmlPropertyCacheCreatorBase::tr("Cannot override FINAL property"));
}
@@ -395,19 +499,32 @@ inline QQmlError QQmlPropertyCacheCreator<ObjectContainer>::createMetaObject(int
// For property change signal override detection.
// We prepopulate a set of signal names which already exist in the object,
// and throw an error if there is a signal/method defined as an override.
- QSet<QString> seenSignals;
- seenSignals << QStringLiteral("destroyed") << QStringLiteral("parentChanged") << QStringLiteral("objectNameChanged");
- QQmlPropertyCache *parentCache = cache.data();
- while ((parentCache = parentCache->parent())) {
+ // TODO: Remove AllowOverride once we can. No override should be allowed.
+ enum class AllowOverride { No, Yes };
+ QHash<QString, AllowOverride> seenSignals {
+ { QStringLiteral("destroyed"), AllowOverride::No },
+ { QStringLiteral("parentChanged"), AllowOverride::No },
+ { QStringLiteral("objectNameChanged"), AllowOverride::No }
+ };
+ const QQmlPropertyCache *parentCache = cache.data();
+ while ((parentCache = parentCache->parent().data())) {
if (int pSigCount = parentCache->signalCount()) {
int pSigOffset = parentCache->signalOffset();
for (int i = pSigOffset; i < pSigCount; ++i) {
- QQmlPropertyData *currPSig = parentCache->signal(i);
+ const QQmlPropertyData *currPSig = parentCache->signal(i);
// XXX TODO: find a better way to get signal name from the property data :-/
for (QQmlPropertyCache::StringCache::ConstIterator iter = parentCache->stringCache.begin();
iter != parentCache->stringCache.end(); ++iter) {
if (currPSig == (*iter).second) {
- seenSignals.insert(iter.key());
+ if (currPSig->isOverridableSignal()) {
+ const qsizetype oldSize = seenSignals.size();
+ AllowOverride &entry = seenSignals[iter.key()];
+ if (seenSignals.size() != oldSize)
+ entry = AllowOverride::Yes;
+ } else {
+ seenSignals[iter.key()] = AllowOverride::No;
+ }
+
break;
}
}
@@ -421,8 +538,9 @@ inline QQmlError QQmlPropertyCacheCreator<ObjectContainer>::createMetaObject(int
for ( ; p != pend; ++p) {
auto flags = QQmlPropertyData::defaultSignalFlags();
- QString changedSigName = stringAt(p->nameIndex) + QLatin1String("Changed");
- seenSignals.insert(changedSigName);
+ const QString changedSigName =
+ QQmlSignalNames::propertyNameToChangedSignalName(stringAt(p->nameIndex));
+ seenSignals[changedSigName] = AllowOverride::No;
cache->appendSignal(changedSigName, flags, effectiveMethodIndex++);
}
@@ -432,8 +550,9 @@ inline QQmlError QQmlPropertyCacheCreator<ObjectContainer>::createMetaObject(int
for ( ; a != aend; ++a) {
auto flags = QQmlPropertyData::defaultSignalFlags();
- QString changedSigName = stringAt(a->nameIndex) + QLatin1String("Changed");
- seenSignals.insert(changedSigName);
+ const QString changedSigName =
+ QQmlSignalNames::propertyNameToChangedSignalName(stringAt(a->nameIndex()));
+ seenSignals[changedSigName] = AllowOverride::No;
cache->appendSignal(changedSigName, flags, effectiveMethodIndex++);
}
@@ -461,10 +580,9 @@ inline QQmlError QQmlPropertyCacheCreator<ObjectContainer>::createMetaObject(int
QList<QByteArray> names;
names.reserve(paramCount);
- QVarLengthArray<int, 10> paramTypes(paramCount?(paramCount + 1):0);
+ QVarLengthArray<QMetaType, 10> paramTypes(paramCount);
if (paramCount) {
- paramTypes[0] = paramCount;
int i = 0;
auto param = s->parametersBegin();
@@ -477,7 +595,7 @@ inline QQmlError QQmlPropertyCacheCreator<ObjectContainer>::createMetaObject(int
if (!type.isValid())
return qQmlCompileError(s->location, QQmlPropertyCacheCreatorBase::tr("Invalid signal parameter type: %1").arg(customTypeName));
- paramTypes[i + 1] = type.id();
+ paramTypes[i] = type;
}
}
@@ -486,10 +604,26 @@ inline QQmlError QQmlPropertyCacheCreator<ObjectContainer>::createMetaObject(int
flags.setHasArguments(true);
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"));
- seenSignals.insert(signalName);
-
+ const auto it = seenSignals.find(signalName);
+ if (it == seenSignals.end()) {
+ seenSignals[signalName] = AllowOverride::No;
+ } else {
+ // TODO: Remove the AllowOverride::Yes branch once we can.
+ QQmlError message = qQmlCompileError(
+ s->location,
+ QQmlPropertyCacheCreatorBase::tr(
+ "Duplicate signal name: "
+ "invalid override of property change signal or superclass signal"));
+ switch (*it) {
+ case AllowOverride::No:
+ return message;
+ case AllowOverride::Yes:
+ message.setUrl(objectContainer->url());
+ enginePrivate->warning(message);
+ *it = AllowOverride::No; // No further overriding allowed.
+ break;
+ }
+ }
cache->appendSignal(signalName, flags, effectiveMethodIndex++,
paramCount?paramTypes.constData():nullptr, names);
}
@@ -502,27 +636,42 @@ inline QQmlError QQmlPropertyCacheCreator<ObjectContainer>::createMetaObject(int
auto flags = QQmlPropertyData::defaultSlotFlags();
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"));
+ const auto it = seenSignals.constFind(slotName);
+ if (it != seenSignals.constEnd()) {
+ // TODO: Remove the AllowOverride::Yes branch once we can.
+ QQmlError message = qQmlCompileError(
+ function->location,
+ QQmlPropertyCacheCreatorBase::tr(
+ "Duplicate method name: "
+ "invalid override of property change signal or superclass signal"));
+ switch (*it) {
+ case AllowOverride::No:
+ return message;
+ case AllowOverride::Yes:
+ message.setUrl(objectContainer->url());
+ enginePrivate->warning(message);
+ break;
+ }
+ }
// Note: we don't append slotName to the seenSignals list, since we don't
// protect against overriding change signals or methods with properties.
QList<QByteArray> parameterNames;
- QVector<int> parameterTypes;
+ QVector<QMetaType> parameterTypes;
auto formal = function->formalsBegin();
auto end = function->formalsEnd();
for ( ; formal != end; ++formal) {
flags.setHasArguments(true);
parameterNames << stringAt(formal->nameIndex).toUtf8();
- int type = metaTypeForParameter(formal->type).id();
- if (type == QMetaType::UnknownType)
- type = QMetaType::QVariant;
+ QMetaType type = metaTypeForParameter(formal->type);
+ if (!type.isValid())
+ type = QMetaType::fromType<QVariant>();
parameterTypes << type;
}
- int returnType = metaTypeForParameter(function->returnType).id();
- if (returnType == QMetaType::UnknownType)
- returnType = QMetaType::QVariant;
+ QMetaType returnType = metaTypeForParameter(function->returnType);
+ if (!returnType.isValid())
+ returnType = QMetaType::fromType<QVariant>();
cache->appendMethod(slotName, flags, effectiveMethodIndex++, returnType, parameterNames, parameterTypes);
}
@@ -538,77 +687,74 @@ inline QQmlError QQmlPropertyCacheCreator<ObjectContainer>::createMetaObject(int
QTypeRevision propertyTypeVersion = QTypeRevision::zero();
QQmlPropertyData::Flags propertyFlags;
- const QV4::CompiledData::BuiltinType type = p->builtinType();
+ const QV4::CompiledData::CommonType type = p->commonType();
- if (type == QV4::CompiledData::BuiltinType::Var)
- propertyFlags.type = QQmlPropertyData::Flags::VarPropertyType;
+ if (p->isList())
+ propertyFlags.setType(QQmlPropertyData::Flags::QListType);
+ else if (type == QV4::CompiledData::CommonType::Var)
+ propertyFlags.setType(QQmlPropertyData::Flags::VarPropertyType);
-
- if (type != QV4::CompiledData::BuiltinType::InvalidBuiltin) {
- propertyType = metaTypeForPropertyType(type);
+ if (type != QV4::CompiledData::CommonType::Invalid) {
+ propertyType = p->isList()
+ ? listTypeForPropertyType(type)
+ : metaTypeForPropertyType(type);
} else {
- Q_ASSERT(!p->isBuiltinType);
+ Q_ASSERT(!p->isCommonType());
QQmlType qmltype;
bool selfReference = false;
- if (!imports->resolveType(stringAt(p->builtinTypeOrTypeNameIndex), &qmltype, nullptr, nullptr,
- nullptr, QQmlType::AnyRegistrationType, &selfReference)) {
+ if (!imports->resolveType(
+ QQmlTypeLoader::get(enginePrivate),
+ stringAt(p->commonTypeOrTypeNameIndex()), &qmltype, nullptr, nullptr,
+ nullptr, QQmlType::AnyRegistrationType, &selfReference)) {
return qQmlCompileError(p->location, QQmlPropertyCacheCreatorBase::tr("Invalid property type"));
}
// inline components are not necessarily valid yet
- Q_ASSERT(qmltype.isValid() || qmltype.isInlineComponentType());
+ Q_ASSERT(qmltype.isValid());
if (qmltype.isComposite() || qmltype.isInlineComponentType()) {
- CompositeMetaTypeIds typeIds;
+ QQmlType compositeType;
if (qmltype.isInlineComponentType()) {
- auto objectId = qmltype.inlineComponentId();
- auto containingType = qmltype.containingType();
- if (containingType.isValid()) {
- auto icType = containingType.lookupInlineComponentById(objectId);
- typeIds = {icType.typeId(), icType.qListTypeId()};
- } else {
- typeIds = {};
- }
- if (!typeIds.isValid()) // type has not been registered yet, we must be in containing type
- typeIds = objectContainer->typeIdsForComponent(objectId);
- Q_ASSERT(typeIds.isValid());
+ compositeType = qmltype;
+ Q_ASSERT(compositeType.isValid());
} else if (selfReference) {
- typeIds = objectContainer->typeIdsForComponent();
+ compositeType = objectContainer->qmlTypeForComponent();
} else {
- QQmlRefPointer<QQmlTypeData> tdata = enginePrivate->typeLoader.getType(qmltype.sourceUrl());
+ // compositeType may not be the same type as qmlType because multiple engines
+ // may load different types for the same document. Therefore we have to ask
+ // our engine's type loader here.
+ QQmlRefPointer<QQmlTypeData> tdata
+ = enginePrivate->typeLoader.getType(qmltype.sourceUrl());
Q_ASSERT(tdata);
Q_ASSERT(tdata->isComplete());
-
- auto compilationUnit = tdata->compilationUnit();
- typeIds = compilationUnit->typeIdsForComponent();
+ compositeType = tdata->compilationUnit()->qmlTypeForComponent();
}
- if (p->isList) {
- propertyType = typeIds.listId;
+ if (p->isList()) {
+ propertyType = compositeType.qListTypeId();
} else {
- propertyType = typeIds.id;
+ propertyType = compositeType.typeId();
}
} else {
- if (p->isList) {
+ if (p->isList())
propertyType = qmltype.qListTypeId();
- } else {
+ else
propertyType = qmltype.typeId();
- propertyTypeVersion = qmltype.version();
- }
+ propertyTypeVersion = qmltype.version();
}
- if (p->isList)
- propertyFlags.type = QQmlPropertyData::Flags::QListType;
- else
- propertyFlags.type = QQmlPropertyData::Flags::QObjectDerivedType;
+ if (p->isList())
+ propertyFlags.setType(QQmlPropertyData::Flags::QListType);
+ else if (propertyType.flags().testFlag(QMetaType::PointerToQObject))
+ propertyFlags.setType(QQmlPropertyData::Flags::QObjectDerivedType);
}
- if (!p->isReadOnly && !p->isList)
+ if (!p->isReadOnly() && !propertyType.flags().testFlag(QMetaType::IsQmlList))
propertyFlags.setIsWritable(true);
QString propertyName = stringAt(p->nameIndex);
- if (!obj->defaultPropertyIsAlias && propertyIdx == obj->indexOfDefaultPropertyOrAlias)
+ if (!obj->hasAliasAsDefaultProperty() && propertyIdx == obj->indexOfDefaultPropertyOrAlias)
cache->_defaultPropertyName = propertyName;
cache->appendProperty(propertyName, propertyFlags, effectivePropertyIndex++,
propertyType, propertyTypeVersion, effectiveSignalIndex);
@@ -621,37 +767,56 @@ inline QQmlError QQmlPropertyCacheCreator<ObjectContainer>::createMetaObject(int
}
template <typename ObjectContainer>
-inline QMetaType QQmlPropertyCacheCreator<ObjectContainer>::metaTypeForParameter(const QV4::CompiledData::ParameterType &param,
- QString *customTypeName)
+inline QMetaType QQmlPropertyCacheCreator<ObjectContainer>::metaTypeForParameter(
+ const QV4::CompiledData::ParameterType &param, QString *customTypeName)
{
- if (param.indexIsBuiltinType) {
+ const quint32 typeId = param.typeNameIndexOrCommonType();
+ if (param.indexIsCommonType()) {
// built-in type
- return metaTypeForPropertyType(static_cast<QV4::CompiledData::BuiltinType>(int(param.typeNameIndexOrBuiltinType)));
+ if (param.isList())
+ return listTypeForPropertyType(QV4::CompiledData::CommonType(typeId));
+ return metaTypeForPropertyType(QV4::CompiledData::CommonType(typeId));
}
// lazily resolved type
- const QString typeName = stringAt(param.typeNameIndexOrBuiltinType);
+ const QString typeName = stringAt(param.typeNameIndexOrCommonType());
if (customTypeName)
*customTypeName = typeName;
QQmlType qmltype;
bool selfReference = false;
- if (!imports->resolveType(typeName, &qmltype, nullptr, nullptr, nullptr,
- QQmlType::AnyRegistrationType, &selfReference))
+ if (!imports->resolveType(
+ &enginePrivate->typeLoader, typeName, &qmltype, nullptr, nullptr, nullptr,
+ QQmlType::AnyRegistrationType, &selfReference))
return QMetaType();
- if (!qmltype.isComposite())
- return qmltype.typeId();
-
- if (selfReference)
- return objectContainer->typeIdsForComponent().id;
+ if (!qmltype.isComposite()) {
+ const QMetaType typeId = param.isList() ? qmltype.qListTypeId() : qmltype.typeId();
+ if (!typeId.isValid() && qmltype.isInlineComponentType()) {
+ const QQmlType qmlType = objectContainer->qmlTypeForComponent(qmltype.elementName());
+ return param.isList() ? qmlType.qListTypeId() : qmlType.typeId();
+ } else {
+ return typeId;
+ }
+ }
- QQmlRefPointer<QQmlTypeData> tdata = enginePrivate->typeLoader.getType(qmltype.sourceUrl());
- Q_ASSERT(tdata);
- Q_ASSERT(tdata->isComplete());
+ if (selfReference) {
+ const QQmlType qmlType = objectContainer->qmlTypeForComponent();
+ return param.isList() ? qmlType.qListTypeId() : qmlType.typeId();
+ }
- auto compilationUnit = tdata->compilationUnit();
+ return param.isList() ? qmltype.qListTypeId() : qmltype.typeId();
+}
- return compilationUnit->typeIds.id;
+template <typename ObjectContainer, typename CompiledObject>
+int objectForId(const ObjectContainer *objectContainer, const CompiledObject &component, int id)
+{
+ for (quint32 i = 0, count = component.namedObjectsInComponentCount(); i < count; ++i) {
+ const int candidateIndex = component.namedObjectsInComponentTable()[i];
+ const CompiledObject &candidate = *objectContainer->objectAt(candidateIndex);
+ if (candidate.objectId() == id)
+ return candidateIndex;
+ }
+ return -1;
}
template <typename ObjectContainer>
@@ -660,122 +825,27 @@ class QQmlPropertyCacheAliasCreator
public:
typedef typename ObjectContainer::CompiledObject CompiledObject;
- QQmlPropertyCacheAliasCreator(QQmlPropertyCacheVector *propertyCaches, const ObjectContainer *objectContainer);
-
- void appendAliasPropertiesToMetaObjects(QQmlEnginePrivate *enginePriv);
-
- QQmlError appendAliasesToPropertyCache(const CompiledObject &component, int objectIndex, QQmlEnginePrivate *enginePriv);
+ QQmlPropertyCacheAliasCreator(
+ QQmlPropertyCacheVector *propertyCaches, const ObjectContainer *objectContainer);
+ QQmlError appendAliasesToPropertyCache(
+ const CompiledObject &component, int objectIndex, QQmlEnginePrivate *enginePriv);
private:
- void appendAliasPropertiesInMetaObjectsWithinComponent(const CompiledObject &component, int firstObjectIndex, QQmlEnginePrivate *enginePriv);
- QQmlError propertyDataForAlias(const CompiledObject &component, const QV4::CompiledData::Alias &alias, QMetaType *type, QTypeRevision *version, QQmlPropertyData::Flags *propertyFlags, QQmlEnginePrivate *enginePriv);
-
- void collectObjectsWithAliasesRecursively(int objectIndex, QVector<int> *objectsWithAliases) const;
-
- int objectForId(const CompiledObject &component, int id) const;
+ QQmlError propertyDataForAlias(
+ const CompiledObject &component, const QV4::CompiledData::Alias &alias, QMetaType *type,
+ QTypeRevision *version, QQmlPropertyData::Flags *propertyFlags,
+ QQmlEnginePrivate *enginePriv);
QQmlPropertyCacheVector *propertyCaches;
const ObjectContainer *objectContainer;
};
template <typename ObjectContainer>
-inline QQmlPropertyCacheAliasCreator<ObjectContainer>::QQmlPropertyCacheAliasCreator(QQmlPropertyCacheVector *propertyCaches, const ObjectContainer *objectContainer)
+inline QQmlPropertyCacheAliasCreator<ObjectContainer>::QQmlPropertyCacheAliasCreator(
+ QQmlPropertyCacheVector *propertyCaches, const ObjectContainer *objectContainer)
: propertyCaches(propertyCaches)
, objectContainer(objectContainer)
{
-
-}
-
-template <typename ObjectContainer>
-inline void QQmlPropertyCacheAliasCreator<ObjectContainer>::appendAliasPropertiesToMetaObjects(QQmlEnginePrivate *enginePriv)
-{
- // skip the root object (index 0) as that one does not have a first object index originating
- // from a binding.
- for (int i = 1; i < objectContainer->objectCount(); ++i) {
- const CompiledObject &component = *objectContainer->objectAt(i);
- if (!(component.flags & QV4::CompiledData::Object::IsComponent))
- continue;
-
- const auto rootBinding = component.bindingsBegin();
- appendAliasPropertiesInMetaObjectsWithinComponent(component, rootBinding->value.objectIndex, enginePriv);
- }
-
- const int rootObjectIndex = 0;
- appendAliasPropertiesInMetaObjectsWithinComponent(*objectContainer->objectAt(rootObjectIndex), rootObjectIndex, enginePriv);
-}
-
-template <typename ObjectContainer>
-inline void QQmlPropertyCacheAliasCreator<ObjectContainer>::appendAliasPropertiesInMetaObjectsWithinComponent(const CompiledObject &component, int firstObjectIndex, QQmlEnginePrivate *enginePriv)
-{
- QVector<int> objectsWithAliases;
- collectObjectsWithAliasesRecursively(firstObjectIndex, &objectsWithAliases);
- if (objectsWithAliases.isEmpty())
- return;
-
- const auto allAliasTargetsExist = [this, &component](const CompiledObject &object) {
- auto alias = object.aliasesBegin();
- auto end = object.aliasesEnd();
- for ( ; alias != end; ++alias) {
- Q_ASSERT(alias->flags & QV4::CompiledData::Alias::Resolved);
-
- const int targetObjectIndex = objectForId(component, alias->targetObjectId);
- Q_ASSERT(targetObjectIndex >= 0);
-
- if (alias->aliasToLocalAlias)
- continue;
-
- if (alias->encodedMetaPropertyIndex == -1)
- continue;
-
- const QQmlPropertyCache *targetCache = propertyCaches->at(targetObjectIndex);
- Q_ASSERT(targetCache);
-
- int coreIndex = QQmlPropertyIndex::fromEncoded(alias->encodedMetaPropertyIndex).coreIndex();
- QQmlPropertyData *targetProperty = targetCache->property(coreIndex);
- if (!targetProperty)
- return false;
- }
- return true;
- };
-
- do {
- QVector<int> pendingObjects;
-
- for (int objectIndex: qAsConst(objectsWithAliases)) {
- const CompiledObject &object = *objectContainer->objectAt(objectIndex);
-
- if (allAliasTargetsExist(object)) {
- appendAliasesToPropertyCache(component, objectIndex, enginePriv);
- } else {
- pendingObjects.append(objectIndex);
- }
-
- }
- qSwap(objectsWithAliases, pendingObjects);
- } while (!objectsWithAliases.isEmpty());
-}
-
-template <typename ObjectContainer>
-inline void QQmlPropertyCacheAliasCreator<ObjectContainer>::collectObjectsWithAliasesRecursively(int objectIndex, QVector<int> *objectsWithAliases) const
-{
- const CompiledObject &object = *objectContainer->objectAt(objectIndex);
- if (object.aliasCount() > 0)
- objectsWithAliases->append(objectIndex);
-
- // Stop at Component boundary
- if (object.flags & QV4::CompiledData::Object::IsComponent && objectIndex != /*root object*/0)
- return;
-
- auto binding = object.bindingsBegin();
- auto end = object.bindingsEnd();
- for (; binding != end; ++binding) {
- if (binding->type != QV4::CompiledData::Binding::Type_Object
- && binding->type != QV4::CompiledData::Binding::Type_AttachedProperty
- && binding->type != QV4::CompiledData::Binding::Type_GroupProperty)
- continue;
-
- collectObjectsWithAliasesRecursively(binding->value.objectIndex, objectsWithAliases);
- }
}
template <typename ObjectContainer>
@@ -791,12 +861,13 @@ inline QQmlError QQmlPropertyCacheAliasCreator<ObjectContainer>::propertyDataFor
propertyFlags->setIsAlias(true);
- if (alias.aliasToLocalAlias) {
+ if (alias.isAliasToLocalAlias()) {
const QV4::CompiledData::Alias *lastAlias = &alias;
QVarLengthArray<const QV4::CompiledData::Alias *, 4> seenAliases({lastAlias});
do {
- const int targetObjectIndex = objectForId(component, lastAlias->targetObjectId);
+ const int targetObjectIndex = objectForId(
+ objectContainer, component, lastAlias->targetObjectId());
Q_ASSERT(targetObjectIndex >= 0);
const CompiledObject *targetObject = objectContainer->objectAt(targetObjectIndex);
Q_ASSERT(targetObject);
@@ -813,17 +884,18 @@ inline QQmlError QQmlPropertyCacheAliasCreator<ObjectContainer>::propertyDataFor
seenAliases.append(targetAlias);
lastAlias = targetAlias;
- } while (lastAlias->aliasToLocalAlias);
+ } while (lastAlias->isAliasToLocalAlias());
- return propertyDataForAlias(component, *lastAlias, type, version, propertyFlags, enginePriv);
+ return propertyDataForAlias(
+ component, *lastAlias, type, version, propertyFlags, enginePriv);
}
- const int targetObjectIndex = objectForId(component, alias.targetObjectId);
+ const int targetObjectIndex = objectForId(objectContainer, component, alias.targetObjectId());
Q_ASSERT(targetObjectIndex >= 0);
const CompiledObject &targetObject = *objectContainer->objectAt(targetObjectIndex);
if (alias.encodedMetaPropertyIndex == -1) {
- Q_ASSERT(alias.flags & QV4::CompiledData::Alias::AliasPointsToPointerObject);
+ Q_ASSERT(alias.hasFlag(QV4::CompiledData::Alias::AliasPointsToPointerObject));
auto *typeRef = objectContainer->resolvedType(targetObject.inheritedTypeNameIndex);
if (!typeRef) {
// Can be caused by the alias target not being a valid id or property. E.g.:
@@ -834,70 +906,91 @@ inline QQmlError QQmlPropertyCacheAliasCreator<ObjectContainer>::propertyDataFor
}
const auto referencedType = typeRef->type();
- if (referencedType.isValid())
+ if (referencedType.isValid()) {
*type = referencedType.typeId();
- else
- *type = typeRef->compilationUnit()->typeIds.id;
+ if (!type->isValid() && referencedType.isInlineComponentType()) {
+ *type = objectContainer->qmlTypeForComponent(referencedType.elementName()).typeId();
+ Q_ASSERT(type->isValid());
+ }
+ } else {
+ *type = typeRef->compilationUnit()->metaType();
+ }
*version = typeRef->version();
- propertyFlags->type = QQmlPropertyData::Flags::QObjectDerivedType;
+ propertyFlags->setType(QQmlPropertyData::Flags::QObjectDerivedType);
} else {
int coreIndex = QQmlPropertyIndex::fromEncoded(alias.encodedMetaPropertyIndex).coreIndex();
- int valueTypeIndex = QQmlPropertyIndex::fromEncoded(alias.encodedMetaPropertyIndex).valueTypeIndex();
+ int valueTypeIndex = QQmlPropertyIndex::fromEncoded(
+ alias.encodedMetaPropertyIndex).valueTypeIndex();
- QQmlPropertyCache *targetCache = propertyCaches->at(targetObjectIndex);
+ QQmlPropertyCache::ConstPtr targetCache = propertyCaches->at(targetObjectIndex);
Q_ASSERT(targetCache);
- QQmlPropertyData *targetProperty = targetCache->property(coreIndex);
+ const QQmlPropertyData *targetProperty = targetCache->property(coreIndex);
Q_ASSERT(targetProperty);
+ const QMetaType targetPropType = targetProperty->propType();
+
+ const auto populateWithPropertyData = [&](const QQmlPropertyData *property) {
+ *type = property->propType();
+ writable = property->isWritable();
+ resettable = property->isResettable();
+ bindable = property->isBindable();
+
+ if (property->isVarProperty())
+ propertyFlags->setType(QQmlPropertyData::Flags::QVariantType);
+ else
+ propertyFlags->copyPropertyTypeFlags(property->flags());
+ };
+
// for deep aliases, valueTypeIndex is always set
- if (!QQmlMetaType::isValueType(targetProperty->propType()) && valueTypeIndex != -1) {
+ if (!QQmlMetaType::isValueType(targetPropType) && valueTypeIndex != -1) {
// deep alias property
- *type = targetProperty->propType();
- targetCache = enginePriv->propertyCacheForType(type->id());
- Q_ASSERT(targetCache);
- targetProperty = targetCache->property(valueTypeIndex);
-
- if (targetProperty == nullptr) {
- return qQmlCompileError(alias.referenceLocation,
- QQmlPropertyCacheCreatorBase::tr("Invalid alias target"));
+
+ QQmlPropertyCache::ConstPtr typeCache
+ = QQmlMetaType::propertyCacheForType(targetPropType);
+
+ if (!typeCache) {
+ // See if it's a half-resolved composite type
+ if (const QV4::ResolvedTypeReference *typeRef
+ = objectContainer->resolvedType(targetPropType)) {
+ typeCache = typeRef->typePropertyCache();
+ }
}
- *type = targetProperty->propType();
- writable = targetProperty->isWritable();
- resettable = targetProperty->isResettable();
- bindable = targetProperty->isBindable();
+ const QQmlPropertyData *typeProperty = typeCache
+ ? typeCache->property(valueTypeIndex)
+ : nullptr;
+ if (typeProperty == nullptr) {
+ return qQmlCompileError(
+ alias.referenceLocation,
+ QQmlPropertyCacheCreatorBase::tr("Invalid alias target"));
+ }
+ populateWithPropertyData(typeProperty);
} else {
// value type or primitive type or enum
- *type = targetProperty->propType();
-
- writable = targetProperty->isWritable();
- resettable = targetProperty->isResettable();
- bindable = targetProperty->isBindable();
+ populateWithPropertyData(targetProperty);
if (valueTypeIndex != -1) {
- const QMetaObject *valueTypeMetaObject = QQmlMetaType::metaObjectForMetaType(*type);
- if (valueTypeMetaObject->property(valueTypeIndex).isEnumType())
- *type = QMetaType::fromType<int>();
- else
- *type = valueTypeMetaObject->property(valueTypeIndex).metaType();
- } else {
- if (targetProperty->isEnum()) {
- *type = QMetaType::fromType<int>();
- } else {
- // Copy type flags
- propertyFlags->copyPropertyTypeFlags(targetProperty->flags());
-
- if (targetProperty->isVarProperty())
- propertyFlags->type = QQmlPropertyData::Flags::QVariantType;
- }
+ const QMetaObject *valueTypeMetaObject
+ = QQmlMetaType::metaObjectForValueType(*type);
+ const QMetaProperty valueTypeMetaProperty
+ = valueTypeMetaObject->property(valueTypeIndex);
+ *type = valueTypeMetaProperty.metaType();
+
+ // We can only write or reset the value type property if we can write
+ // the value type itself.
+ resettable = writable && valueTypeMetaProperty.isResettable();
+ writable = writable && valueTypeMetaProperty.isWritable();
+
+ bindable = valueTypeMetaProperty.isBindable();
}
}
}
- propertyFlags->setIsWritable(!(alias.flags & QV4::CompiledData::Alias::IsReadOnly) && writable);
+ propertyFlags->setIsWritable(
+ writable && !alias.hasFlag(QV4::CompiledData::Alias::IsReadOnly));
propertyFlags->setIsResettable(resettable);
propertyFlags->setIsBindable(bindable);
return QQmlError();
@@ -911,17 +1004,17 @@ inline QQmlError QQmlPropertyCacheAliasCreator<ObjectContainer>::appendAliasesTo
if (!object.aliasCount())
return QQmlError();
- QQmlPropertyCache *propertyCache = propertyCaches->at(objectIndex);
+ QQmlPropertyCache::Ptr propertyCache = propertyCaches->ownAt(objectIndex);
Q_ASSERT(propertyCache);
- int effectiveSignalIndex = propertyCache->signalHandlerIndexCacheStart + propertyCache->propertyIndexCache.count();
- int effectivePropertyIndex = propertyCache->propertyIndexCacheStart + propertyCache->propertyIndexCache.count();
+ int effectiveSignalIndex = propertyCache->signalHandlerIndexCacheStart + propertyCache->propertyIndexCache.size();
+ int effectivePropertyIndex = propertyCache->propertyIndexCacheStart + propertyCache->propertyIndexCache.size();
int aliasIndex = 0;
auto alias = object.aliasesBegin();
auto end = object.aliasesEnd();
for ( ; alias != end; ++alias, ++aliasIndex) {
- Q_ASSERT(alias->flags & QV4::CompiledData::Alias::Resolved);
+ Q_ASSERT(alias->hasFlag(QV4::CompiledData::Alias::Resolved));
QMetaType type;
QTypeRevision version = QTypeRevision::zero();
@@ -931,9 +1024,9 @@ inline QQmlError QQmlPropertyCacheAliasCreator<ObjectContainer>::appendAliasesTo
if (error.isValid())
return error;
- const QString propertyName = objectContainer->stringAt(alias->nameIndex);
+ const QString propertyName = objectContainer->stringAt(alias->nameIndex());
- if (object.defaultPropertyIsAlias && aliasIndex == object.indexOfDefaultPropertyOrAlias)
+ if (object.hasAliasAsDefaultProperty() && aliasIndex == object.indexOfDefaultPropertyOrAlias)
propertyCache->_defaultPropertyName = propertyName;
propertyCache->appendProperty(propertyName, propertyFlags, effectivePropertyIndex++,
@@ -943,18 +1036,6 @@ inline QQmlError QQmlPropertyCacheAliasCreator<ObjectContainer>::appendAliasesTo
return QQmlError();
}
-template <typename ObjectContainer>
-inline int QQmlPropertyCacheAliasCreator<ObjectContainer>::objectForId(const CompiledObject &component, int id) const
-{
- for (quint32 i = 0, count = component.namedObjectsInComponentCount(); i < count; ++i) {
- const int candidateIndex = component.namedObjectsInComponentTable()[i];
- const CompiledObject &candidate = *objectContainer->objectAt(candidateIndex);
- if (candidate.id == id)
- return candidateIndex;
- }
- return -1;
-}
-
QT_END_NAMESPACE
#endif // QQMLPROPERTYCACHECREATOR_P_H
diff --git a/src/qml/qml/qqmlpropertycachemethodarguments_p.h b/src/qml/qml/qqmlpropertycachemethodarguments_p.h
index 3e3666e2e6..ab17c01379 100644
--- a/src/qml/qml/qqmlpropertycachemethodarguments_p.h
+++ b/src/qml/qml/qqmlpropertycachemethodarguments_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 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$
-**
-****************************************************************************/
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLPROPERTYCACHEMETODARGUMENTS_P_H
#define QQMLPROPERTYCACHEMETODARGUMENTS_P_H
@@ -53,6 +17,9 @@
#include <QtCore/qlist.h>
#include <QtCore/qbytearray.h>
+#include <QtCore/qtaggedpointer.h>
+#include <QtCore/qmetatype.h>
+#include <QtCore/private/qglobal_p.h>
QT_BEGIN_NAMESPACE
@@ -61,14 +28,8 @@ class QQmlPropertyCacheMethodArguments
{
public:
QQmlPropertyCacheMethodArguments *next;
-
- //for signal handler rewrites
- int parameterError:1;
- int argumentsValid:1;
-
QList<QByteArray> *names;
-
- int arguments[1];
+ QMetaType types[1]; // First one is return type
};
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlpropertycachevector_p.h b/src/qml/qml/qqmlpropertycachevector_p.h
index 2e09423206..1cee914220 100644
--- a/src/qml/qml/qqmlpropertycachevector_p.h
+++ b/src/qml/qml/qqmlpropertycachevector_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 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$
-**
-****************************************************************************/
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLPROPERTYCACHEVECTOR_P_H
#define QQMLPROPERTYCACHEVECTOR_P_H
@@ -51,8 +15,8 @@
// We mean it.
//
-#include <private/qflagpointer_p.h>
#include <private/qqmlpropertycache_p.h>
+#include <private/qbipointer_p.h>
#include <QtCore/qtaggedpointer.h>
@@ -61,49 +25,119 @@ QT_BEGIN_NAMESPACE
class QQmlPropertyCacheVector
{
public:
- enum Tag {
- NoTag,
- CacheNeedsVMEMetaObject
- };
-
- QQmlPropertyCacheVector() {}
- QQmlPropertyCacheVector(QQmlPropertyCacheVector &&other)
- : data(std::move(other.data)) {}
- QQmlPropertyCacheVector &operator=(QQmlPropertyCacheVector &&other) {
- QVector<QTaggedPointer<QQmlPropertyCache, Tag>> moved(std::move(other.data));
- data.swap(moved);
- return *this;
- }
+ QQmlPropertyCacheVector() = default;
+ QQmlPropertyCacheVector(QQmlPropertyCacheVector &&) = default;
+ QQmlPropertyCacheVector &operator=(QQmlPropertyCacheVector &&) = default;
~QQmlPropertyCacheVector() { clear(); }
- void resize(int size) { return data.resize(size); }
- int count() const { return data.count(); }
+ void resize(int size)
+ {
+ Q_ASSERT(size >= data.size());
+ return data.resize(size);
+ }
+
+ int count() const {
+ // the property cache vector will never contain more thant INT_MAX many elements
+ return int(data.size());
+ }
void clear()
{
- for (int i = 0; i < data.count(); ++i) {
- if (QQmlPropertyCache *cache = data.at(i).data())
- cache->release();
- }
+ for (int i = 0; i < data.size(); ++i)
+ releaseElement(i);
data.clear();
}
- void append(QQmlPropertyCache *cache) { cache->addref(); data.append(QTaggedPointer<QQmlPropertyCache, Tag>(cache)); }
- QQmlPropertyCache *at(int index) const { return data.at(index).data(); }
- void set(int index, const QQmlRefPointer<QQmlPropertyCache> &replacement) {
- if (QQmlPropertyCache *oldCache = data.at(index).data()) {
- if (replacement.data() == oldCache)
+ void resetAndResize(int size)
+ {
+ for (int i = 0; i < data.size(); ++i) {
+ releaseElement(i);
+ data[i] = BiPointer();
+ }
+ data.resize(size);
+ }
+
+ void append(const QQmlPropertyCache::ConstPtr &cache) {
+ cache->addref();
+ data.append(BiPointer(cache.data()));
+ Q_ASSERT(data.last().isT1());
+ Q_ASSERT(data.size() <= std::numeric_limits<int>::max());
+ }
+
+ void appendOwn(const QQmlPropertyCache::Ptr &cache) {
+ cache->addref();
+ data.append(BiPointer(cache.data()));
+ Q_ASSERT(data.last().isT2());
+ Q_ASSERT(data.size() <= std::numeric_limits<int>::max());
+ }
+
+ QQmlPropertyCache::ConstPtr at(int index) const
+ {
+ const auto entry = data.at(index);
+ if (entry.isT2())
+ return entry.asT2();
+ return entry.asT1();
+ }
+
+ QQmlPropertyCache::Ptr ownAt(int index) const
+ {
+ const auto entry = data.at(index);
+ if (entry.isT2())
+ return entry.asT2();
+ return QQmlPropertyCache::Ptr();
+ }
+
+ void set(int index, const QQmlPropertyCache::ConstPtr &replacement) {
+ if (QQmlPropertyCache::ConstPtr oldCache = at(index)) {
+ // If it is our own, we keep it our own
+ if (replacement.data() == oldCache.data())
return;
oldCache->release();
}
data[index] = replacement.data();
replacement->addref();
+ Q_ASSERT(data[index].isT1());
+ }
+
+ void setOwn(int index, const QQmlPropertyCache::Ptr &replacement) {
+ if (QQmlPropertyCache::ConstPtr oldCache = at(index)) {
+ if (replacement.data() != oldCache.data()) {
+ oldCache->release();
+ replacement->addref();
+ }
+ } else {
+ replacement->addref();
+ }
+ data[index] = replacement.data();
+ Q_ASSERT(data[index].isT2());
+ }
+
+ void setNeedsVMEMetaObject(int index) { data[index].setFlag(); }
+ bool needsVMEMetaObject(int index) const { return data.at(index).flag(); }
+
+ void seal()
+ {
+ for (auto &entry: data) {
+ if (entry.isT2())
+ entry = static_cast<const QQmlPropertyCache *>(entry.asT2());
+ Q_ASSERT(entry.isT1());
+ }
}
- void setNeedsVMEMetaObject(int index) { data[index].setTag(CacheNeedsVMEMetaObject); }
- bool needsVMEMetaObject(int index) const { return data.at(index).tag() == CacheNeedsVMEMetaObject; }
private:
+ void releaseElement(int i)
+ {
+ const auto &cache = data.at(i);
+ if (cache.isT2()) {
+ if (QQmlPropertyCache *data = cache.asT2())
+ data->release();
+ } else if (const QQmlPropertyCache *data = cache.asT1()) {
+ data->release();
+ }
+ }
+
Q_DISABLE_COPY(QQmlPropertyCacheVector)
- QVector<QTaggedPointer<QQmlPropertyCache, Tag>> data;
+ using BiPointer = QBiPointer<const QQmlPropertyCache, QQmlPropertyCache>;
+ QVector<BiPointer> data;
};
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlpropertydata_p.h b/src/qml/qml/qqmlpropertydata_p.h
index 4decbf6e21..0fa7984f05 100644
--- a/src/qml/qml/qqmlpropertydata_p.h
+++ b/src/qml/qml/qqmlpropertydata_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 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$
-**
-****************************************************************************/
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLPROPERTYDATA_P_H
#define QQMLPROPERTYDATA_P_H
@@ -64,7 +28,8 @@ public:
enum WriteFlag {
BypassInterceptor = 0x01,
DontRemoveBinding = 0x02,
- RemoveBindingOnAliasWrite = 0x04
+ RemoveBindingOnAliasWrite = 0x04,
+ HasInternalIndex = 0x8,
};
Q_DECLARE_FLAGS(WriteFlags, WriteFlag)
@@ -72,19 +37,18 @@ public:
struct Flags {
friend class QQmlPropertyData;
- enum Types {
+ enum Type {
OtherType = 0,
FunctionType = 1, // Is an invokable
QObjectDerivedType = 2, // Property type is a QObject* derived type
EnumType = 3, // Property type is an enum
QListType = 4, // Property type is a QML list
- QmlBindingType = 5, // Property type is a QQmlBinding*
- QJSValueType = 6, // Property type is a QScriptValue
- // Gap, used to be V4HandleType
- VarPropertyType = 8, // Property type is a "var" property of VMEMO
- QVariantType = 9 // Property is a QVariant
+ VarPropertyType = 5, // Property type is a "var" property of VMEMO
+ QVariantType = 6, // Property is a QVariant
+ // One spot left for an extra type in the 3 bits used to store this.
};
+ private:
// The _otherBits (which "pad" the Flags struct to align it nicely) are used
// to store the relative property index. It will only get used when said index fits. See
// trySetStaticMetaCallFunction for details.
@@ -97,38 +61,38 @@ public:
// b when type equals FunctionType. For that reason, the semantic meaning of the bit is
// overloaded, and the accessor functions are used to get the correct value
//
- // Moreover, isSignalHandler, isOverload and isCloned make only sense
+ // Moreover, isSignalHandler, isOverridableSignal and isCloned make only sense
// for functions, too (and could at a later point be reused for flags that only make sense
// for non-functions)
//
// Lastly, isDirect and isOverridden apply to both functions and non-functions
- private:
- unsigned isConstantORisVMEFunction : 1; // Has CONST flag OR Function was added by QML
+ unsigned isConst : 1; // Property: has CONST flag/Method: is const
+ unsigned isVMEFunction : 1; // Function was added by QML
unsigned isWritableORhasArguments : 1; // Has WRITE function OR Function takes arguments
unsigned isResettableORisSignal : 1; // Has RESET function OR Function is a signal
unsigned isAliasORisVMESignal : 1; // Is a QML alias to another property OR Signal was added by QML
- unsigned isFinalORisV4Function : 1; // Has FINAL flag OR Function takes QQmlV4Function* args
+ unsigned isFinalORisV4Function : 1; // Has FINAL flag OR Function takes QQmlV4FunctionPtr args
unsigned isSignalHandler : 1; // Function is a signal handler
- unsigned isOverload : 1; // Function is an overload of another function
+
+ // TODO: Remove this once we can. Signals should not be overridable.
+ unsigned isOverridableSignal : 1; // Function is an overridable signal
+
unsigned isRequiredORisCloned : 1; // Has REQUIRED flag OR The function was marked as cloned
- unsigned isConstructorORisBindable : 1; // The function was marked is a constructor OR property is backed by QProperty<T>
- unsigned isDirect : 1; // Exists on a C++ QMetaObject
+ unsigned isConstructorORisBindable : 1; // The function was marked is a constructor OR property is backed by QProperty<T>
unsigned isOverridden : 1; // Is overridden by a extension property
- public:
- unsigned type : 4; // stores an entry of Types
-
- // Apply only to IsFunctions
+ unsigned hasMetaObject : 1;
+ unsigned type : 3; // stores an entry of Types
// Internal QQmlPropertyCache flags
- unsigned overrideIndexIsProperty: 1;
+ unsigned overrideIndexIsProperty : 1;
+ public:
inline Flags();
inline bool operator==(const Flags &other) const;
inline void copyPropertyTypeFlags(Flags from);
void setIsConstant(bool b) {
- Q_ASSERT(type != FunctionType);
- isConstantORisVMEFunction = b;
+ isConst = b;
}
void setIsWritable(bool b) {
@@ -160,10 +124,6 @@ public:
isConstructorORisBindable = b;
}
- void setIsDirect(bool b) {
- isDirect = b;
- }
-
void setIsRequired(bool b) {
Q_ASSERT(type != FunctionType);
isRequiredORisCloned = b;
@@ -171,7 +131,7 @@ public:
void setIsVMEFunction(bool b) {
Q_ASSERT(type == FunctionType);
- isConstantORisVMEFunction = b;
+ isVMEFunction = b;
}
void setHasArguments(bool b) {
Q_ASSERT(type == FunctionType);
@@ -196,9 +156,11 @@ public:
isSignalHandler = b;
}
- void setIsOverload(bool b) {
+ // TODO: Remove this once we can. Signals should not be overridable.
+ void setIsOverridableSignal(bool b) {
Q_ASSERT(type == FunctionType);
- isOverload = b;
+ Q_ASSERT(isResettableORisSignal);
+ isOverridableSignal = b;
}
void setIsCloned(bool b) {
@@ -211,6 +173,13 @@ public:
isConstructorORisBindable = b;
}
+ void setHasMetaObject(bool b) {
+ hasMetaObject = b;
+ }
+
+ void setType(Type newType) {
+ type = newType;
+ }
};
@@ -226,32 +195,32 @@ public:
bool isValid() const { return coreIndex() != -1; }
- bool isConstant() const { return !isFunction() && m_flags.isConstantORisVMEFunction; }
+ bool isConstant() const { return m_flags.isConst; }
bool isWritable() const { return !isFunction() && m_flags.isWritableORhasArguments; }
void setWritable(bool onoff) { Q_ASSERT(!isFunction()); m_flags.isWritableORhasArguments = onoff; }
bool isResettable() const { return !isFunction() && m_flags.isResettableORisSignal; }
bool isAlias() const { return !isFunction() && m_flags.isAliasORisVMESignal; }
bool isFinal() const { return !isFunction() && m_flags.isFinalORisV4Function; }
bool isOverridden() const { return m_flags.isOverridden; }
- bool isDirect() const { return m_flags.isDirect; }
bool isRequired() const { return !isFunction() && m_flags.isRequiredORisCloned; }
bool hasStaticMetaCallFunction() const { return staticMetaCallFunction() != nullptr; }
bool isFunction() const { return m_flags.type == Flags::FunctionType; }
bool isQObject() const { return m_flags.type == Flags::QObjectDerivedType; }
bool isEnum() const { return m_flags.type == Flags::EnumType; }
bool isQList() const { return m_flags.type == Flags::QListType; }
- bool isQmlBinding() const { return m_flags.type == Flags::QmlBindingType; }
- bool isQJSValue() const { return m_flags.type == Flags::QJSValueType; }
bool isVarProperty() const { return m_flags.type == Flags::VarPropertyType; }
bool isQVariant() const { return m_flags.type == Flags::QVariantType; }
- bool isVMEFunction() const { return isFunction() && m_flags.isConstantORisVMEFunction; }
+ bool isVMEFunction() const { return isFunction() && m_flags.isVMEFunction; }
bool hasArguments() const { return isFunction() && m_flags.isWritableORhasArguments; }
bool isSignal() const { return isFunction() && m_flags.isResettableORisSignal; }
bool isVMESignal() const { return isFunction() && m_flags.isAliasORisVMESignal; }
bool isV4Function() const { return isFunction() && m_flags.isFinalORisV4Function; }
bool isSignalHandler() const { return m_flags.isSignalHandler; }
- bool isOverload() const { return m_flags.isOverload; }
- void setOverload(bool onoff) { m_flags.isOverload = onoff; }
+ bool hasMetaObject() const { return m_flags.hasMetaObject; }
+
+ // TODO: Remove this once we can. Signals should not be overridable.
+ bool isOverridableSignal() const { return m_flags.isOverridableSignal; }
+
bool isCloned() const { return isFunction() && m_flags.isRequiredORisCloned; }
bool isConstructor() const { return isFunction() && m_flags.isConstructorORisBindable; }
bool isBindable() const { return !isFunction() && m_flags.isConstructorORisBindable; }
@@ -316,8 +285,36 @@ public:
QTypeRevision typeVersion() const { return m_typeVersion; }
void setTypeVersion(QTypeRevision typeVersion) { m_typeVersion = typeVersion; }
- QQmlPropertyCacheMethodArguments *arguments() const { return m_arguments; }
- void setArguments(QQmlPropertyCacheMethodArguments *args) { m_arguments = args; }
+ QQmlPropertyCacheMethodArguments *arguments() const
+ {
+ Q_ASSERT(!hasMetaObject());
+ return m_arguments;
+ }
+ void setArguments(QQmlPropertyCacheMethodArguments *args)
+ {
+ Q_ASSERT(!hasMetaObject());
+ m_arguments = args;
+ }
+
+ const QMetaObject *metaObject() const
+ {
+ Q_ASSERT(hasMetaObject());
+ return m_metaObject;
+ }
+
+ void setMetaObject(const QMetaObject *metaObject)
+ {
+ Q_ASSERT(!hasArguments() || !m_arguments);
+ m_flags.setHasMetaObject(true);
+ m_metaObject = metaObject;
+ }
+
+ QMetaMethod metaMethod() const
+ {
+ Q_ASSERT(hasMetaObject());
+ Q_ASSERT(isFunction());
+ return m_metaObject->method(m_coreIndex);
+ }
int metaObjectOffset() const { return m_metaObjectOffset; }
void setMetaObjectOffset(int off)
@@ -327,9 +324,10 @@ public:
m_metaObjectOffset = qint16(off);
}
- StaticMetaCallFunction staticMetaCallFunction() const { return m_staticMetaCallFunction; }
+ StaticMetaCallFunction staticMetaCallFunction() const { Q_ASSERT(!isFunction()); return m_staticMetaCallFunction; }
void trySetStaticMetaCallFunction(StaticMetaCallFunction f, unsigned relativePropertyIndex)
{
+ Q_ASSERT(!isFunction());
if (relativePropertyIndex < (1 << Flags::BitsLeftInFlags) - 1) {
m_flags.otherBits = relativePropertyIndex;
m_staticMetaCallFunction = f;
@@ -343,7 +341,7 @@ public:
QString name(QObject *) const;
QString name(const QMetaObject *) const;
- void markAsOverrideOf(QQmlPropertyData *predecessor);
+ bool markAsOverrideOf(QQmlPropertyData *predecessor);
inline void readProperty(QObject *target, void *property) const
{
@@ -351,14 +349,23 @@ public:
readPropertyWithArgs(target, args);
}
- inline void readPropertyWithArgs(QObject *target, void *args[]) const
+ // This is the same as QMetaObject::metacall(), but inlined here to avoid a function call.
+ // And we ignore the return value.
+ template<QMetaObject::Call call>
+ void doMetacall(QObject *object, int idx, void **argv) const
+ {
+ if (QDynamicMetaObjectData *dynamicMetaObject = QObjectPrivate::get(object)->metaObject)
+ dynamicMetaObject->metaCall(object, call, idx, argv);
+ else
+ object->qt_metacall(call, idx, argv);
+ }
+
+ void readPropertyWithArgs(QObject *target, void *args[]) const
{
if (hasStaticMetaCallFunction())
staticMetaCallFunction()(target, QMetaObject::ReadProperty, relativePropertyIndex(), args);
- else if (isDirect())
- target->qt_metacall(QMetaObject::ReadProperty, coreIndex(), args);
else
- QMetaObject::metacall(target, QMetaObject::ReadProperty, coreIndex(), args);
+ doMetacall<QMetaObject::ReadProperty>(target, coreIndex(), args);
}
bool writeProperty(QObject *target, void *value, WriteFlags flags) const
@@ -367,17 +374,24 @@ public:
void *argv[] = { value, nullptr, &status, &flags };
if (flags.testFlag(BypassInterceptor) && hasStaticMetaCallFunction())
staticMetaCallFunction()(target, QMetaObject::WriteProperty, relativePropertyIndex(), argv);
- else if (flags.testFlag(BypassInterceptor) && isDirect())
- target->qt_metacall(QMetaObject::WriteProperty, coreIndex(), argv);
else
- QMetaObject::metacall(target, QMetaObject::WriteProperty, coreIndex(), argv);
+ doMetacall<QMetaObject::WriteProperty>(target, coreIndex(), argv);
+ return true;
+ }
+
+ bool resetProperty(QObject *target, WriteFlags flags) const
+ {
+ if (flags.testFlag(BypassInterceptor) && hasStaticMetaCallFunction())
+ staticMetaCallFunction()(target, QMetaObject::ResetProperty, relativePropertyIndex(), nullptr);
+ else
+ doMetacall<QMetaObject::ResetProperty>(target, coreIndex(), nullptr);
return true;
}
static Flags defaultSignalFlags()
{
Flags f;
- f.type = Flags::FunctionType;
+ f.setType(Flags::FunctionType);
f.setIsSignal(true);
f.setIsVMESignal(true);
return f;
@@ -386,15 +400,13 @@ public:
static Flags defaultSlotFlags()
{
Flags f;
- f.type = Flags::FunctionType;
+ f.setType(Flags::FunctionType);
f.setIsVMEFunction(true);
return f;
}
private:
friend class QQmlPropertyCache;
- void lazyLoad(const QMetaProperty &);
- void lazyLoad(const QMetaMethod &);
Flags m_flags;
qint16 m_coreIndex = -1;
@@ -411,16 +423,21 @@ private:
QMetaType m_propType = {};
- QQmlPropertyCacheMethodArguments *m_arguments = nullptr;
- StaticMetaCallFunction m_staticMetaCallFunction = nullptr;
+ union {
+ QQmlPropertyCacheMethodArguments *m_arguments = nullptr;
+ StaticMetaCallFunction m_staticMetaCallFunction;
+ const QMetaObject *m_metaObject;
+ };
};
#if QT_POINTER_SIZE == 4
- Q_STATIC_ASSERT(sizeof(QQmlPropertyData) == 28);
+ Q_STATIC_ASSERT(sizeof(QQmlPropertyData) == 24);
#else // QT_POINTER_SIZE == 8
- Q_STATIC_ASSERT(sizeof(QQmlPropertyData) == 40);
+ Q_STATIC_ASSERT(sizeof(QQmlPropertyData) == 32);
#endif
+static_assert(std::is_trivially_copyable<QQmlPropertyData>::value);
+
bool QQmlPropertyData::operator==(const QQmlPropertyData &other) const
{
return flags() == other.flags() &&
@@ -432,24 +449,27 @@ bool QQmlPropertyData::operator==(const QQmlPropertyData &other) const
QQmlPropertyData::Flags::Flags()
: otherBits(0)
- , isConstantORisVMEFunction(false)
+ , isConst(false)
+ , isVMEFunction(false)
, isWritableORhasArguments(false)
, isResettableORisSignal(false)
, isAliasORisVMESignal(false)
, isFinalORisV4Function(false)
, isSignalHandler(false)
- , isOverload(false)
+ , isOverridableSignal(false)
, isRequiredORisCloned(false)
, isConstructorORisBindable(false)
- , isDirect(false)
, isOverridden(false)
+ , hasMetaObject(false)
, type(OtherType)
, overrideIndexIsProperty(false)
-{}
+{
+}
bool QQmlPropertyData::Flags::operator==(const QQmlPropertyData::Flags &other) const
{
- return isConstantORisVMEFunction == other.isConstantORisVMEFunction &&
+ return isConst == other.isConst &&
+ isVMEFunction == other.isVMEFunction &&
isWritableORhasArguments == other.isWritableORhasArguments &&
isResettableORisSignal == other.isResettableORisSignal &&
isAliasORisVMESignal == other.isAliasORisVMESignal &&
@@ -457,6 +477,7 @@ bool QQmlPropertyData::Flags::operator==(const QQmlPropertyData::Flags &other) c
isOverridden == other.isOverridden &&
isSignalHandler == other.isSignalHandler &&
isRequiredORisCloned == other.isRequiredORisCloned &&
+ hasMetaObject == other.hasMetaObject &&
type == other.type &&
isConstructorORisBindable == other.isConstructorORisBindable &&
overrideIndexIsProperty == other.overrideIndexIsProperty;
@@ -468,8 +489,6 @@ void QQmlPropertyData::Flags::copyPropertyTypeFlags(QQmlPropertyData::Flags from
case QObjectDerivedType:
case EnumType:
case QListType:
- case QmlBindingType:
- case QJSValueType:
case QVariantType:
type = from.type;
}
diff --git a/src/qml/qml/qqmlpropertyindex_p.h b/src/qml/qml/qqmlpropertyindex_p.h
index ebc1828efb..ca63cbf881 100644
--- a/src/qml/qml/qqmlpropertyindex_p.h
+++ b/src/qml/qml/qqmlpropertyindex_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLPROPERTYINDEX_P_H
#define QQMLPROPERTYINDEX_P_H
diff --git a/src/qml/qml/qqmlpropertyresolver.cpp b/src/qml/qml/qqmlpropertyresolver.cpp
index 396f2876b9..0217f7b7b5 100644
--- a/src/qml/qml/qqmlpropertyresolver.cpp
+++ b/src/qml/qml/qqmlpropertyresolver.cpp
@@ -1,53 +1,18 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the tools applications 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$
-**
-****************************************************************************/
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qqmlpropertyresolver_p.h"
#include <private/qqmlcontextdata_p.h>
+#include <private/qqmlsignalnames_p.h>
QT_BEGIN_NAMESPACE
-QQmlPropertyData *QQmlPropertyResolver::property(const QString &name, bool *notInRevision,
+const QQmlPropertyData *QQmlPropertyResolver::property(const QString &name, bool *notInRevision,
RevisionCheck check) const
{
if (notInRevision) *notInRevision = false;
- QQmlPropertyData *d = cache->property(name, nullptr, nullptr);
+ const QQmlPropertyData *d = cache->property(name, nullptr, nullptr);
// Find the first property
while (d && d->isFunction())
@@ -62,11 +27,11 @@ QQmlPropertyData *QQmlPropertyResolver::property(const QString &name, bool *notI
}
-QQmlPropertyData *QQmlPropertyResolver::signal(const QString &name, bool *notInRevision) const
+const QQmlPropertyData *QQmlPropertyResolver::signal(const QString &name, bool *notInRevision) const
{
if (notInRevision) *notInRevision = false;
- QQmlPropertyData *d = cache->property(name, nullptr, nullptr);
+ const QQmlPropertyData *d = cache->property(name, nullptr, nullptr);
if (notInRevision) *notInRevision = false;
while (d && !(d->isFunction()))
@@ -79,10 +44,8 @@ QQmlPropertyData *QQmlPropertyResolver::signal(const QString &name, bool *notInR
return d;
}
- if (name.endsWith(QLatin1String("Changed"))) {
- QString propName = name.mid(0, name.length() - static_cast<int>(strlen("Changed")));
-
- d = property(propName, notInRevision);
+ if (auto propName = QQmlSignalNames::changedSignalNameToPropertyName(name)) {
+ d = property(*propName, notInRevision);
if (d)
return cache->signal(d->notifyIndex());
}
diff --git a/src/qml/qml/qqmlpropertyresolver_p.h b/src/qml/qml/qqmlpropertyresolver_p.h
index df857f242e..4c9ae4a8af 100644
--- a/src/qml/qml/qqmlpropertyresolver_p.h
+++ b/src/qml/qml/qqmlpropertyresolver_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the tools applications 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$
-**
-****************************************************************************/
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLPROPERTYRESOLVER_P_H
#define QQMLPROPERTYRESOLVER_P_H
@@ -59,11 +23,11 @@ QT_BEGIN_NAMESPACE
struct Q_QML_EXPORT QQmlPropertyResolver
{
- QQmlPropertyResolver(const QQmlRefPointer<QQmlPropertyCache> &cache)
+ QQmlPropertyResolver(const QQmlPropertyCache::ConstPtr &cache)
: cache(cache)
{}
- QQmlPropertyData *property(int index) const
+ const QQmlPropertyData *property(int index) const
{
return cache->property(index);
}
@@ -73,13 +37,13 @@ struct Q_QML_EXPORT QQmlPropertyResolver
IgnoreRevision
};
- QQmlPropertyData *property(const QString &name, bool *notInRevision = nullptr,
+ const QQmlPropertyData *property(const QString &name, bool *notInRevision = nullptr,
RevisionCheck check = CheckRevision) const;
// This code must match the semantics of QQmlPropertyPrivate::findSignalByName
- QQmlPropertyData *signal(const QString &name, bool *notInRevision) const;
+ const QQmlPropertyData *signal(const QString &name, bool *notInRevision) const;
- QQmlRefPointer<QQmlPropertyCache> cache;
+ QQmlPropertyCache::ConstPtr cache;
};
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlpropertytopropertybinding.cpp b/src/qml/qml/qqmlpropertytopropertybinding.cpp
new file mode 100644
index 0000000000..ec77e8c97a
--- /dev/null
+++ b/src/qml/qml/qqmlpropertytopropertybinding.cpp
@@ -0,0 +1,128 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qqmlpropertytopropertybinding_p.h"
+#include <private/qqmlvmemetaobject_p.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ * \internal
+ * \class QQmlPropertyToPropertyBinding
+ *
+ * This class can be used to create a direct binding from a source property to
+ * a target property, without going through QQmlJavaScriptExpression and
+ * QV4::Function. In particular you don't need a compilation unit or byte code
+ * to set this up.
+ */
+
+QQmlPropertyToPropertyBinding::QQmlPropertyToPropertyBinding(
+ QQmlEngine *engine, QObject *sourceObject, int sourcePropertyIndex,
+ QObject *targetObject, int targetPropertyIndex)
+ : QQmlNotifierEndpoint(QQmlPropertyGuard)
+ , m_engine(engine)
+ , m_sourceObject(sourceObject)
+ , m_sourcePropertyIndex(sourcePropertyIndex)
+{
+ setTarget(targetObject, targetPropertyIndex, false, -1);
+}
+
+QQmlAbstractBinding::Kind QQmlPropertyToPropertyBinding::kind() const
+{
+ return PropertyToPropertyBinding;
+}
+
+void QQmlPropertyToPropertyBinding::setEnabled(bool e, QQmlPropertyData::WriteFlags flags)
+{
+ const bool wasEnabled = enabledFlag();
+ setEnabledFlag(e);
+ updateCanUseAccessor();
+ if (e && !wasEnabled)
+ update(flags);
+}
+
+void QQmlPropertyToPropertyBinding::captureProperty(
+ const QMetaObject *sourceMetaObject, int notifyIndex,
+ bool isSourceBindable, bool isTargetBindable)
+{
+ if (isSourceBindable) {
+ // if the property is a QPropery, and we're binding to a QProperty
+ // the automatic capturing process already takes care of everything
+ if (isTargetBindable)
+ return;
+
+ // We have already captured.
+ if (observer)
+ return;
+
+ observer = std::make_unique<Observer>(this);
+ QUntypedBindable bindable;
+ void *argv[] = { &bindable };
+ sourceMetaObject->metacall(
+ m_sourceObject, QMetaObject::BindableProperty, m_sourcePropertyIndex, argv);
+ bindable.observe(observer.get());
+ return;
+ }
+
+ // We cannot capture non-bindable properties without signals
+ if (notifyIndex == -1)
+ return;
+
+ if (isConnected(m_sourceObject, notifyIndex))
+ cancelNotify();
+ else
+ connect(m_sourceObject, notifyIndex, m_engine, true);
+}
+
+void QQmlPropertyToPropertyBinding::update(QQmlPropertyData::WriteFlags flags)
+{
+ if (!enabledFlag())
+ return;
+
+ // Check that the target has not been deleted
+ QObject *target = targetObject();
+ if (QQmlData::wasDeleted(target))
+ return;
+
+ const QQmlPropertyData *d = nullptr;
+ QQmlPropertyData vtd;
+ getPropertyData(&d, &vtd);
+ Q_ASSERT(d);
+
+ // Check for a binding update loop
+ if (Q_UNLIKELY(updatingFlag())) {
+ QQmlAbstractBinding::printBindingLoopError(
+ QQmlPropertyPrivate::restore(target, *d, &vtd, nullptr));
+ return;
+ }
+
+ setUpdatingFlag(true);
+
+ if (canUseAccessor())
+ flags.setFlag(QQmlPropertyData::BypassInterceptor);
+
+ const QMetaObject *sourceMetaObject = m_sourceObject->metaObject();
+ const QMetaProperty property = sourceMetaObject->property(m_sourcePropertyIndex);
+ if (!property.isConstant()) {
+ captureProperty(sourceMetaObject, QMetaObjectPrivate::signalIndex(property.notifySignal()),
+ property.isBindable(), !vtd.isValid() && d->isBindable());
+ }
+
+ QQmlPropertyPrivate::writeValueProperty(
+ target, *d, vtd, property.read(m_sourceObject), {}, flags);
+
+ setUpdatingFlag(false);
+}
+
+void QQmlPropertyGuard_callback(QQmlNotifierEndpoint *e, void **)
+{
+ static_cast<QQmlPropertyToPropertyBinding *>(e)->update();
+}
+
+void QQmlPropertyToPropertyBinding::Observer::trigger(
+ QPropertyObserver *observer, QUntypedPropertyData *)
+{
+ static_cast<Observer *>(observer)->binding->update();
+}
+
+QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlpropertytopropertybinding_p.h b/src/qml/qml/qqmlpropertytopropertybinding_p.h
new file mode 100644
index 0000000000..d741c5a740
--- /dev/null
+++ b/src/qml/qml/qqmlpropertytopropertybinding_p.h
@@ -0,0 +1,64 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QQMLPROPERTYTOPROPERTYBINDINDING_P_H
+#define QQMLPROPERTYTOPROPERTYBINDINDING_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 <private/qqmlabstractbinding_p.h>
+#include <private/qqmlnotifier_p.h>
+#include <QtCore/qproperty.h>
+
+QT_BEGIN_NAMESPACE
+
+class Q_QML_EXPORT QQmlPropertyToPropertyBinding
+ : public QQmlAbstractBinding, public QQmlNotifierEndpoint
+{
+public:
+ QQmlPropertyToPropertyBinding(
+ QQmlEngine *engine, QObject *sourceObject, int sourcePropertyIndex,
+ QObject *targetObject, int targetPropertyIndex);
+
+ Kind kind() const final;
+ void setEnabled(bool e, QQmlPropertyData::WriteFlags flags) final;
+
+ void update(QQmlPropertyData::WriteFlags flags = QQmlPropertyData::DontRemoveBinding);
+
+private:
+ static void trigger(QPropertyObserver *, QUntypedPropertyData *);
+
+ void captureProperty(
+ const QMetaObject *sourceMetaObject, int notifyIndex,
+ bool isSourceBindable, bool isTargetBindable);
+
+ struct Observer : QPropertyObserver {
+ static void trigger(QPropertyObserver *observer, QUntypedPropertyData *);
+ Observer(QQmlPropertyToPropertyBinding *binding)
+ : QPropertyObserver(trigger)
+ , binding(binding)
+ {
+ }
+ QQmlPropertyToPropertyBinding *binding = nullptr;
+ };
+
+ std::unique_ptr<Observer> observer;
+ QQmlEngine *m_engine = nullptr;
+ QObject *m_sourceObject = nullptr;
+ int m_sourcePropertyIndex = -1;
+};
+
+void QQmlPropertyGuard_callback(QQmlNotifierEndpoint *e, void **);
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/qml/qml/qqmlpropertyvalidator.cpp b/src/qml/qml/qqmlpropertyvalidator.cpp
index 7aeef30d9d..ff22c3043a 100644
--- a/src/qml/qml/qqmlpropertyvalidator.cpp
+++ b/src/qml/qml/qqmlpropertyvalidator.cpp
@@ -1,57 +1,23 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the tools applications 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qqmlpropertyvalidator_p.h"
#include <private/qqmlcustomparser_p.h>
+#include <private/qqmlglobal_p.h>
#include <private/qqmlirbuilder_p.h>
-#include <private/qqmlstringconverters_p.h>
#include <private/qqmlpropertycachecreator_p.h>
#include <private/qqmlpropertyresolver_p.h>
+#include <private/qqmlstringconverters_p.h>
+#include <private/qqmlsignalnames_p.h>
#include <QtCore/qdatetime.h>
QT_BEGIN_NAMESPACE
-static bool isPrimitiveType(int typeId)
+static bool isPrimitiveType(QMetaType metaType)
{
- switch (typeId) {
+ switch (metaType.id()) {
#define HANDLE_PRIMITIVE(Type, id, T) \
case QMetaType::Type:
QT_FOR_EACH_STATIC_PRIMITIVE_TYPE(HANDLE_PRIMITIVE);
@@ -62,7 +28,8 @@ QT_FOR_EACH_STATIC_PRIMITIVE_TYPE(HANDLE_PRIMITIVE);
}
}
-QQmlPropertyValidator::QQmlPropertyValidator(QQmlEnginePrivate *enginePrivate, const QQmlImports &imports, const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit)
+QQmlPropertyValidator::QQmlPropertyValidator(QQmlEnginePrivate *enginePrivate, const QQmlImports *imports,
+ const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &compilationUnit)
: enginePrivate(enginePrivate)
, compilationUnit(compilationUnit)
, imports(imports)
@@ -106,19 +73,26 @@ QVector<QQmlError> QQmlPropertyValidator::validateObject(
return errors;
}
- if (obj->flags & QV4::CompiledData::Object::IsComponent && !(obj->flags & QV4::CompiledData::Object::IsInlineComponentRoot)) {
+ if (obj->hasFlag(QV4::CompiledData::Object::IsComponent)
+ && !obj->hasFlag(QV4::CompiledData::Object::IsInlineComponentRoot)) {
Q_ASSERT(obj->nBindings == 1);
const QV4::CompiledData::Binding *componentBinding = obj->bindingTable();
- Q_ASSERT(componentBinding->type == QV4::CompiledData::Binding::Type_Object);
+ Q_ASSERT(componentBinding->type() == QV4::CompiledData::Binding::Type_Object);
return validateObject(componentBinding->value.objectIndex, componentBinding);
}
- QQmlPropertyCache *propertyCache = propertyCaches.at(objectIndex);
+ QQmlPropertyCache::ConstPtr propertyCache = propertyCaches.at(objectIndex);
if (!propertyCache)
return QVector<QQmlError>();
QQmlCustomParser *customParser = nullptr;
if (auto typeRef = resolvedType(obj->inheritedTypeNameIndex)) {
+
+ // This binding instantiates a separate object. The separate object can have an ID and its
+ // own group properties even if it's then assigned to a value type, for example a 'var', or
+ // anything with an invokable ctor taking a QObject*.
+ populatingValueTypeGroupProperty = false;
+
const auto type = typeRef->type();
if (type.isValid())
customParser = type.customParser();
@@ -134,7 +108,7 @@ QVector<QQmlError> QQmlPropertyValidator::validateObject(
if (!binding->isGroupProperty())
continue;
- if (binding->flags & QV4::CompiledData::Binding::IsOnAssignment)
+ if (binding->hasFlag(QV4::CompiledData::Binding::IsOnAssignment))
continue;
if (populatingValueTypeGroupProperty) {
@@ -148,9 +122,9 @@ QVector<QQmlError> QQmlPropertyValidator::validateObject(
QQmlPropertyResolver propertyResolver(propertyCache);
QString defaultPropertyName;
- QQmlPropertyData *defaultProperty = nullptr;
+ const QQmlPropertyData *defaultProperty = nullptr;
if (obj->indexOfDefaultPropertyOrAlias != -1) {
- QQmlPropertyCache *cache = propertyCache->parent();
+ const QQmlPropertyCache *cache = propertyCache->parent().data();
defaultPropertyName = cache->defaultPropertyName();
defaultProperty = cache->defaultProperty();
} else {
@@ -158,19 +132,21 @@ QVector<QQmlError> QQmlPropertyValidator::validateObject(
defaultProperty = propertyCache->defaultProperty();
}
- QV4::BindingPropertyData collectedBindingPropertyData(obj->nBindings);
+ QV4::CompiledData::BindingPropertyData collectedBindingPropertyData(obj->nBindings);
binding = obj->bindingTable();
for (quint32 i = 0; i < obj->nBindings; ++i, ++binding) {
QString name = stringAt(binding->propertyNameIndex);
+ const QV4::CompiledData::Binding::Type bindingType = binding->type();
+ const QV4::CompiledData::Binding::Flags bindingFlags = binding->flags();
if (customParser) {
- if (binding->type == QV4::CompiledData::Binding::Type_AttachedProperty) {
+ if (bindingType == QV4::CompiledData::Binding::Type_AttachedProperty) {
if (customParser->flags() & QQmlCustomParser::AcceptsAttachedProperties) {
customBindings << binding;
continue;
}
- } else if (QmlIR::IRBuilder::isSignalPropertyName(name)
+ } else if (QQmlSignalNames::isHandlerName(name)
&& !(customParser->flags() & QQmlCustomParser::AcceptsSignalHandlers)) {
customBindings << binding;
continue;
@@ -178,13 +154,14 @@ QVector<QQmlError> QQmlPropertyValidator::validateObject(
}
bool bindingToDefaultProperty = false;
- bool isGroupProperty = instantiatingBinding && instantiatingBinding->type == QV4::CompiledData::Binding::Type_GroupProperty;
+ bool isGroupProperty = instantiatingBinding
+ && instantiatingBinding->type() == QV4::CompiledData::Binding::Type_GroupProperty;
bool notInRevision = false;
- QQmlPropertyData *pd = nullptr;
+ const QQmlPropertyData *pd = nullptr;
if (!name.isEmpty()) {
- if (binding->flags & QV4::CompiledData::Binding::IsSignalHandlerExpression
- || binding->flags & QV4::CompiledData::Binding::IsSignalHandlerObject) {
+ if (bindingFlags & QV4::CompiledData::Binding::IsSignalHandlerExpression
+ || bindingFlags & QV4::CompiledData::Binding::IsSignalHandlerObject) {
pd = propertyResolver.signal(name, &notInRevision);
} else {
pd = propertyResolver.property(name, &notInRevision,
@@ -222,17 +199,20 @@ QVector<QQmlError> QQmlPropertyValidator::validateObject(
if (name.constData()->isUpper() && !binding->isAttachedProperty()) {
QQmlType type;
QQmlImportNamespace *typeNamespace = nullptr;
- imports.resolveType(stringAt(binding->propertyNameIndex), &type, nullptr, &typeNamespace);
+ imports->resolveType(
+ QQmlTypeLoader::get(enginePrivate), stringAt(binding->propertyNameIndex),
+ &type, nullptr, &typeNamespace);
if (typeNamespace)
return recordError(binding->location, tr("Invalid use of namespace"));
return recordError(binding->location, tr("Invalid attached object assignment"));
}
- if (binding->type >= QV4::CompiledData::Binding::Type_Object && (pd || binding->isAttachedProperty())) {
+ if (bindingType >= QV4::CompiledData::Binding::Type_Object
+ && (pd || binding->isAttachedProperty() || binding->isGroupProperty())) {
const bool populatingValueTypeGroupProperty
= pd
- && QQmlMetaType::metaObjectForMetaType(pd->propType())
- && !(binding->flags & QV4::CompiledData::Binding::IsOnAssignment);
+ && QQmlMetaType::metaObjectForValueType(pd->propType())
+ && !binding->hasFlag(QV4::CompiledData::Binding::IsOnAssignment);
const QVector<QQmlError> subObjectValidatorErrors
= validateObject(binding->value.objectIndex, binding,
populatingValueTypeGroupProperty);
@@ -241,15 +221,25 @@ QVector<QQmlError> QQmlPropertyValidator::validateObject(
}
// Signal handlers were resolved and checked earlier in the signal handler conversion pass.
- if (binding->flags & QV4::CompiledData::Binding::IsSignalHandlerExpression
- || binding->flags & QV4::CompiledData::Binding::IsSignalHandlerObject)
+ if (binding->flags() & (QV4::CompiledData::Binding::IsSignalHandlerExpression
+ | QV4::CompiledData::Binding::IsSignalHandlerObject
+ | QV4::CompiledData::Binding::IsPropertyObserver)) {
continue;
+ }
- if (binding->type == QV4::CompiledData::Binding::Type_AttachedProperty) {
- if (instantiatingBinding && (instantiatingBinding->isAttachedProperty() || instantiatingBinding->isGroupProperty())) {
- return recordError(binding->location, tr("Attached properties cannot be used here"));
+ if ((pd && bindingType == QV4::CompiledData::Binding::Type_AttachedProperty)
+ || (!pd && bindingType == QV4::CompiledData::Binding::Type_GroupProperty)) {
+ if (instantiatingBinding && (instantiatingBinding->isAttachedProperty()
+ || instantiatingBinding->isGroupProperty())) {
+ return recordError(
+ binding->location, tr("%1 properties cannot be used here")
+ .arg(bindingType == QV4::CompiledData::Binding::Type_AttachedProperty
+ ? QStringLiteral("Attached")
+ : QStringLiteral("Group")));
}
continue;
+ } else if (bindingType == QV4::CompiledData::Binding::Type_AttachedProperty) {
+ continue;
}
if (pd) {
@@ -259,15 +249,15 @@ QVector<QQmlError> QQmlPropertyValidator::validateObject(
if (!pd->isWritable()
&& !pd->isQList()
&& !binding->isGroupProperty()
- && !(binding->flags & QV4::CompiledData::Binding::InitializerForReadOnlyDeclaration)
+ && !(bindingFlags & QV4::CompiledData::Binding::InitializerForReadOnlyDeclaration)
) {
- if (assigningToGroupProperty && binding->type < QV4::CompiledData::Binding::Type_Object)
+ if (assigningToGroupProperty && bindingType < QV4::CompiledData::Binding::Type_Object)
return recordError(binding->valueLocation, tr("Cannot assign a value directly to a grouped property"));
return recordError(binding->valueLocation, tr("Invalid property assignment: \"%1\" is a read-only property").arg(name));
}
- if (!pd->isQList() && (binding->flags & QV4::CompiledData::Binding::IsListItem)) {
+ if (!pd->isQList() && (bindingFlags & QV4::CompiledData::Binding::IsListItem)) {
QString error;
if (pd->propType() == QMetaType::fromType<QQmlScriptString>())
error = tr( "Cannot assign multiple values to a script property");
@@ -278,7 +268,7 @@ QVector<QQmlError> QQmlPropertyValidator::validateObject(
if (!bindingToDefaultProperty
&& !binding->isGroupProperty()
- && !(binding->flags & QV4::CompiledData::Binding::IsOnAssignment)
+ && !(bindingFlags & QV4::CompiledData::Binding::IsOnAssignment)
&& assigningToGroupProperty) {
QV4::CompiledData::Location loc = binding->valueLocation;
if (loc < (*assignedGroupProperty)->valueLocation)
@@ -289,17 +279,17 @@ QVector<QQmlError> QQmlPropertyValidator::validateObject(
return recordError(loc, tr("Cannot assign a value directly to a grouped property"));
}
- if (binding->type < QV4::CompiledData::Binding::Type_Script) {
+ if (bindingType < QV4::CompiledData::Binding::Type_Script) {
QQmlError bindingError = validateLiteralBinding(propertyCache, pd, binding);
if (bindingError.isValid())
return recordError(bindingError);
- } else if (binding->type == QV4::CompiledData::Binding::Type_Object) {
+ } else if (bindingType == QV4::CompiledData::Binding::Type_Object) {
QQmlError bindingError = validateObjectBinding(pd, name, binding);
if (bindingError.isValid())
return recordError(bindingError);
} else if (binding->isGroupProperty()) {
if (QQmlMetaType::isValueType(pd->propType())) {
- if (QQmlMetaType::metaObjectForMetaType(pd->propType())) {
+ if (QQmlMetaType::metaObjectForValueType(pd->propType())) {
if (!pd->isWritable()) {
return recordError(binding->location, tr("Invalid property assignment: \"%1\" is a read-only property").arg(name));
}
@@ -307,22 +297,30 @@ QVector<QQmlError> QQmlPropertyValidator::validateObject(
return recordError(binding->location, tr("Invalid grouped property access"));
}
} else {
- const int typeId = pd->propType().id();
- if (isPrimitiveType(typeId)) {
+ const QMetaType type = pd->propType();
+ if (isPrimitiveType(type)) {
return recordError(
binding->location,
tr("Invalid grouped property access: Property \"%1\" with primitive type \"%2\".")
- .arg(name)
- .arg(QString::fromLatin1(QMetaType(typeId).name()))
+ .arg(name, QString::fromUtf8(type.name()))
);
}
- if (!enginePrivate->propertyCacheForType(typeId)) {
- return recordError(binding->location,
- tr("Invalid grouped property access: Property \"%1\" with type \"%2\", which is not a value type")
- .arg(name)
- .arg(QString::fromLatin1(QMetaType(typeId).name()))
- );
+ if (!QQmlMetaType::propertyCacheForType(type)) {
+ auto mo = type.metaObject();
+ if (!mo) {
+ return recordError(binding->location,
+ tr("Invalid grouped property access: Property \"%1\" with type \"%2\", which is neither a value nor an object type")
+ .arg(name, QString::fromUtf8(type.name()))
+ );
+ }
+ if (QMetaObjectPrivate::get(mo)->flags & DynamicMetaObject) {
+ return recordError(binding->location,
+ tr("Unsupported grouped property access: Property \"%1\" with type \"%2\" has a dynamic meta-object.")
+ .arg(name, QString::fromUtf8(type.name()))
+ );
+ }
+ // fall through, this is okay
}
}
}
@@ -351,8 +349,11 @@ QVector<QQmlError> QQmlPropertyValidator::validateObject(
customParser->clearErrors();
customParser->validator = this;
customParser->engine = enginePrivate;
- customParser->imports = &imports;
- customParser->verifyBindings(compilationUnit, customBindings);
+ customParser->imports = imports;
+ customParser->verifyBindings(
+ enginePrivate->v4engine()->executableCompilationUnit(
+ QQmlRefPointer<QV4::CompiledData::CompilationUnit>(compilationUnit)),
+ customBindings);
customParser->validator = nullptr;
customParser->engine = nullptr;
customParser->imports = (QQmlImports*)nullptr;
@@ -367,7 +368,9 @@ QVector<QQmlError> QQmlPropertyValidator::validateObject(
return noError;
}
-QQmlError QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache *propertyCache, QQmlPropertyData *property, const QV4::CompiledData::Binding *binding) const
+QQmlError QQmlPropertyValidator::validateLiteralBinding(
+ const QQmlPropertyCache::ConstPtr &propertyCache, const QQmlPropertyData *property,
+ const QV4::CompiledData::Binding *binding) const
{
if (property->isQList()) {
return qQmlCompileError(binding->valueLocation, tr("Cannot assign primitives to lists"));
@@ -376,7 +379,12 @@ QQmlError QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache *prope
QQmlError noError;
if (property->isEnum()) {
- if (binding->flags & QV4::CompiledData::Binding::IsResolvedEnum)
+ if (binding->hasFlag(QV4::CompiledData::Binding::IsResolvedEnum))
+ return noError;
+
+ // TODO: For historical reasons you can assign any number to an enum property alias
+ // This can be fixed with an opt-out mechanism, for example a pragma.
+ if (property->isAlias() && binding->isNumberBinding())
return noError;
QString value = compilationUnit->bindingValueAsString(binding);
@@ -394,24 +402,14 @@ QQmlError QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache *prope
}
auto warnOrError = [&](const QString &error) {
- if (binding->type == QV4::CompiledData::Binding::Type_Null) {
- QQmlError warning;
- warning.setUrl(compilationUnit->url());
- warning.setLine(qmlConvertSourceCoordinate<quint32, int>(binding->valueLocation.line));
- warning.setColumn(qmlConvertSourceCoordinate<quint32, int>(binding->valueLocation.column));
- warning.setDescription(error + tr(" - Assigning null to incompatible properties in QML "
- "is deprecated. This will become a compile error in "
- "future versions of Qt."));
- enginePrivate->warning(warning);
- return noError;
- }
return qQmlCompileError(binding->valueLocation, error);
};
+ const QV4::CompiledData::Binding::Type bindingType = binding->type();
const auto isStringBinding = [&]() -> bool {
// validateLiteralBinding is not supposed to be used on scripts
- Q_ASSERT(binding->type != QV4::CompiledData::Binding::Type_Script);
- return binding->type == QV4::CompiledData::Binding::Type_String;
+ Q_ASSERT(bindingType != QV4::CompiledData::Binding::Type_Script);
+ return bindingType == QV4::CompiledData::Binding::Type_String;
};
switch (property->propType().id()) {
@@ -430,19 +428,17 @@ QQmlError QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache *prope
}
break;
case QMetaType::QByteArray: {
- if (binding->type != QV4::CompiledData::Binding::Type_String) {
+ if (bindingType != QV4::CompiledData::Binding::Type_String)
return warnOrError(tr("Invalid property assignment: byte array expected"));
- }
}
break;
case QMetaType::QUrl: {
- if (binding->type != QV4::CompiledData::Binding::Type_String) {
+ if (bindingType != QV4::CompiledData::Binding::Type_String)
return warnOrError(tr("Invalid property assignment: url expected"));
- }
}
break;
case QMetaType::UInt: {
- if (binding->type == QV4::CompiledData::Binding::Type_Number) {
+ if (bindingType == QV4::CompiledData::Binding::Type_Number) {
double d = compilationUnit->bindingValueAsNumber(binding);
if (double(uint(d)) == d)
return noError;
@@ -451,7 +447,7 @@ QQmlError QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache *prope
}
break;
case QMetaType::Int: {
- if (binding->type == QV4::CompiledData::Binding::Type_Number) {
+ if (bindingType == QV4::CompiledData::Binding::Type_Number) {
double d = compilationUnit->bindingValueAsNumber(binding);
if (double(int(d)) == d)
return noError;
@@ -460,13 +456,13 @@ QQmlError QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache *prope
}
break;
case QMetaType::Float: {
- if (binding->type != QV4::CompiledData::Binding::Type_Number) {
+ if (bindingType != QV4::CompiledData::Binding::Type_Number) {
return warnOrError(tr("Invalid property assignment: number expected"));
}
}
break;
case QMetaType::Double: {
- if (binding->type != QV4::CompiledData::Binding::Type_Number) {
+ if (bindingType != QV4::CompiledData::Binding::Type_Number) {
return warnOrError(tr("Invalid property assignment: number expected"));
}
}
@@ -564,7 +560,7 @@ QQmlError QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache *prope
}
break;
case QMetaType::Bool: {
- if (binding->type != QV4::CompiledData::Binding::Type_Boolean) {
+ if (bindingType != QV4::CompiledData::Binding::Type_Boolean) {
return warnOrError(tr("Invalid property assignment: boolean expected"));
}
}
@@ -582,10 +578,10 @@ QQmlError QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache *prope
default: return QString();
}
};
- QVariant result;
- if (!QQml_valueTypeProvider()->createValueType(
- property->propType().id(),
- compilationUnit->bindingValueAsString(binding), result)) {
+ const QVariant result = QQmlValueTypeProvider::createValueType(
+ compilationUnit->bindingValueAsString(binding),
+ property->propType());
+ if (!result.isValid()) {
return warnOrError(tr("Invalid property assignment: %1 expected")
.arg(typeName()));
}
@@ -596,12 +592,12 @@ QQmlError QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache *prope
default: {
// generate single literal value assignment to a list property if required
if (property->propType() == QMetaType::fromType<QList<qreal> >()) {
- if (binding->type != QV4::CompiledData::Binding::Type_Number) {
+ if (bindingType != QV4::CompiledData::Binding::Type_Number) {
return warnOrError(tr("Invalid property assignment: number or array of numbers expected"));
}
break;
} else if (property->propType() == QMetaType::fromType<QList<int> >()) {
- bool ok = (binding->type == QV4::CompiledData::Binding::Type_Number);
+ bool ok = (bindingType == QV4::CompiledData::Binding::Type_Number);
if (ok) {
double n = compilationUnit->bindingValueAsNumber(binding);
if (double(int(n)) != n)
@@ -611,12 +607,12 @@ QQmlError QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache *prope
return warnOrError(tr("Invalid property assignment: int or array of ints expected"));
break;
} else if (property->propType() == QMetaType::fromType<QList<bool> >()) {
- if (binding->type != QV4::CompiledData::Binding::Type_Boolean) {
+ if (bindingType != QV4::CompiledData::Binding::Type_Boolean) {
return warnOrError(tr("Invalid property assignment: bool or array of bools expected"));
}
break;
} else if (property->propType() == QMetaType::fromType<QList<QUrl> >()) {
- if (binding->type != QV4::CompiledData::Binding::Type_String) {
+ if (bindingType != QV4::CompiledData::Binding::Type_String) {
return warnOrError(tr("Invalid property assignment: url or array of urls expected"));
}
break;
@@ -630,15 +626,13 @@ QQmlError QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache *prope
} else if (property->propType() == QMetaType::fromType<QQmlScriptString>()) {
break;
} else if (property->isQObject()
- && binding->type == QV4::CompiledData::Binding::Type_Null) {
+ && bindingType == QV4::CompiledData::Binding::Type_Null) {
+ break;
+ } else if (QQmlMetaType::qmlType(property->propType()).canConstructValueType()) {
break;
}
- // otherwise, try a custom type assignment
- QQmlMetaType::StringConverter converter = QQmlMetaType::customStringConverter(property->propType().id());
- if (!converter) {
- return warnOrError(tr("Invalid property assignment: unsupported type \"%1\"").arg(QString::fromLatin1(QMetaType(property->propType()).name())));
- }
+ return warnOrError(tr("Invalid property assignment: unsupported type \"%1\"").arg(QLatin1StringView(property->propType().name())));
}
break;
}
@@ -649,17 +643,17 @@ QQmlError QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache *prope
Returns true if from can be assigned to a (QObject) property of type
to.
*/
-bool QQmlPropertyValidator::canCoerce(int to, QQmlPropertyCache *fromMo) const
+bool QQmlPropertyValidator::canCoerce(QMetaType to, QQmlPropertyCache::ConstPtr fromMo) const
{
- QQmlPropertyCache *toMo = enginePrivate->rawPropertyCacheForType(to);
+ QQmlPropertyCache::ConstPtr toMo = QQmlMetaType::rawPropertyCacheForType(to);
- if (toMo == nullptr) {
+ if (toMo.isNull()) {
// if we have an inline component from the current file,
// it is not properly registered at this point, as registration
// only occurs after the whole file has been validated
// Therefore we need to check the ICs here
for (const auto& icDatum : compilationUnit->inlineComponentData) {
- if (icDatum.typeIds.id.id() == to) {
+ if (icDatum.qmlType.typeId() == to) {
toMo = compilationUnit->propertyCaches.at(icDatum.objectIndex);
break;
}
@@ -688,26 +682,25 @@ QVector<QQmlError> QQmlPropertyValidator::recordError(const QQmlError &error) co
return errors;
}
-QQmlError QQmlPropertyValidator::validateObjectBinding(QQmlPropertyData *property, const QString &propertyName, const QV4::CompiledData::Binding *binding) const
+QQmlError QQmlPropertyValidator::validateObjectBinding(const QQmlPropertyData *property, const QString &propertyName, const QV4::CompiledData::Binding *binding) const
{
QQmlError noError;
- if (binding->flags & QV4::CompiledData::Binding::IsOnAssignment) {
- Q_ASSERT(binding->type == QV4::CompiledData::Binding::Type_Object);
+ if (binding->hasFlag(QV4::CompiledData::Binding::IsOnAssignment)) {
+ Q_ASSERT(binding->type() == QV4::CompiledData::Binding::Type_Object);
bool isValueSource = false;
bool isPropertyInterceptor = false;
const QV4::CompiledData::Object *targetObject = compilationUnit->objectAt(binding->value.objectIndex);
if (auto *typeRef = resolvedType(targetObject->inheritedTypeNameIndex)) {
- QQmlRefPointer<QQmlPropertyCache> cache = typeRef->createPropertyCache(QQmlEnginePrivate::get(enginePrivate));
- const QMetaObject *mo = cache->firstCppMetaObject();
+ QQmlPropertyCache::ConstPtr cache = typeRef->createPropertyCache();
+ const QMetaObject *mo = cache ? cache->firstCppMetaObject() : nullptr;
QQmlType qmlType;
while (mo && !qmlType.isValid()) {
qmlType = QQmlMetaType::qmlType(mo);
mo = mo->superClass();
}
- Q_ASSERT(qmlType.isValid());
isValueSource = qmlType.propertyValueSourceCast() != -1;
isPropertyInterceptor = qmlType.propertyValueInterceptorCast() != -1;
@@ -720,7 +713,7 @@ QQmlError QQmlPropertyValidator::validateObjectBinding(QQmlPropertyData *propert
return noError;
}
- const int propType = property->propType().id();
+ const QMetaType propType = property->propType();
const auto rhsType = [&]() {
return stringAt(compilationUnit->objectAt(binding->value.objectIndex)
->inheritedTypeNameIndex);
@@ -730,19 +723,21 @@ QQmlError QQmlPropertyValidator::validateObjectBinding(QQmlPropertyData *propert
// Can only check at instantiation time if the created sub-object successfully casts to the
// target interface.
return noError;
- } else if (propType == QMetaType::QVariant || propType == qMetaTypeId<QJSValue>()) {
+ } else if (propType == QMetaType::fromType<QVariant>()
+ || propType == QMetaType::fromType<QJSValue>()) {
// We can convert everything to QVariant :)
return noError;
} else if (property->isQList()) {
- const int listType = QQmlMetaType::listType(propType);
+ const QMetaType listType = QQmlMetaType::listValueType(property->propType());
if (!QQmlMetaType::isInterface(listType)) {
- QQmlPropertyCache *source = propertyCaches.at(binding->value.objectIndex);
+ QQmlPropertyCache::ConstPtr 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 noError;
- } else if (binding->flags & QV4::CompiledData::Binding::IsSignalHandlerObject && property->isFunction()) {
+ } else if (binding->hasFlag(QV4::CompiledData::Binding::IsSignalHandlerObject)
+ && property->isFunction()) {
return noError;
} else if (isPrimitiveType(propType)) {
auto typeName = QString::fromUtf8(QMetaType(propType).name());
@@ -750,7 +745,7 @@ QQmlError QQmlPropertyValidator::validateObjectBinding(QQmlPropertyData *propert
.arg(rhsType())
.arg(propertyName)
.arg(typeName));
- } else if (propType == qMetaTypeId<QQmlScriptString>()) {
+ } else if (propType == QMetaType::fromType<QQmlScriptString>()) {
return qQmlCompileError(binding->valueLocation, tr("Invalid property assignment: script expected"));
} else if (QQmlMetaType::isValueType(property->propType())) {
return qQmlCompileError(binding->location, tr("Cannot assign value of type \"%1\" to property \"%2\", expecting an object")
@@ -760,15 +755,17 @@ QQmlError QQmlPropertyValidator::validateObjectBinding(QQmlPropertyData *propert
// actual property type before we applied any extensions that might
// effect the properties on the type, but don't effect assignability
// Not passing a version ensures that we get the raw metaObject.
- QQmlPropertyCache *propertyMetaObject = enginePrivate->rawPropertyCacheForType(propType);
+ QQmlPropertyCache::ConstPtr propertyMetaObject
+ = QQmlMetaType::rawPropertyCacheForType(propType);
if (!propertyMetaObject) {
// if we have an inline component from the current file,
// it is not properly registered at this point, as registration
// only occurs after the whole file has been validated
// Therefore we need to check the ICs here
for (const auto& icDatum: compilationUnit->inlineComponentData) {
- if (icDatum.typeIds.id == property->propType()) {
- propertyMetaObject = compilationUnit->propertyCaches.at(icDatum.objectIndex);
+ if (icDatum.qmlType.typeId() == property->propType()) {
+ propertyMetaObject
+ = compilationUnit->propertyCaches.at(icDatum.objectIndex);
break;
}
}
@@ -778,7 +775,7 @@ QQmlError QQmlPropertyValidator::validateObjectBinding(QQmlPropertyData *propert
// Will be true if the assigned type inherits propertyMetaObject
// Determine isAssignable value
bool isAssignable = false;
- QQmlPropertyCache *c = propertyCaches.at(binding->value.objectIndex);
+ QQmlPropertyCache::ConstPtr c = propertyCaches.at(binding->value.objectIndex);
while (c && !isAssignable) {
isAssignable |= c == propertyMetaObject;
c = c->parent();
diff --git a/src/qml/qml/qqmlpropertyvalidator_p.h b/src/qml/qml/qqmlpropertyvalidator_p.h
index 281472981c..75787fcf68 100644
--- a/src/qml/qml/qqmlpropertyvalidator_p.h
+++ b/src/qml/qml/qqmlpropertyvalidator_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the tools applications 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLPROPERTYVALIDATOR_P_H
#define QQMLPROPERTYVALIDATOR_P_H
@@ -64,22 +28,27 @@ class QQmlPropertyValidator
{
Q_DECLARE_TR_FUNCTIONS(QQmlPropertyValidator)
public:
- QQmlPropertyValidator(QQmlEnginePrivate *enginePrivate, const QQmlImports &imports, const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit);
+ QQmlPropertyValidator(
+ QQmlEnginePrivate *enginePrivate, const QQmlImports *imports,
+ const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &compilationUnit);
QVector<QQmlError> validate();
+ QQmlPropertyCache::ConstPtr rootPropertyCache() const { return propertyCaches.at(0); }
+ QUrl documentSourceUrl() const { return compilationUnit->url(); }
+
private:
QVector<QQmlError> validateObject(
int objectIndex, const QV4::CompiledData::Binding *instantiatingBinding,
bool populatingValueTypeGroupProperty = false) const;
QQmlError validateLiteralBinding(
- QQmlPropertyCache *propertyCache, QQmlPropertyData *property,
+ const QQmlPropertyCache::ConstPtr &propertyCache, const QQmlPropertyData *property,
const QV4::CompiledData::Binding *binding) const;
QQmlError validateObjectBinding(
- QQmlPropertyData *property, const QString &propertyName,
+ const QQmlPropertyData *property, const QString &propertyName,
const QV4::CompiledData::Binding *binding) const;
- bool canCoerce(int to, QQmlPropertyCache *fromMo) const;
+ bool canCoerce(QMetaType to, QQmlPropertyCache::ConstPtr fromMo) const;
Q_REQUIRED_RESULT QVector<QQmlError> recordError(
const QV4::CompiledData::Location &location, const QString &description) const;
@@ -91,12 +60,12 @@ private:
}
QQmlEnginePrivate *enginePrivate;
- QQmlRefPointer<QV4::ExecutableCompilationUnit> compilationUnit;
- const QQmlImports &imports;
+ QQmlRefPointer<QV4::CompiledData::CompilationUnit> compilationUnit;
+ const QQmlImports *imports;
const QV4::CompiledData::Unit *qmlUnit;
const QQmlPropertyCacheVector &propertyCaches;
- QVector<QV4::BindingPropertyData> * const bindingPropertyDataPerObject;
+ QVector<QV4::CompiledData::BindingPropertyData> * const bindingPropertyDataPerObject;
};
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlpropertyvalueinterceptor.cpp b/src/qml/qml/qqmlpropertyvalueinterceptor.cpp
index 603245f29d..17d43a1271 100644
--- a/src/qml/qml/qqmlpropertyvalueinterceptor.cpp
+++ b/src/qml/qml/qqmlpropertyvalueinterceptor.cpp
@@ -1,46 +1,8 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qqmlpropertyvalueinterceptor_p.h"
-#include "qqml.h"
-
QT_BEGIN_NAMESPACE
/*!
@@ -64,6 +26,21 @@ QQmlPropertyValueInterceptor::~QQmlPropertyValueInterceptor()
}
/*!
+ \internal
+ Called when a BindableProperty metacall gets intercepted. The default implementation does nothing
+ and simply returns false.
+ A subclass which can properly intercept the metacall should return true after doing its work.
+ \a bindable is the pointer to the QUntypedBindable passed through the metacall
+ \a target is the QUntypedBindable of the intercepted property
+*/
+bool QQmlPropertyValueInterceptor::bindable(QUntypedBindable *bindable, QUntypedBindable target)
+{
+ Q_UNUSED(bindable);
+ Q_UNUSED(target)
+ return false;
+}
+
+/*!
\fn void QQmlPropertyValueInterceptor::setTarget(const QQmlProperty &property)
Set the target \a property for the value interceptor. This method will
be called by the QML engine when assigning a value interceptor.
diff --git a/src/qml/qml/qqmlpropertyvalueinterceptor_p.h b/src/qml/qml/qqmlpropertyvalueinterceptor_p.h
index a3d6b0c8c7..9d1b0606cd 100644
--- a/src/qml/qml/qqmlpropertyvalueinterceptor_p.h
+++ b/src/qml/qml/qqmlpropertyvalueinterceptor_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLPROPERTYVALUEINTERCEPTOR_P_H
#define QQMLPROPERTYVALUEINTERCEPTOR_P_H
@@ -54,17 +18,19 @@
#include <private/qtqmlglobal_p.h>
#include <private/qqmlpropertyindex_p.h>
#include <QtCore/qobject.h>
+#include <QtCore/qproperty.h>
QT_BEGIN_NAMESPACE
class QQmlProperty;
-class Q_QML_PRIVATE_EXPORT QQmlPropertyValueInterceptor
+class Q_QML_EXPORT QQmlPropertyValueInterceptor
{
public:
QQmlPropertyValueInterceptor();
virtual ~QQmlPropertyValueInterceptor();
virtual void setTarget(const QQmlProperty &property) = 0;
virtual void write(const QVariant &value) = 0;
+ virtual bool bindable(QUntypedBindable *bindable, QUntypedBindable target);
private:
friend class QQmlInterceptorMetaObject;
diff --git a/src/qml/qml/qqmlpropertyvaluesource.cpp b/src/qml/qml/qqmlpropertyvaluesource.cpp
index 0aad41ebf1..558b36de09 100644
--- a/src/qml/qml/qqmlpropertyvaluesource.cpp
+++ b/src/qml/qml/qqmlpropertyvaluesource.cpp
@@ -1,46 +1,8 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qqmlpropertyvaluesource.h"
-#include "qqml.h"
-
QT_BEGIN_NAMESPACE
/*!
diff --git a/src/qml/qml/qqmlpropertyvaluesource.h b/src/qml/qml/qqmlpropertyvaluesource.h
index 282a1021d6..9a39728220 100644
--- a/src/qml/qml/qqmlpropertyvaluesource.h
+++ b/src/qml/qml/qqmlpropertyvaluesource.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLPROPERTYVALUESOURCE_H
#define QQMLPROPERTYVALUESOURCE_H
diff --git a/src/qml/qml/qqmlproxymetaobject.cpp b/src/qml/qml/qqmlproxymetaobject.cpp
index 21d3c7ed05..6ec4009c37 100644
--- a/src/qml/qml/qqmlproxymetaobject.cpp
+++ b/src/qml/qml/qqmlproxymetaobject.cpp
@@ -1,55 +1,19 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qqmlproxymetaobject_p.h"
#include "qqmlproperty_p.h"
QT_BEGIN_NAMESPACE
-QQmlProxyMetaObject::QQmlProxyMetaObject(QObject *obj, QList<ProxyData> *mList)
-: metaObjects(mList), proxies(nullptr), parent(nullptr), object(obj)
+QQmlProxyMetaObject::QQmlProxyMetaObject(QObject *obj, const QList<ProxyData> *mList)
+ : metaObjects(mList), proxies(nullptr), parent(nullptr), object(obj)
{
- *static_cast<QMetaObject *>(this) = *metaObjects->constFirst().metaObject;
+ metaObject = metaObjects->constFirst().metaObject;
QObjectPrivate *op = QObjectPrivate::get(obj);
if (op->metaObject)
- parent = static_cast<QAbstractDynamicMetaObject*>(op->metaObject);
+ parent = op->metaObject;
op->metaObject = this;
}
@@ -68,11 +32,8 @@ QQmlProxyMetaObject::~QQmlProxyMetaObject()
QObject *QQmlProxyMetaObject::getProxy(int index)
{
if (!proxies) {
- if (!proxies) {
- proxies = new QObject*[metaObjects->count()];
- ::memset(proxies, 0,
- sizeof(QObject *) * metaObjects->count());
- }
+ proxies = new QObject *[metaObjects->size()];
+ ::memset(proxies, 0, sizeof(QObject *) * metaObjects->size());
}
if (!proxies[index]) {
@@ -104,39 +65,60 @@ int QQmlProxyMetaObject::metaCall(QObject *o, QMetaObject::Call c, int id, void
{
Q_ASSERT(object == o);
- if ((c == QMetaObject::ReadProperty ||
- c == QMetaObject::WriteProperty) &&
- id >= metaObjects->constLast().propertyOffset) {
+ switch (c) {
+ case QMetaObject::ReadProperty:
+ case QMetaObject::WriteProperty: {
+ if (id < metaObjects->constLast().propertyOffset)
+ break;
- for (int ii = 0; ii < metaObjects->count(); ++ii) {
+ for (int ii = 0; ii < metaObjects->size(); ++ii) {
const int globalPropertyOffset = metaObjects->at(ii).propertyOffset;
- if (id >= globalPropertyOffset) {
- QObject *proxy = getProxy(ii);
- const int localProxyOffset = proxy->metaObject()->propertyOffset();
- const int localProxyId = id - globalPropertyOffset + localProxyOffset;
-
- return proxy->qt_metacall(c, localProxyId, a);
- }
+ if (id < globalPropertyOffset)
+ continue;
+
+ QObject *proxy = getProxy(ii);
+ Q_ASSERT(proxy);
+ const int localProxyOffset = proxy->metaObject()->propertyOffset();
+ const int localProxyId = id - globalPropertyOffset + localProxyOffset;
+ return proxy->qt_metacall(c, localProxyId, a);
}
- } else if (c == QMetaObject::InvokeMetaMethod &&
- id >= metaObjects->constLast().methodOffset) {
+ break;
+ }
+ case QMetaObject::InvokeMetaMethod: {
+ if (id < metaObjects->constLast().methodOffset)
+ break;
+
QMetaMethod m = object->metaObject()->method(id);
if (m.methodType() == QMetaMethod::Signal) {
QMetaObject::activate(object, id, a);
return -1;
- } else {
- for (int ii = 0; ii < metaObjects->count(); ++ii) {
- const int globalMethodOffset = metaObjects->at(ii).methodOffset;
- if (id >= globalMethodOffset) {
- QObject *proxy = getProxy(ii);
-
- const int localMethodOffset = proxy->metaObject()->methodOffset();
- const int localMethodId = id - globalMethodOffset + localMethodOffset;
-
- return proxy->qt_metacall(c, localMethodId, a);
- }
- }
}
+
+ for (int ii = 0; ii < metaObjects->size(); ++ii) {
+ const int globalMethodOffset = metaObjects->at(ii).methodOffset;
+ if (id < globalMethodOffset)
+ continue;
+
+ QObject *proxy = getProxy(ii);
+ Q_ASSERT(proxy);
+ const int localMethodOffset = proxy->metaObject()->methodOffset();
+ const int localMethodId = id - globalMethodOffset + localMethodOffset;
+ return proxy->qt_metacall(c, localMethodId, a);
+ }
+
+ break;
+ }
+ case QMetaObject::CustomCall: {
+ if ((id & ~MaxExtensionCount) != ExtensionObjectId)
+ break;
+ int index = id & MaxExtensionCount;
+ if (qsizetype(index) >= metaObjects->size())
+ break;
+ a[0] = getProxy(index);
+ return id;
+ }
+ default:
+ break;
}
if (parent)
@@ -145,4 +127,17 @@ int QQmlProxyMetaObject::metaCall(QObject *o, QMetaObject::Call c, int id, void
return object->qt_metacall(c, id, a);
}
+QMetaObject *QQmlProxyMetaObject::toDynamicMetaObject(QObject *)
+{
+ return metaObject;
+}
+
+void QQmlProxyMetaObject::objectDestroyed(QObject *object)
+{
+ if (parent)
+ parent->objectDestroyed(object);
+ else
+ QDynamicMetaObjectData::objectDestroyed(object);
+}
+
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlproxymetaobject_p.h b/src/qml/qml/qqmlproxymetaobject_p.h
index dfa5d44059..18cf2d4bac 100644
--- a/src/qml/qml/qqmlproxymetaobject_p.h
+++ b/src/qml/qml/qqmlproxymetaobject_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLPROXYMETAOBJECT_P_H
#define QQMLPROXYMETAOBJECT_P_H
@@ -51,8 +15,8 @@
// We mean it.
//
+#include <private/qtqmlglobal_p.h>
#include <private/qmetaobjectbuilder_p.h>
-#include "qqml.h"
#include <QtCore/QMetaObject>
#include <QtCore/QObject>
@@ -61,8 +25,7 @@
QT_BEGIN_NAMESPACE
-
-class QQmlProxyMetaObject : public QAbstractDynamicMetaObject
+class Q_QML_EXPORT QQmlProxyMetaObject : public QDynamicMetaObjectData
{
public:
struct ProxyData {
@@ -73,20 +36,39 @@ public:
int methodOffset;
};
- QQmlProxyMetaObject(QObject *, QList<ProxyData> *);
+ QQmlProxyMetaObject(QObject *, const QList<ProxyData> *);
~QQmlProxyMetaObject();
+ static constexpr int extensionObjectId(int id) noexcept
+ {
+ Q_ASSERT(id >= 0);
+ Q_ASSERT(id <= MaxExtensionCount); // MaxExtensionCount is a valid index
+ return ExtensionObjectId | id;
+ }
+
protected:
int metaCall(QObject *o, QMetaObject::Call _c, int _id, void **_a) override;
+ QMetaObject *toDynamicMetaObject(QObject *) override;
+ void objectDestroyed(QObject *object) override;
private:
QObject *getProxy(int index);
- QList<ProxyData> *metaObjects;
+ const QList<ProxyData> *metaObjects;
QObject **proxies;
- QAbstractDynamicMetaObject *parent;
+ QDynamicMetaObjectData *parent;
+ QMetaObject *metaObject;
QObject *object;
+
+ // ExtensionObjectId acts as a flag for whether we should interpret a
+ // QMetaObject::CustomCall as a call to fetch the extension object (see
+ // QQmlProxyMetaObject::metaCall()). MaxExtensionCount is a limit on how
+ // many extensions we can query via such mechanism
+ enum : int {
+ MaxExtensionCount = 127, // magic number so that low bits are all '1'
+ ExtensionObjectId = ~MaxExtensionCount,
+ };
};
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlregistration.h b/src/qml/qml/qqmlregistration.h
new file mode 100644
index 0000000000..562a79eaf1
--- /dev/null
+++ b/src/qml/qml/qqmlregistration.h
@@ -0,0 +1,15 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QQMLREGISTRATION_H
+#define QQMLREGISTRATION_H
+
+#include <QtCore/qglobal.h>
+#include <QtQmlIntegration/qqmlintegration.h>
+
+// satisfy configure, which warns about public headers not using those
+QT_BEGIN_NAMESPACE
+
+QT_END_NAMESPACE
+
+#endif // QQMLREGISTRATION_H
diff --git a/src/qml/qml/qqmlscriptblob.cpp b/src/qml/qml/qqmlscriptblob.cpp
index 7b7a842d04..fa9a41e801 100644
--- a/src/qml/qml/qqmlscriptblob.cpp
+++ b/src/qml/qml/qqmlscriptblob.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 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$
-**
-****************************************************************************/
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <private/qqmlengine_p.h>
#include <private/qqmlirbuilder_p.h>
@@ -68,14 +32,18 @@ QQmlRefPointer<QQmlScriptData> QQmlScriptBlob::scriptData() const
return m_scriptData;
}
+bool QQmlScriptBlob::isNative() const
+{
+ return m_scriptData && !m_scriptData->m_value.isEmpty();
+}
+
void QQmlScriptBlob::dataReceived(const SourceCodeData &data)
{
- if (diskCacheEnabled()) {
- QQmlRefPointer<QV4::ExecutableCompilationUnit> unit
- = QV4::ExecutableCompilationUnit::create();
+ if (readCacheFile()) {
+ auto unit = QQml::makeRefPointer<QV4::CompiledData::CompilationUnit>();
QString error;
if (unit->loadFromDisk(url(), data.sourceTimeStamp(), &error)) {
- initializeFromCompilationUnit(unit);
+ initializeFromCompilationUnit(std::move(unit));
return;
} else {
qCDebug(DBG_DISK_CACHE()) << "Error loading" << urlString() << "from disk cache:" << error;
@@ -97,7 +65,7 @@ void QQmlScriptBlob::dataReceived(const SourceCodeData &data)
return;
}
- QV4::CompiledData::CompilationUnit unit;
+ QQmlRefPointer<QV4::CompiledData::CompilationUnit> unit;
if (m_isModule) {
QList<QQmlJS::DiagnosticMessage> diagnostics;
@@ -132,28 +100,26 @@ void QQmlScriptBlob::dataReceived(const SourceCodeData &data)
unit = std::move(irUnit.javaScriptCompilationUnit);
}
- auto executableUnit = QV4::ExecutableCompilationUnit::create(std::move(unit));
-
- if (diskCacheEnabled()) {
+ if (writeCacheFile()) {
QString errorString;
- if (executableUnit->saveToDisk(url(), &errorString)) {
+ if (unit->saveToDisk(url(), &errorString)) {
QString error;
- if (!executableUnit->loadFromDisk(url(), data.sourceTimeStamp(), &error)) {
+ if (!unit->loadFromDisk(url(), data.sourceTimeStamp(), &error)) {
// ignore error, keep using the in-memory compilation unit.
}
} else {
qCDebug(DBG_DISK_CACHE()) << "Error saving cached version of"
- << executableUnit->fileName() << "to disk:" << errorString;
+ << unit->fileName() << "to disk:" << errorString;
}
}
- initializeFromCompilationUnit(executableUnit);
+ initializeFromCompilationUnit(std::move(unit));
}
-void QQmlScriptBlob::initializeFromCachedUnit(const QQmlPrivate::CachedQmlUnit *unit)
+void QQmlScriptBlob::initializeFromCachedUnit(const QQmlPrivate::CachedQmlUnit *cachedUnit)
{
- initializeFromCompilationUnit(QV4::ExecutableCompilationUnit::create(
- QV4::CompiledData::CompilationUnit(unit->qmlData, unit->aotCompiledFunctions, urlString(), finalUrlString())));
+ initializeFromCompilationUnit(QQml::makeRefPointer<QV4::CompiledData::CompilationUnit>(
+ cachedUnit->qmlData, cachedUnit->aotCompiledFunctions, urlString(), finalUrlString()));
}
void QQmlScriptBlob::done()
@@ -162,15 +128,15 @@ void QQmlScriptBlob::done()
return;
// Check all script dependencies for errors
- for (int ii = 0; ii < m_scripts.count(); ++ii) {
+ for (int ii = 0; ii < m_scripts.size(); ++ii) {
const ScriptReference &script = m_scripts.at(ii);
Q_ASSERT(script.script->isCompleteOrError());
if (script.script->isError()) {
QList<QQmlError> errors = script.script->errors();
QQmlError error;
error.setUrl(url());
- error.setLine(qmlConvertSourceCoordinate<quint32, int>(script.location.line));
- error.setColumn(qmlConvertSourceCoordinate<quint32, int>(script.location.column));
+ error.setLine(qmlConvertSourceCoordinate<quint32, int>(script.location.line()));
+ error.setColumn(qmlConvertSourceCoordinate<quint32, int>(script.location.column()));
error.setDescription(QQmlTypeLoader::tr("Script %1 unavailable").arg(script.script->urlString()));
errors.prepend(error);
setError(errors);
@@ -183,7 +149,7 @@ void QQmlScriptBlob::done()
QSet<QString> ns;
- for (int scriptIndex = 0; scriptIndex < m_scripts.count(); ++scriptIndex) {
+ for (int scriptIndex = 0; scriptIndex < m_scripts.size(); ++scriptIndex) {
const ScriptReference &script = m_scripts.at(scriptIndex);
m_scriptData->scripts.append(script.script);
@@ -197,7 +163,7 @@ void QQmlScriptBlob::done()
m_scriptData->typeNameCache->add(script.qualifier, scriptIndex, script.nameSpace);
}
- m_importCache.populateCache(m_scriptData->typeNameCache.data());
+ m_importCache->populateCache(m_scriptData->typeNameCache.data());
}
m_scripts.clear();
}
@@ -218,28 +184,29 @@ void QQmlScriptBlob::scriptImported(const QQmlRefPointer<QQmlScriptBlob> &blob,
m_scripts << ref;
}
-void QQmlScriptBlob::initializeFromCompilationUnit(const QQmlRefPointer<QV4::ExecutableCompilationUnit> &unit)
+void QQmlScriptBlob::initializeFromCompilationUnit(
+ QQmlRefPointer<QV4::CompiledData::CompilationUnit> &&unit)
{
Q_ASSERT(!m_scriptData);
+ Q_ASSERT(unit);
+
m_scriptData.adopt(new QQmlScriptData());
m_scriptData->url = finalUrl();
m_scriptData->urlString = finalUrlString();
m_scriptData->m_precompiledScript = unit;
- m_importCache.setBaseUrl(finalUrl(), finalUrlString());
-
- QQmlRefPointer<QV4::ExecutableCompilationUnit> script = m_scriptData->m_precompiledScript;
+ m_importCache->setBaseUrl(finalUrl(), finalUrlString());
if (!m_isModule) {
QList<QQmlError> errors;
- for (quint32 i = 0, count = script->importCount(); i < count; ++i) {
- const QV4::CompiledData::Import *import = script->importAt(i);
+ for (quint32 i = 0, count = unit->importCount(); i < count; ++i) {
+ const QV4::CompiledData::Import *import = unit->importAt(i);
if (!addImport(import, {}, &errors)) {
Q_ASSERT(errors.size());
QQmlError error(errors.takeFirst());
- error.setUrl(m_importCache.baseUrl());
- error.setLine(import->location.line);
- error.setColumn(import->location.column);
+ error.setUrl(m_importCache->baseUrl());
+ error.setLine(import->location.line());
+ error.setColumn(import->location.column());
errors.prepend(error); // put it back on the list after filling out information.
setError(errors);
return;
@@ -247,19 +214,42 @@ void QQmlScriptBlob::initializeFromCompilationUnit(const QQmlRefPointer<QV4::Exe
}
}
- auto *v4 = QQmlEnginePrivate::getV4Engine(typeLoader()->engine());
-
- v4->injectModule(unit);
+ const QStringList moduleRequests = unit->moduleRequests();
+ for (const QString &request: moduleRequests) {
+ const QUrl relativeRequest = QUrl(request);
+ if (m_typeLoader->injectedScript(relativeRequest))
+ continue;
- for (const QString &request: unit->moduleRequests()) {
- if (v4->moduleForUrl(QUrl(request), unit.data()))
+ const QUrl absoluteRequest = unit->finalUrl().resolved(relativeRequest);
+ QQmlRefPointer<QQmlScriptBlob> absoluteBlob = typeLoader()->getScript(absoluteRequest);
+ if (absoluteBlob->m_scriptData && absoluteBlob->m_scriptData->m_precompiledScript)
continue;
- const QUrl absoluteRequest = unit->finalUrl().resolved(QUrl(request));
- QQmlRefPointer<QQmlScriptBlob> blob = typeLoader()->getScript(absoluteRequest);
- addDependency(blob.data());
- scriptImported(blob, /* ### */QV4::CompiledData::Location(), /*qualifier*/QString(), /*namespace*/QString());
+ addDependency(absoluteBlob.data());
+ scriptImported(
+ absoluteBlob, /* ### */QV4::CompiledData::Location(), /*qualifier*/QString(),
+ /*namespace*/QString());
}
}
+
+/*!
+ \internal
+
+ This initializes a dummy script blob from a "native" ECMAScript module.
+ Native modules are just JavaScript values, possibly objects with members.
+
+ \sa QJSEngine::registerModule()
+ */
+void QQmlScriptBlob::initializeFromNative(const QV4::Value &value)
+{
+ Q_ASSERT(!m_scriptData);
+ m_scriptData.adopt(new QQmlScriptData());
+ m_scriptData->url = finalUrl();
+ m_scriptData->urlString = finalUrlString();
+ m_scriptData->m_loaded = true;
+ m_scriptData->m_value.set(QQmlEnginePrivate::getV4Engine(typeLoader()->engine()), value);
+ m_importCache->setBaseUrl(finalUrl(), finalUrlString());
+}
+
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlscriptblob_p.h b/src/qml/qml/qqmlscriptblob_p.h
index d8cdf5939d..59f969859b 100644
--- a/src/qml/qml/qqmlscriptblob_p.h
+++ b/src/qml/qml/qqmlscriptblob_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 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$
-**
-****************************************************************************/
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLSCRIPTBLOB_P_H
#define QQMLSCRIPTBLOB_P_H
@@ -75,6 +39,7 @@ public:
};
QQmlRefPointer<QQmlScriptData> scriptData() const;
+ bool isNative() const;
protected:
void dataReceived(const SourceCodeData &) override;
@@ -85,7 +50,8 @@ protected:
private:
void scriptImported(const QQmlRefPointer<QQmlScriptBlob> &blob, const QV4::CompiledData::Location &location, const QString &qualifier, const QString &nameSpace) override;
- void initializeFromCompilationUnit(const QQmlRefPointer<QV4::ExecutableCompilationUnit> &unit);
+ void initializeFromCompilationUnit(QQmlRefPointer<QV4::CompiledData::CompilationUnit> &&cu);
+ void initializeFromNative(const QV4::Value &value);
QList<ScriptReference> m_scripts;
QQmlRefPointer<QQmlScriptData> m_scriptData;
diff --git a/src/qml/qml/qqmlscriptdata.cpp b/src/qml/qml/qqmlscriptdata.cpp
index 684564fcfb..9337f25c6e 100644
--- a/src/qml/qml/qqmlscriptdata.cpp
+++ b/src/qml/qml/qqmlscriptdata.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 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$
-**
-****************************************************************************/
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <private/qqmlscriptdata_p.h>
#include <private/qqmlcontext_p.h>
@@ -49,18 +13,12 @@
QT_BEGIN_NAMESPACE
-QQmlScriptData::QQmlScriptData()
- : typeNameCache(nullptr)
- , m_loaded(false)
-{
-}
-
QQmlRefPointer<QQmlContextData> QQmlScriptData::qmlContextDataForContext(
const QQmlRefPointer<QQmlContextData> &parentQmlContextData)
{
Q_ASSERT(parentQmlContextData && parentQmlContextData->engine());
- if (m_precompiledScript->isESModule())
+ if (!m_precompiledScript || m_precompiledScript->isESModule())
return nullptr;
QQmlRefPointer<QQmlContextData> qmlContextData = m_precompiledScript->isSharedLibrary()
@@ -92,15 +50,15 @@ QQmlRefPointer<QQmlContextData> QQmlScriptData::qmlContextDataForContext(
QV4::Scope scope(v4);
QV4::ScopedObject scriptsArray(scope);
if (qmlContextData->importedScripts().isNullOrUndefined()) {
- scriptsArray = v4->newArrayObject(scripts.count());
+ scriptsArray = v4->newArrayObject(scripts.size());
qmlContextData->setImportedScripts(
QV4::PersistentValue(v4, scriptsArray.asReturnedValue()));
} else {
scriptsArray = qmlContextData->importedScripts().valueRef();
}
QV4::ScopedValue v(scope);
- for (int ii = 0; ii < scripts.count(); ++ii) {
- v = scripts.at(ii)->scriptData()->scriptValueForContext(qmlContextData.data());
+ for (int ii = 0; ii < scripts.size(); ++ii) {
+ v = scripts.at(ii)->scriptData()->scriptValueForContext(qmlContextData);
scriptsArray->put(ii, v);
}
@@ -123,7 +81,11 @@ QV4::ReturnedValue QQmlScriptData::scriptValueForContext(
/* scopeObject: */ nullptr);
}
- QV4::Scoped<QV4::Module> module(scope, m_precompiledScript->instantiate(v4));
+ QV4::Scoped<QV4::Module> module(
+ scope,
+ v4->executableCompilationUnit(QQmlRefPointer<QV4::CompiledData::CompilationUnit>(
+ m_precompiledScript))->instantiate());
+
if (module) {
if (qmlExecutionContext) {
module->d()->scope->outer.set(v4, qmlExecutionContext->d());
diff --git a/src/qml/qml/qqmlscriptdata_p.h b/src/qml/qml/qqmlscriptdata_p.h
index 816e968f6e..ad5ffb3d07 100644
--- a/src/qml/qml/qqmlscriptdata_p.h
+++ b/src/qml/qml/qqmlscriptdata_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 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$
-**
-****************************************************************************/
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLSCRIPTDATA_P_H
#define QQMLSCRIPTDATA_P_H
@@ -55,7 +19,7 @@
#include <private/qqmlscriptblob_p.h>
#include <private/qv4value_p.h>
#include <private/qv4persistent_p.h>
-#include <private/qv4executablecompilationunit_p.h>
+#include <private/qv4compileddata_p.h>
#include <QtCore/qurl.h>
@@ -64,12 +28,12 @@ QT_BEGIN_NAMESPACE
class QQmlTypeNameCache;
class QQmlContextData;
-class Q_AUTOTEST_EXPORT QQmlScriptData : public QQmlRefCount
+class Q_AUTOTEST_EXPORT QQmlScriptData final : public QQmlRefCounted<QQmlScriptData>
{
private:
friend class QQmlTypeLoader;
- QQmlScriptData();
+ QQmlScriptData() = default;
public:
QUrl url;
@@ -79,7 +43,10 @@ public:
QV4::ReturnedValue scriptValueForContext(const QQmlRefPointer<QQmlContextData> &parentCtxt);
- QQmlRefPointer<QV4::ExecutableCompilationUnit> compilationUnit() const { return m_precompiledScript; }
+ QQmlRefPointer<QV4::CompiledData::CompilationUnit> compilationUnit() const
+ {
+ return m_precompiledScript;
+ }
private:
friend class QQmlScriptBlob;
@@ -87,8 +54,8 @@ private:
QQmlRefPointer<QQmlContextData> qmlContextDataForContext(
const QQmlRefPointer<QQmlContextData> &parentQmlContextData);
- bool m_loaded;
- QQmlRefPointer<QV4::ExecutableCompilationUnit> m_precompiledScript;
+ bool m_loaded = false;
+ QQmlRefPointer<QV4::CompiledData::CompilationUnit> m_precompiledScript;
QV4::PersistentValue m_value;
};
diff --git a/src/qml/qml/qqmlscriptstring.cpp b/src/qml/qml/qqmlscriptstring.cpp
index 3230e69b6d..9f47841031 100644
--- a/src/qml/qml/qqmlscriptstring.cpp
+++ b/src/qml/qml/qqmlscriptstring.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qqmlscriptstring.h"
#include "qqmlscriptstring_p.h"
@@ -80,7 +44,7 @@ const QQmlScriptStringPrivate* QQmlScriptStringPrivate::get(const QQmlScriptStri
Constructs an empty instance.
*/
QQmlScriptString::QQmlScriptString()
-: d(new QQmlScriptStringPrivate)
+: d()
{
}
@@ -128,6 +92,8 @@ bool QQmlScriptString::operator==(const QQmlScriptString &other) const
{
if (d == other.d)
return true;
+ if (!d || !other.d)
+ return false;
if (d->isNumberLiteral || other.d->isNumberLiteral)
return d->isNumberLiteral && other.d->isNumberLiteral && d->numberValue == other.d->numberValue;
@@ -162,6 +128,8 @@ Returns whether the QQmlScriptString is empty.
*/
bool QQmlScriptString::isEmpty() const
{
+ if (!d)
+ return true;
if (!d->script.isEmpty())
return false;
return d->bindingId == -1;
@@ -172,7 +140,7 @@ Returns whether the content of the QQmlScriptString is the \c undefined literal.
*/
bool QQmlScriptString::isUndefinedLiteral() const
{
- return d->script == QLatin1String("undefined");
+ return d && d->script == QLatin1String("undefined");
}
/*!
@@ -180,7 +148,7 @@ Returns whether the content of the QQmlScriptString is the \c null literal.
*/
bool QQmlScriptString::isNullLiteral() const
{
- return d->script == QLatin1String("null");
+ return d && d->script == QLatin1String("null");
}
/*!
@@ -189,8 +157,8 @@ Otherwise returns a null QString.
*/
QString QQmlScriptString::stringLiteral() const
{
- if (d->isStringLiteral)
- return d->script.mid(1, d->script.length()-2);
+ if (d && d->isStringLiteral)
+ return d->script.mid(1, d->script.size()-2);
return QString();
}
@@ -201,8 +169,8 @@ sets \a ok to true. Otherwise returns 0.0 and sets \a ok to false.
qreal QQmlScriptString::numberLiteral(bool *ok) const
{
if (ok)
- *ok = d->isNumberLiteral;
- return d->isNumberLiteral ? d->numberValue : 0.;
+ *ok = d && d->isNumberLiteral;
+ return (d && d->isNumberLiteral) ? d->numberValue : 0.;
}
/*!
@@ -211,8 +179,8 @@ sets \a ok to true. Otherwise returns false and sets \a ok to false.
*/
bool QQmlScriptString::booleanLiteral(bool *ok) const
{
- bool isTrue = d->script == QLatin1String("true");
- bool isFalse = !isTrue && d->script == QLatin1String("false");
+ bool isTrue = d && d->script == QLatin1String("true");
+ bool isFalse = !isTrue && d && d->script == QLatin1String("false");
if (ok)
*ok = isTrue || isFalse;
return isTrue ? true : false;
@@ -220,3 +188,5 @@ bool QQmlScriptString::booleanLiteral(bool *ok) const
QT_END_NAMESPACE
+#include "moc_qqmlscriptstring.cpp"
+
diff --git a/src/qml/qml/qqmlscriptstring.h b/src/qml/qml/qqmlscriptstring.h
index a768dabf9f..debc3d16c1 100644
--- a/src/qml/qml/qqmlscriptstring.h
+++ b/src/qml/qml/qqmlscriptstring.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLSCRIPTSTRING_H
#define QQMLSCRIPTSTRING_H
@@ -59,7 +23,6 @@ namespace QV4 {
class Q_QML_EXPORT QQmlScriptString
{
Q_GADGET
- QML_ANONYMOUS
public:
QQmlScriptString();
QQmlScriptString(const QQmlScriptString &);
@@ -86,6 +49,7 @@ private:
friend class QQmlScriptStringPrivate;
friend class QQmlExpression;
friend class QQmlBinding;
+ friend class QQmlPropertyBinding;
friend struct QV4::QObjectWrapper;
};
diff --git a/src/qml/qml/qqmlscriptstring_p.h b/src/qml/qml/qqmlscriptstring_p.h
index fd8ccd5d53..a1b078ee8e 100644
--- a/src/qml/qml/qqmlscriptstring_p.h
+++ b/src/qml/qml/qqmlscriptstring_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLSCRIPTSTRING_P_H
#define QQMLSCRIPTSTRING_P_H
@@ -53,6 +17,7 @@
#include "qqmlscriptstring.h"
#include <QtQml/qqmlcontext.h>
+#include <QtCore/private/qglobal_p.h>
QT_BEGIN_NAMESPACE
diff --git a/src/qml/qml/qqmlsourcecoordinate_p.h b/src/qml/qml/qqmlsourcecoordinate_p.h
index 55e11fd147..f7474f4d9b 100644
--- a/src/qml/qml/qqmlsourcecoordinate_p.h
+++ b/src/qml/qml/qqmlsourcecoordinate_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLSOURCECOORDINATE_P_H
#define QQMLSOURCECOORDINATE_P_H
@@ -51,7 +15,7 @@
// We mean it.
//
-#include <QtCore/qglobal.h>
+#include <QtCore/private/qglobal_p.h>
#include <limits>
diff --git a/src/qml/qml/qqmlstringconverters.cpp b/src/qml/qml/qqmlstringconverters.cpp
index 9c2e715a6a..a1f8cce67c 100644
--- a/src/qml/qml/qqmlstringconverters.cpp
+++ b/src/qml/qml/qqmlstringconverters.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qqmlstringconverters_p.h"
#include <private/qqmlglobal_p.h>
@@ -48,9 +12,9 @@
QT_BEGIN_NAMESPACE
-QVariant QQmlStringConverters::variantFromString(const QString &s, int preferredType, bool *ok)
+QVariant QQmlStringConverters::variantFromString(const QString &s, QMetaType preferredType, bool *ok)
{
- switch (preferredType) {
+ switch (preferredType.id()) {
case QMetaType::Int:
return QVariant(int(qRound(s.toDouble(ok))));
case QMetaType::UInt:
@@ -76,11 +40,15 @@ QVariant QQmlStringConverters::variantFromString(const QString &s, int preferred
case QMetaType::QRect:
return QVariant::fromValue(rectFFromString(s, ok).toRect());
default: {
- QVariant ret;
- bool success = QQml_valueTypeProvider()->createValueType(preferredType, QJSValue(s), ret);
+ const QVariant ret = QQmlValueTypeProvider::createValueType(s, preferredType);
+ if (ret.isValid()) {
+ if (ok)
+ *ok = true;
+ return ret;
+ }
if (ok)
- *ok = success;
- return ret;
+ *ok = false;
+ return QVariant();
}
}
}
@@ -121,77 +89,19 @@ QDateTime QQmlStringConverters::dateTimeFromString(const QString &s, bool *ok)
//expects input of "x,y"
QPointF QQmlStringConverters::pointFFromString(const QString &s, bool *ok)
{
- if (s.count(QLatin1Char(',')) != 1) {
- if (ok)
- *ok = false;
- return QPointF();
- }
-
- bool xGood, yGood;
- int index = s.indexOf(QLatin1Char(','));
- qreal xCoord = QStringView{s}.left(index).toDouble(&xGood);
- qreal yCoord = QStringView{s}.mid(index+1).toDouble(&yGood);
- if (!xGood || !yGood) {
- if (ok)
- *ok = false;
- return QPointF();
- }
-
- if (ok)
- *ok = true;
- return QPointF(xCoord, yCoord);
+ return valueTypeFromNumberString<QPointF, 2, u','>(s, ok);
}
//expects input of "widthxheight"
QSizeF QQmlStringConverters::sizeFFromString(const QString &s, bool *ok)
{
- if (s.count(QLatin1Char('x')) != 1) {
- if (ok)
- *ok = false;
- return QSizeF();
- }
-
- bool wGood, hGood;
- int index = s.indexOf(QLatin1Char('x'));
- qreal width = QStringView{s}.left(index).toDouble(&wGood);
- qreal height = QStringView{s}.mid(index+1).toDouble(&hGood);
- if (!wGood || !hGood) {
- if (ok)
- *ok = false;
- return QSizeF();
- }
-
- if (ok)
- *ok = true;
- return QSizeF(width, height);
+ return valueTypeFromNumberString<QSizeF, 2, u'x'>(s, ok);
}
//expects input of "x,y,widthxheight" //### use space instead of second comma?
QRectF QQmlStringConverters::rectFFromString(const QString &s, bool *ok)
{
- if (s.count(QLatin1Char(',')) != 2 || s.count(QLatin1Char('x')) != 1) {
- if (ok)
- *ok = false;
- return QRectF();
- }
-
- bool xGood, yGood, wGood, hGood;
- int index = s.indexOf(QLatin1Char(','));
- qreal x = QStringView{s}.left(index).toDouble(&xGood);
- int index2 = s.indexOf(QLatin1Char(','), index+1);
- qreal y = QStringView{s}.mid(index+1, index2-index-1).toDouble(&yGood);
- index = s.indexOf(QLatin1Char('x'), index2+1);
- qreal width = QStringView{s}.mid(index2+1, index-index2-1).toDouble(&wGood);
- qreal height = QStringView{s}.mid(index+1).toDouble(&hGood);
- if (!xGood || !yGood || !wGood || !hGood) {
- if (ok)
- *ok = false;
- return QRectF();
- }
-
- if (ok)
- *ok = true;
- return QRectF(x, y, width, height);
+ return valueTypeFromNumberString<QRectF, 4, u',', u',', u'x'>(s, ok);
}
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlstringconverters_p.h b/src/qml/qml/qqmlstringconverters_p.h
index 52c602c18e..0d220b11fc 100644
--- a/src/qml/qml/qqmlstringconverters_p.h
+++ b/src/qml/qml/qqmlstringconverters_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLSTRINGCONVERTERS_P_H
#define QQMLSTRINGCONVERTERS_P_H
@@ -66,19 +30,92 @@ class QByteArray;
namespace QQmlStringConverters
{
- Q_QML_PRIVATE_EXPORT QVariant variantFromString(const QString &, int preferredType, bool *ok = nullptr);
+ Q_QML_EXPORT QVariant variantFromString(const QString &, QMetaType preferredType, bool *ok = nullptr);
- Q_QML_PRIVATE_EXPORT QVariant colorFromString(const QString &, bool *ok = nullptr);
- Q_QML_PRIVATE_EXPORT unsigned rgbaFromString(const QString &, bool *ok = nullptr);
+ Q_QML_EXPORT QVariant colorFromString(const QString &, bool *ok = nullptr);
+ Q_QML_EXPORT unsigned rgbaFromString(const QString &, bool *ok = nullptr);
#if QT_CONFIG(datestring)
- Q_QML_PRIVATE_EXPORT QDate dateFromString(const QString &, bool *ok = nullptr);
- Q_QML_PRIVATE_EXPORT QTime timeFromString(const QString &, bool *ok = nullptr);
- Q_QML_PRIVATE_EXPORT QDateTime dateTimeFromString(const QString &, bool *ok = nullptr);
+ Q_QML_EXPORT QDate dateFromString(const QString &, bool *ok = nullptr);
+ Q_QML_EXPORT QTime timeFromString(const QString &, bool *ok = nullptr);
+ Q_QML_EXPORT QDateTime dateTimeFromString(const QString &, bool *ok = nullptr);
#endif
- Q_QML_PRIVATE_EXPORT QPointF pointFFromString(const QString &, bool *ok = nullptr);
- Q_QML_PRIVATE_EXPORT QSizeF sizeFFromString(const QString &, bool *ok = nullptr);
- Q_QML_PRIVATE_EXPORT QRectF rectFFromString(const QString &, bool *ok = nullptr);
+ Q_QML_EXPORT QPointF pointFFromString(const QString &, bool *ok = nullptr);
+ Q_QML_EXPORT QSizeF sizeFFromString(const QString &, bool *ok = nullptr);
+ Q_QML_EXPORT QRectF rectFFromString(const QString &, bool *ok = nullptr);
+
+ // checks if the string contains a list of doubles separated by separators, like "double1
+ // separators1 double2 separators2 ..." for example.
+ template<int NumParams, char16_t... separators>
+ bool isValidNumberString(const QString &s, std::array<double, NumParams> *numbers = nullptr)
+ {
+ Q_STATIC_ASSERT_X(
+ NumParams == 2 || NumParams == 3 || NumParams == 4 || NumParams == 16,
+ "Unsupported number of params; add an additional case below if necessary.");
+ constexpr std::array<char16_t, NumParams - 1> separatorArray{ separators... };
+ // complain about missing separators when first or last entry is initialized with 0
+ Q_STATIC_ASSERT_X(separatorArray[0] != 0,
+ "Did not specify any separators for isValidNumberString.");
+ Q_STATIC_ASSERT_X(separatorArray[NumParams - 2] != 0,
+ "Did not specify enough separators for isValidNumberString.");
+
+ bool floatOk = true;
+ QStringView view(s);
+ for (qsizetype i = 0; i < NumParams - 1; ++i) {
+ const qsizetype commaIndex = view.indexOf(separatorArray[i]);
+ if (commaIndex == -1)
+ return false;
+ const auto current = view.first(commaIndex).toDouble(&floatOk);
+ if (!floatOk)
+ return false;
+ if (numbers)
+ (*numbers)[i] = current;
+
+ view = view.sliced(commaIndex + 1);
+ }
+ const auto current = view.toDouble(&floatOk);
+ if (!floatOk)
+ return false;
+ if (numbers)
+ (*numbers)[NumParams - 1] = current;
+
+ return true;
+ }
+
+ // Constructs a value type T from the given string that contains NumParams double values
+ // separated by separators, like "double1 separators1 double2 separators2 ..." for example.
+ template<typename T, int NumParams, char16_t... separators>
+ T valueTypeFromNumberString(const QString &s, bool *ok = nullptr)
+ {
+ Q_STATIC_ASSERT_X(
+ NumParams == 2 || NumParams == 3 || NumParams == 4 || NumParams == 16,
+ "Unsupported number of params; add an additional case below if necessary.");
+
+ std::array<double, NumParams> parameters;
+ if (!isValidNumberString<NumParams, separators...>(s, &parameters)) {
+ if (ok)
+ *ok = false;
+ return T{};
+ }
+
+ if (ok)
+ *ok = true;
+
+ if constexpr (NumParams == 2) {
+ return T(parameters[0], parameters[1]);
+ } else if constexpr (NumParams == 3) {
+ return T(parameters[0], parameters[1], parameters[2]);
+ } else if constexpr (NumParams == 4) {
+ return T(parameters[0], parameters[1], parameters[2], parameters[3]);
+ } else if constexpr (NumParams == 16) {
+ return T(parameters[0], parameters[1], parameters[2], parameters[3], parameters[4],
+ parameters[5], parameters[6], parameters[7], parameters[8], parameters[9],
+ parameters[10], parameters[11], parameters[12], parameters[13], parameters[14],
+ parameters[15]);
+ }
+
+ Q_UNREACHABLE_RETURN(T{});
+ }
}
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmltype.cpp b/src/qml/qml/qqmltype.cpp
index 811ff668c6..533c3909ba 100644
--- a/src/qml/qml/qqmltype.cpp
+++ b/src/qml/qml/qqmltype.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 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$
-**
-****************************************************************************/
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qqmltype_p_p.h"
@@ -53,45 +17,44 @@
QT_BEGIN_NAMESPACE
QQmlTypePrivate::QQmlTypePrivate(QQmlType::RegistrationType type)
- : regType(type), iid(nullptr), revision(QTypeRevision::zero()),
- containsRevisionedAttributes(false), baseMetaObject(nullptr),
- index(-1), isSetup(false), isEnumFromCacheSetup(false), isEnumFromBaseSetup(false),
- haveSuperType(false)
+ : regType(type)
{
switch (type) {
case QQmlType::CppType:
- extraData.cd = new QQmlCppTypeData;
- extraData.cd->allocationSize = 0;
- extraData.cd->newFunc = nullptr;
- extraData.cd->createValueTypeFunc = nullptr;
- extraData.cd->parserStatusCast = -1;
- extraData.cd->extFunc = nullptr;
- extraData.cd->extMetaObject = nullptr;
- extraData.cd->customParser = nullptr;
- extraData.cd->attachedPropertiesFunc = nullptr;
- extraData.cd->attachedPropertiesType = nullptr;
- extraData.cd->propertyValueSourceCast = -1;
- extraData.cd->propertyValueInterceptorCast = -1;
- extraData.cd->registerEnumClassesUnscoped = true;
+ extraData.cppTypeData = new QQmlCppTypeData;
+ extraData.cppTypeData->allocationSize = 0;
+ extraData.cppTypeData->newFunc = nullptr;
+ extraData.cppTypeData->createValueTypeFunc = nullptr;
+ extraData.cppTypeData->parserStatusCast = -1;
+ extraData.cppTypeData->extFunc = nullptr;
+ extraData.cppTypeData->extMetaObject = nullptr;
+ extraData.cppTypeData->customParser = nullptr;
+ extraData.cppTypeData->attachedPropertiesFunc = nullptr;
+ extraData.cppTypeData->attachedPropertiesType = nullptr;
+ extraData.cppTypeData->propertyValueSourceCast = -1;
+ extraData.cppTypeData->propertyValueInterceptorCast = -1;
+ extraData.cppTypeData->finalizerCast = -1;
+ extraData.cppTypeData->registerEnumClassesUnscoped = true;
+ extraData.cppTypeData->registerEnumsFromRelatedTypes = true;
break;
case QQmlType::SingletonType:
case QQmlType::CompositeSingletonType:
- extraData.sd = new QQmlSingletonTypeData;
- extraData.sd->singletonInstanceInfo = nullptr;
- extraData.sd->extFunc = nullptr;
- extraData.sd->extMetaObject = nullptr;
+ extraData.singletonTypeData = new QQmlSingletonTypeData;
+ extraData.singletonTypeData->singletonInstanceInfo = nullptr;
+ extraData.singletonTypeData->extFunc = nullptr;
+ extraData.singletonTypeData->extMetaObject = nullptr;
break;
case QQmlType::InterfaceType:
- extraData.cd = nullptr;
+ extraData.interfaceTypeData = nullptr;
break;
case QQmlType::CompositeType:
- extraData.fd = new QQmlCompositeTypeData;
+ new (&extraData.compositeTypeData) QUrl();
break;
case QQmlType::InlineComponentType:
- extraData.id = new QQmlInlineTypeData;
+ new (&extraData.inlineComponentTypeData) QUrl();
break;
case QQmlType::SequentialContainerType:
- extraData.ld = new QQmlSequenceTypeData;
+ new (&extraData.sequentialContainerTypeData) QMetaSequence();
break;
default: qFatal("QQmlTypePrivate Internal Error.");
}
@@ -99,27 +62,32 @@ QQmlTypePrivate::QQmlTypePrivate(QQmlType::RegistrationType type)
QQmlTypePrivate::~QQmlTypePrivate()
{
- qDeleteAll(scopedEnums);
- for (const auto &metaObject : metaObjects)
- free(metaObject.metaObject);
+ delete enums.fetchAndStoreAcquire(nullptr);
+ delete proxyMetaObjects.fetchAndStoreAcquire(nullptr);
+
+ if (const QtPrivate::QMetaTypeInterface *iface = typeId.iface()) {
+ if (iface->metaObjectFn == &dynamicQmlMetaObject)
+ QQmlMetaType::unregisterInternalCompositeType(typeId, listId);
+ }
+
switch (regType) {
case QQmlType::CppType:
- delete extraData.cd->customParser;
- delete extraData.cd;
+ delete extraData.cppTypeData->customParser;
+ delete extraData.cppTypeData;
break;
case QQmlType::SingletonType:
case QQmlType::CompositeSingletonType:
- delete extraData.sd->singletonInstanceInfo;
- delete extraData.sd;
+ extraData.singletonTypeData->singletonInstanceInfo.reset();
+ delete extraData.singletonTypeData;
break;
case QQmlType::CompositeType:
- delete extraData.fd;
+ extraData.compositeTypeData.~QUrl();
break;
case QQmlType::InlineComponentType:
- delete extraData.id;
+ extraData.inlineComponentTypeData.~QUrl();
break;
case QQmlType::SequentialContainerType:
- delete extraData.ld;
+ extraData.sequentialContainerTypeData.~QMetaSequence();
break;
default: //Also InterfaceType, because it has no extra data
break;
@@ -178,12 +146,13 @@ QQmlType QQmlTypePrivate::resolveCompositeBaseType(QQmlEnginePrivate *engine) co
QQmlRefPointer<QQmlTypeData> td(engine->typeLoader.getType(sourceUrl()));
if (td.isNull() || !td->isComplete())
return QQmlType();
- QV4::ExecutableCompilationUnit *compilationUnit = td->compilationUnit();
+ QV4::CompiledData::CompilationUnit *compilationUnit = td->compilationUnit();
const QMetaObject *mo = compilationUnit->rootPropertyCache()->firstCppMetaObject();
return QQmlMetaType::qmlType(mo);
}
-QQmlPropertyCache *QQmlTypePrivate::compositePropertyCache(QQmlEnginePrivate *engine) const
+QQmlPropertyCache::ConstPtr QQmlTypePrivate::compositePropertyCache(
+ QQmlEnginePrivate *engine) const
{
// similar logic to resolveCompositeBaseType
Q_ASSERT(isComposite());
@@ -192,8 +161,8 @@ QQmlPropertyCache *QQmlTypePrivate::compositePropertyCache(QQmlEnginePrivate *en
QQmlRefPointer<QQmlTypeData> td(engine->typeLoader.getType(sourceUrl()));
if (td.isNull() || !td->isComplete())
return nullptr;
- QV4::ExecutableCompilationUnit *compilationUnit = td->compilationUnit();
- return compilationUnit->rootPropertyCache().data();
+ QV4::CompiledData::CompilationUnit *compilationUnit = td->compilationUnit();
+ return compilationUnit->rootPropertyCache();
}
static bool isPropertyRevisioned(const QMetaObject *mo, int index)
@@ -201,54 +170,63 @@ static bool isPropertyRevisioned(const QMetaObject *mo, int index)
return mo->property(index).revision();
}
-void QQmlTypePrivate::init() const
+const QQmlTypePrivate::ProxyMetaObjects *QQmlTypePrivate::init() const
{
- if (isSetup.loadAcquire())
- return;
+ if (const ProxyMetaObjects *result = proxyMetaObjects.loadRelaxed())
+ return result;
- QMutexLocker lock(QQmlMetaType::typeRegistrationLock());
- if (isSetup.loadAcquire())
- return;
+ ProxyMetaObjects *proxies = new ProxyMetaObjects;
+ auto finalize = [this, proxies]() -> const ProxyMetaObjects *{
+ const ProxyMetaObjects *concurrentModification;
+ if (proxyMetaObjects.testAndSetOrdered(nullptr, proxies, concurrentModification))
+ return proxies;
+
+ delete proxies;
+ return concurrentModification;
+ };
const QMetaObject *mo = baseMetaObject;
if (!mo) {
// version 0 singleton type without metaobject information
- return;
+ return finalize();
}
- auto setupExtendedMetaObject = [&](
- const QMetaObject *extMetaObject,
- QObject *(*extFunc)(QObject *)) {
+ QList<QQmlProxyMetaObject::ProxyData> metaObjects;
+ auto setupExtendedMetaObject = [&](const QMetaObject *extMetaObject,
+ QObject *(*extFunc)(QObject *)) {
if (!extMetaObject)
return;
// XXX - very inefficient
QMetaObjectBuilder builder;
- QQmlMetaType::clone(builder, extMetaObject, extMetaObject, extMetaObject);
- builder.setFlags(MetaObjectFlag::DynamicMetaObject);
+ QQmlMetaType::clone(builder, extMetaObject, extMetaObject, extMetaObject,
+ extFunc ? QQmlMetaType::CloneAll : QQmlMetaType::CloneEnumsOnly);
QMetaObject *mmo = builder.toMetaObject();
mmo->d.superdata = mo;
QQmlProxyMetaObject::ProxyData data = { mmo, extFunc, 0, 0 };
metaObjects << data;
+ QQmlMetaType::registerMetaObjectForType(mmo, const_cast<QQmlTypePrivate *>(this));
};
if (regType == QQmlType::SingletonType)
- setupExtendedMetaObject(extraData.sd->extMetaObject, extraData.sd->extFunc);
+ setupExtendedMetaObject(extraData.singletonTypeData->extMetaObject, extraData.singletonTypeData->extFunc);
else if (regType == QQmlType::CppType)
- setupExtendedMetaObject(extraData.cd->extMetaObject, extraData.cd->extFunc);
+ setupExtendedMetaObject(extraData.cppTypeData->extMetaObject, extraData.cppTypeData->extFunc);
metaObjects.append(QQmlMetaType::proxyData(
mo, baseMetaObject, metaObjects.isEmpty() ? nullptr
: metaObjects.constLast().metaObject));
- for (int ii = 0; ii < metaObjects.count(); ++ii) {
+ for (int ii = 0; ii < metaObjects.size(); ++ii) {
metaObjects[ii].propertyOffset =
metaObjects.at(ii).metaObject->propertyOffset();
metaObjects[ii].methodOffset =
metaObjects.at(ii).metaObject->methodOffset();
}
+ bool containsRevisionedAttributes = false;
+
// Check for revisioned details
{
const QMetaObject *mo = nullptr;
@@ -268,53 +246,75 @@ void QQmlTypePrivate::init() const
}
}
- isSetup.storeRelease(true);
- lock.unlock();
+ proxies->data = std::move(metaObjects);
+ proxies->containsRevisionedAttributes = containsRevisionedAttributes;
+
+ return finalize();
}
-void QQmlTypePrivate::initEnums(QQmlEnginePrivate *engine) const
+const QQmlTypePrivate::Enums *QQmlTypePrivate::initEnums(QQmlEnginePrivate *engine) const
{
- const QQmlPropertyCache *cache = (!isEnumFromCacheSetup.loadAcquire() && isComposite())
- ? compositePropertyCache(engine)
- : nullptr;
+ if (const Enums *result = enums.loadRelaxed())
+ return result;
- // beware: It could be a singleton type without metaobject
- const QMetaObject *metaObject = !isEnumFromBaseSetup.loadAcquire()
- ? baseMetaObject
- : nullptr;
+ QQmlPropertyCache::ConstPtr cache;
+ if (isComposite()) {
+ cache = compositePropertyCache(engine);
+ if (!cache)
+ return nullptr; // Composite type not ready, yet.
+ }
- if (!cache && !metaObject)
- return;
+ Enums *newEnums = new Enums;
- init(); // init() can add to the metaObjects list. Therefore, check metaObjects only below
+ // beware: It could be a singleton type without metaobject
- QMutexLocker lock(QQmlMetaType::typeRegistrationLock());
+ if (cache)
+ insertEnumsFromPropertyCache(newEnums, cache);
- if (cache) {
- insertEnumsFromPropertyCache(cache);
- isEnumFromCacheSetup.storeRelease(true);
+ if (baseMetaObject) {
+ // init() can add to the metaObjects list. Therefore, check proxies->data only below
+ const ProxyMetaObjects *proxies = init();
+ insertEnums(
+ newEnums,
+ proxies->data.isEmpty() ? baseMetaObject : proxies->data.constFirst().metaObject);
}
- if (metaObject) {
- insertEnums(metaObjects.isEmpty() ? baseMetaObject : metaObjects.constFirst().metaObject);
- isEnumFromBaseSetup.storeRelease(true);
- }
+ const Enums *concurrentModification;
+ if (enums.testAndSetOrdered(nullptr, newEnums, concurrentModification))
+ return newEnums;
+
+ delete newEnums;
+ return concurrentModification;
}
-void QQmlTypePrivate::insertEnums(const QMetaObject *metaObject) const
+void QQmlTypePrivate::insertEnums(Enums *enums, const QMetaObject *metaObject) const
{
// Add any enum values defined by 'related' classes
- if (metaObject->d.relatedMetaObjects) {
- const auto *related = metaObject->d.relatedMetaObjects;
- if (related) {
- while (*related)
- insertEnums(*related++);
+ if (regType != QQmlType::CppType || extraData.cppTypeData->registerEnumsFromRelatedTypes) {
+ if (const auto *related = metaObject->d.relatedMetaObjects) {
+ while (const QMetaObject *relatedMetaObject = *related) {
+ insertEnums(enums, relatedMetaObject);
+ ++related;
+ }
}
}
QSet<QString> localEnums;
const QMetaObject *localMetaObject = nullptr;
+ // ### TODO (QTBUG-123294): track this at instance creation time
+ auto shouldSingletonAlsoRegisterUnscoped = [&](){
+ Q_ASSERT(regType == QQmlType::SingletonType);
+ if (!baseMetaObject)
+ return true;
+ int idx = baseMetaObject->indexOfClassInfo("RegisterEnumClassesUnscoped");
+ if (idx == -1)
+ return true;
+ if (qstrcmp(baseMetaObject->classInfo(idx).value(), "false") == 0)
+ return false;
+ return true;
+ };
+
// Add any enum values defined by this class, overwriting any inherited values
for (int ii = 0; ii < metaObject->enumeratorCount(); ++ii) {
QMetaEnum e = metaObject->enumerator(ii);
@@ -331,29 +331,33 @@ void QQmlTypePrivate::insertEnums(const QMetaObject *metaObject) const
localEnums.clear();
localMetaObject = e.enclosingMetaObject();
}
+ const bool shouldRegisterUnscoped = !isScoped
+ || (regType == QQmlType::CppType && extraData.cppTypeData->registerEnumClassesUnscoped)
+ || (regType == QQmlType::SingletonType && shouldSingletonAlsoRegisterUnscoped())
+ ;
for (int jj = 0; jj < e.keyCount(); ++jj) {
const QString key = QString::fromUtf8(e.key(jj));
const int value = e.value(jj);
- if (!isScoped || (regType == QQmlType::CppType && extraData.cd->registerEnumClassesUnscoped)) {
+ if (shouldRegisterUnscoped) {
if (localEnums.contains(key)) {
- auto existingEntry = enums.find(key);
- if (existingEntry != enums.end() && existingEntry.value() != value) {
+ auto existingEntry = enums->enums.find(key);
+ if (existingEntry != enums->enums.end() && existingEntry.value() != value) {
qWarning("Previously registered enum will be overwritten due to name clash: %s.%s", metaObject->className(), key.toUtf8().constData());
createEnumConflictReport(metaObject, key);
}
} else {
localEnums.insert(key);
}
- enums.insert(key, value);
+ enums->enums.insert(key, value);
}
if (isScoped)
scoped->insert(key, value);
}
if (isScoped) {
- scopedEnums << scoped;
- scopedEnumIndex.insert(QString::fromUtf8(e.name()), scopedEnums.count()-1);
+ enums->scopedEnums << scoped;
+ enums->scopedEnumIndex.insert(QString::fromUtf8(e.name()), enums->scopedEnums.size()-1);
}
}
}
@@ -404,41 +408,37 @@ void QQmlTypePrivate::createEnumConflictReport(const QMetaObject *metaObject, co
qWarning().noquote() << QLatin1String("Possible conflicting items:");
// find items with conflicting key
- for (const auto &i : qAsConst(enumInfoList)) {
+ for (const auto &i : std::as_const(enumInfoList)) {
if (i.enumKey == conflictingKey)
qWarning().noquote().nospace() << " " << i.metaObjectName << "." << i.enumName << "." << i.enumKey << " from scope "
<< i.metaEnumScope << " injected by " << i.path.join(QLatin1String("->"));
}
}
-void QQmlTypePrivate::insertEnumsFromPropertyCache(const QQmlPropertyCache *cache) const
+void QQmlTypePrivate::insertEnumsFromPropertyCache(
+ Enums *enums, const QQmlPropertyCache::ConstPtr &cache) const
{
const QMetaObject *cppMetaObject = cache->firstCppMetaObject();
- while (cache && cache->metaObject() != cppMetaObject) {
+ for (const QQmlPropertyCache *currentCache = cache.data();
+ currentCache && currentCache->metaObject() != cppMetaObject;
+ currentCache = currentCache->parent().data()) {
- int count = cache->qmlEnumCount();
+ int count = currentCache->qmlEnumCount();
for (int ii = 0; ii < count; ++ii) {
QStringHash<int> *scoped = new QStringHash<int>();
- QQmlEnumData *enumData = cache->qmlEnum(ii);
+ QQmlEnumData *enumData = currentCache->qmlEnum(ii);
- for (int jj = 0; jj < enumData->values.count(); ++jj) {
+ for (int jj = 0; jj < enumData->values.size(); ++jj) {
const QQmlEnumValue &value = enumData->values.at(jj);
- enums.insert(value.namedValue, value.value);
+ enums->enums.insert(value.namedValue, value.value);
scoped->insert(value.namedValue, value.value);
}
- scopedEnums << scoped;
- scopedEnumIndex.insert(enumData->name, scopedEnums.count()-1);
+ enums->scopedEnums << scoped;
+ enums->scopedEnumIndex.insert(enumData->name, enums->scopedEnums.size()-1);
}
- cache = cache->parent();
}
- insertEnums(cppMetaObject);
-}
-
-void QQmlTypePrivate::setContainingType(QQmlType *containingType)
-{
- Q_ASSERT(regType == QQmlType::InlineComponentType);
- extraData.id->containingType = containingType->d.data();
+ insertEnums(enums, cppMetaObject);
}
void QQmlTypePrivate::setName(const QString &uri, const QString &element)
@@ -452,11 +452,9 @@ QByteArray QQmlType::typeName() const
{
if (d) {
if (d->regType == SingletonType || d->regType == CompositeSingletonType)
- return d->extraData.sd->singletonInstanceInfo->typeName.toUtf8();
+ return d->extraData.singletonTypeData->singletonInstanceInfo->typeName;
else if (d->baseMetaObject)
return d->baseMetaObject->className();
- else if (d->regType == InlineComponentType)
- return d->extraData.id->inlineComponentName.toUtf8();
}
return QByteArray();
}
@@ -475,43 +473,68 @@ QString QQmlType::qmlTypeName() const
return d->name;
}
+/*!
+ \internal
+ Allocates and initializes an object if the type is creatable.
+ Returns a pointer to the object, or nullptr if the type was
+ not creatable.
+ */
QObject *QQmlType::create() const
{
- if (!d || !isCreatable())
- return nullptr;
+ void *unused;
+ return create(&unused, 0);
+}
- d->init();
+/*!
+ \internal
+ \brief Like create without arguments, but allocates some extra space after the object.
+ \param memory An out-only argument. *memory will point to the start of the additionally
+ allocated memory.
+ \param additionalMemory The amount of extra memory in bytes that shoudld be allocated.
- QObject *rv = (QObject *)operator new(d->extraData.cd->allocationSize);
+ \note This function is used to allocate the QQmlData next to the object in the
+ QQmlObjectCreator.
- d->extraData.cd->newFunc(rv, d->extraData.cd->userdata);
+ \overload
+ */
+QObject *QQmlType::create(void **memory, size_t additionalMemory) const
+{
+ if (!d || !isCreatable())
+ return nullptr;
+
+ QObject *rv = (QObject *)operator new(d->extraData.cppTypeData->allocationSize + additionalMemory);
+ d->extraData.cppTypeData->newFunc(rv, d->extraData.cppTypeData->userdata);
createProxy(rv);
+ *memory = ((char *)rv) + d->extraData.cppTypeData->allocationSize;
return rv;
}
-void QQmlType::create(QObject **out, void **memory, size_t additionalMemory) const
+/*!
+ \internal
+ Like create, but also allocates memory behind the object, constructs a QQmlData there
+ and lets the objects declarativeData point to the newly created QQmlData.
+ */
+QObject *QQmlType::createWithQQmlData() const
{
- if (!d || !isCreatable())
- return;
-
- d->init();
-
- QObject *rv = (QObject *)operator new(d->extraData.cd->allocationSize + additionalMemory);
- d->extraData.cd->newFunc(rv, d->extraData.cd->userdata);
-
- createProxy(rv);
- *out = rv;
- *memory = ((char *)rv) + d->extraData.cd->allocationSize;
+ void *ddataMemory = nullptr;
+ auto instance = create(&ddataMemory, sizeof(QQmlData));
+ if (!instance)
+ return nullptr;
+ QObjectPrivate* p = QObjectPrivate::get(instance);
+ Q_ASSERT(!p->isDeletingChildren);
+ if (!p->declarativeData)
+ p->declarativeData = new (ddataMemory) QQmlData(QQmlData::DoesNotOwnMemory);
+ return instance;
}
-QQmlType::SingletonInstanceInfo *QQmlType::singletonInstanceInfo() const
+QQmlType::SingletonInstanceInfo::ConstPtr QQmlType::singletonInstanceInfo() const
{
if (!d)
- return nullptr;
+ return {};
if (d->regType != SingletonType && d->regType != CompositeSingletonType)
- return nullptr;
- return d->extraData.sd->singletonInstanceInfo;
+ return {};
+ return d->extraData.singletonTypeData->singletonInstanceInfo;
}
QQmlCustomParser *QQmlType::customParser() const
@@ -520,33 +543,47 @@ QQmlCustomParser *QQmlType::customParser() const
return nullptr;
if (d->regType != CppType)
return nullptr;
- return d->extraData.cd->customParser;
+ return d->extraData.cppTypeData->customParser;
}
QQmlType::CreateValueTypeFunc QQmlType::createValueTypeFunction() const
{
if (!d || d->regType != CppType)
return nullptr;
- return d->extraData.cd->createValueTypeFunc;
+ return d->extraData.cppTypeData->createValueTypeFunc;
+}
+
+bool QQmlType::canConstructValueType() const
+{
+ if (!d || d->regType != CppType)
+ return false;
+ return d->extraData.cppTypeData->constructValueType;
+}
+
+bool QQmlType::canPopulateValueType() const
+{
+ if (!d || d->regType != CppType)
+ return false;
+ return d->extraData.cppTypeData->populateValueType;
}
QQmlType::CreateFunc QQmlType::createFunction() const
{
if (!d || d->regType != CppType)
return nullptr;
- return d->extraData.cd->newFunc;
+ return d->extraData.cppTypeData->newFunc;
}
QString QQmlType::noCreationReason() const
{
if (!d || d->regType != CppType)
return QString();
- return d->extraData.cd->noCreationReason;
+ return d->extraData.cppTypeData->noCreationReason;
}
bool QQmlType::isCreatable() const
{
- return d && d->regType == CppType && d->extraData.cd->newFunc;
+ return d && d->regType == CppType && d->extraData.cppTypeData->newFunc;
}
QQmlType::ExtensionFunc QQmlType::extensionFunction() const
@@ -556,9 +593,9 @@ QQmlType::ExtensionFunc QQmlType::extensionFunction() const
switch (d->regType) {
case CppType:
- return d->extraData.cd->extFunc;
+ return d->extraData.cppTypeData->extFunc;
case SingletonType:
- return d->extraData.sd->extFunc;
+ return d->extraData.singletonTypeData->extFunc;
default:
return nullptr;
}
@@ -571,9 +608,9 @@ const QMetaObject *QQmlType::extensionMetaObject() const
switch (d->regType) {
case CppType:
- return d->extraData.cd->extMetaObject;
+ return d->extraData.cppTypeData->extMetaObject;
case SingletonType:
- return d->extraData.sd->extMetaObject;
+ return d->extraData.singletonTypeData->extMetaObject;
default:
return nullptr;
}
@@ -581,11 +618,7 @@ const QMetaObject *QQmlType::extensionMetaObject() const
bool QQmlType::isExtendedType() const
{
- if (!d)
- return false;
- d->init();
-
- return !d->metaObjects.isEmpty();
+ return d && !d->init()->data.isEmpty();
}
bool QQmlType::isSingleton() const
@@ -614,12 +647,12 @@ bool QQmlType::isCompositeSingleton() const
bool QQmlType::isQObjectSingleton() const
{
- return d && d->regType == SingletonType && d->extraData.sd->singletonInstanceInfo->qobjectCallback;
+ return d && d->regType == SingletonType && d->extraData.singletonTypeData->singletonInstanceInfo->qobjectCallback;
}
bool QQmlType::isQJSValueSingleton() const
{
- return d && d->regType == SingletonType && d->extraData.sd->singletonInstanceInfo->scriptCallback;
+ return d && d->regType == SingletonType && d->extraData.singletonTypeData->singletonInstanceInfo->scriptCallback;
}
bool QQmlType::isSequentialContainer() const
@@ -627,6 +660,11 @@ bool QQmlType::isSequentialContainer() const
return d && d->regType == SequentialContainerType;
}
+bool QQmlType::isValueType() const
+{
+ return d && d->isValueType();
+}
+
QMetaType QQmlType::typeId() const
{
return d ? d->typeId : QMetaType{};
@@ -637,17 +675,20 @@ QMetaType QQmlType::qListTypeId() const
return d ? d->listId : QMetaType{};
}
-const QMetaObject *QQmlType::metaObject() const
+QMetaSequence QQmlType::listMetaSequence() const
{
- if (!d)
- return nullptr;
- d->init();
+ return isSequentialContainer() ? d->extraData.sequentialContainerTypeData : QMetaSequence();
+}
- if (d->metaObjects.isEmpty())
- return d->baseMetaObject;
- else
- return d->metaObjects.constFirst().metaObject;
+const QMetaObject *QQmlType::metaObject() const
+{
+ return d ? d->metaObject() : nullptr;
+}
+const QMetaObject *QQmlType::metaObjectForValueType() const
+{
+ Q_ASSERT(d);
+ return d->metaObjectForValueType();
}
const QMetaObject *QQmlType::baseMetaObject() const
@@ -657,11 +698,7 @@ const QMetaObject *QQmlType::baseMetaObject() const
bool QQmlType::containsRevisionedAttributes() const
{
- if (!d)
- return false;
- d->init();
-
- return d->containsRevisionedAttributes;
+ return d && d->init()->containsRevisionedAttributes;
}
QTypeRevision QQmlType::metaObjectRevision() const
@@ -672,14 +709,14 @@ QTypeRevision QQmlType::metaObjectRevision() const
QQmlAttachedPropertiesFunc QQmlType::attachedPropertiesFunction(QQmlEnginePrivate *engine) const
{
if (const QQmlTypePrivate *base = d ? d->attachedPropertiesBase(engine) : nullptr)
- return base->extraData.cd->attachedPropertiesFunc;
+ return base->extraData.cppTypeData->attachedPropertiesFunc;
return nullptr;
}
const QMetaObject *QQmlType::attachedPropertiesType(QQmlEnginePrivate *engine) const
{
if (const QQmlTypePrivate *base = d ? d->attachedPropertiesBase(engine) : nullptr)
- return base->extraData.cd->attachedPropertiesType;
+ return base->extraData.cppTypeData->attachedPropertiesType;
return nullptr;
}
@@ -687,28 +724,35 @@ int QQmlType::parserStatusCast() const
{
if (!d || d->regType != CppType)
return -1;
- return d->extraData.cd->parserStatusCast;
+ return d->extraData.cppTypeData->parserStatusCast;
}
int QQmlType::propertyValueSourceCast() const
{
if (!d || d->regType != CppType)
return -1;
- return d->extraData.cd->propertyValueSourceCast;
+ return d->extraData.cppTypeData->propertyValueSourceCast;
}
int QQmlType::propertyValueInterceptorCast() const
{
if (!d || d->regType != CppType)
return -1;
- return d->extraData.cd->propertyValueInterceptorCast;
+ return d->extraData.cppTypeData->propertyValueInterceptorCast;
+}
+
+int QQmlType::finalizerCast() const
+{
+ if (!d || d->regType != CppType)
+ return -1;
+ return d->extraData.cppTypeData->finalizerCast;
}
const char *QQmlType::interfaceIId() const
{
if (!d || d->regType != InterfaceType)
return nullptr;
- return d->iid;
+ return d->extraData.interfaceTypeData;
}
int QQmlType::index() const
@@ -720,200 +764,49 @@ bool QQmlType::isInlineComponentType() const {
return d ? d->regType == QQmlType::InlineComponentType : false;
}
-int QQmlType::inlineComponentId() const {
- bool ok = false;
- if (d->regType == QQmlType::RegistrationType::InlineComponentType) {
- Q_ASSERT(d->extraData.id->objectId != -1);
- return d->extraData.id->objectId;
- }
- int subObjectId = sourceUrl().fragment().toInt(&ok);
- return ok ? subObjectId : -1;
-}
-
QUrl QQmlType::sourceUrl() const
{
- auto url = d ? d->sourceUrl() : QUrl();
- if (url.isValid() && d->regType == QQmlType::RegistrationType::InlineComponentType && d->extraData.id->objectId) {
- Q_ASSERT(url.hasFragment());
- url.setFragment(QString::number(inlineComponentId()));
- }
- return url;
+ return d ? d->sourceUrl() : QUrl();
}
int QQmlType::enumValue(QQmlEnginePrivate *engine, const QHashedStringRef &name, bool *ok) const
{
- Q_ASSERT(ok);
- if (d) {
- *ok = true;
-
- d->initEnums(engine);
-
- int *rv = d->enums.value(name);
- if (rv)
- return *rv;
- }
-
- *ok = false;
- return -1;
+ return QQmlTypePrivate::enumValue(d, engine, name, ok);
}
int QQmlType::enumValue(QQmlEnginePrivate *engine, const QHashedCStringRef &name, bool *ok) const
{
- Q_ASSERT(ok);
- if (d) {
- *ok = true;
-
- d->initEnums(engine);
-
- int *rv = d->enums.value(name);
- if (rv)
- return *rv;
- }
-
- *ok = false;
- return -1;
+ return QQmlTypePrivate::enumValue(d, engine, name, ok);
}
int QQmlType::enumValue(QQmlEnginePrivate *engine, const QV4::String *name, bool *ok) const
{
- Q_ASSERT(ok);
- if (d) {
- *ok = true;
-
- d->initEnums(engine);
-
- int *rv = d->enums.value(name);
- if (rv)
- return *rv;
- }
-
- *ok = false;
- return -1;
+ return QQmlTypePrivate::enumValue(d, engine, name, ok);
}
int QQmlType::scopedEnumIndex(QQmlEnginePrivate *engine, const QV4::String *name, bool *ok) const
{
- Q_ASSERT(ok);
- if (d) {
- *ok = true;
-
- d->initEnums(engine);
-
- int *rv = d->scopedEnumIndex.value(name);
- if (rv)
- return *rv;
- }
-
- *ok = false;
- return -1;
+ return QQmlTypePrivate::scopedEnumIndex(d, engine, name, ok);
}
int QQmlType::scopedEnumIndex(QQmlEnginePrivate *engine, const QString &name, bool *ok) const
{
- Q_ASSERT(ok);
- if (d) {
- *ok = true;
-
- d->initEnums(engine);
-
- int *rv = d->scopedEnumIndex.value(name);
- if (rv)
- return *rv;
- }
-
- *ok = false;
- return -1;
+ return QQmlTypePrivate::scopedEnumIndex(d, engine, name, ok);
}
int QQmlType::scopedEnumValue(QQmlEnginePrivate *engine, int index, const QV4::String *name, bool *ok) const
{
- Q_UNUSED(engine);
- Q_ASSERT(ok);
- *ok = true;
-
- if (d) {
- Q_ASSERT(index > -1 && index < d->scopedEnums.count());
- int *rv = d->scopedEnums.at(index)->value(name);
- if (rv)
- return *rv;
- }
-
- *ok = false;
- return -1;
+ return QQmlTypePrivate::scopedEnumValue(d, engine, index, name, ok);
}
int QQmlType::scopedEnumValue(QQmlEnginePrivate *engine, int index, const QString &name, bool *ok) const
{
- Q_UNUSED(engine);
- Q_ASSERT(ok);
- *ok = true;
-
- if (d) {
- Q_ASSERT(index > -1 && index < d->scopedEnums.count());
- int *rv = d->scopedEnums.at(index)->value(name);
- if (rv)
- return *rv;
- }
-
- *ok = false;
- return -1;
+ return QQmlTypePrivate::scopedEnumValue(d, engine, index, name, ok);
}
-int QQmlType::scopedEnumValue(QQmlEnginePrivate *engine, const QByteArray &scopedEnumName, const QByteArray &name, bool *ok) const
+int QQmlType::scopedEnumValue(QQmlEnginePrivate *engine, const QHashedStringRef &scopedEnumName, const QHashedStringRef &name, bool *ok) const
{
- Q_ASSERT(ok);
- if (d) {
- *ok = true;
-
- d->initEnums(engine);
-
- int *rv = d->scopedEnumIndex.value(QHashedCStringRef(scopedEnumName.constData(), scopedEnumName.length()));
- if (rv) {
- int index = *rv;
- Q_ASSERT(index > -1 && index < d->scopedEnums.count());
- rv = d->scopedEnums.at(index)->value(QHashedCStringRef(name.constData(), name.length()));
- if (rv)
- return *rv;
- }
- }
-
- *ok = false;
- return -1;
-}
-
-int QQmlType::scopedEnumValue(QQmlEnginePrivate *engine, QStringView scopedEnumName, QStringView name, bool *ok) const
-{
- Q_ASSERT(ok);
- if (d) {
- *ok = true;
-
- d->initEnums(engine);
-
- int *rv = d->scopedEnumIndex.value(QHashedStringRef(scopedEnumName));
- if (rv) {
- int index = *rv;
- Q_ASSERT(index > -1 && index < d->scopedEnums.count());
- rv = d->scopedEnums.at(index)->value(QHashedStringRef(name));
- if (rv)
- return *rv;
- }
- }
-
- *ok = false;
- return -1;
-}
-
-int QQmlType::inlineComponentObjectId() const
-{
- if (!isInlineComponentType())
- return -1;
- return d->extraData.id->objectId;
-}
-
-void QQmlType::setInlineComponentObjectId(int id) const
-{
- Q_ASSERT(d && d->regType == QQmlType::InlineComponentType);
- d->extraData.id->objectId = id;
+ return QQmlTypePrivate::scopedEnumValue(d, engine, scopedEnumName, name, ok);
}
void QQmlType::refHandle(const QQmlTypePrivate *priv)
@@ -935,72 +828,11 @@ int QQmlType::refCount(const QQmlTypePrivate *priv)
return -1;
}
-int QQmlType::lookupInlineComponentIdByName(const QString &name) const
-{
- Q_ASSERT(d);
- return d->namesToInlineComponentObjectIndex.value(name, -1);
-}
-
-QQmlType QQmlType::containingType() const
-{
- Q_ASSERT(d && d->regType == QQmlType::RegistrationType::InlineComponentType);
- auto ret = QQmlType {d->extraData.id->containingType};
- Q_ASSERT(!ret.isInlineComponentType());
- return ret;
-}
-
-QQmlType QQmlType::lookupInlineComponentById(int objectid) const
-{
- Q_ASSERT(d);
- return d->objectIdToICType.value(objectid, QQmlType(nullptr));
-}
-
-int QQmlType::generatePlaceHolderICId() const
-{
- Q_ASSERT(d);
- int id = -2;
- for (auto it = d->objectIdToICType.keyBegin(); it != d->objectIdToICType.keyEnd(); ++it)
- if (*it < id)
- id = *it;
- return id;
-}
-
-void QQmlType::associateInlineComponent(const QString &name, int objectID, const CompositeMetaTypeIds &metaTypeIds, QQmlType existingType)
-{
- bool const reuseExistingType = existingType.isValid();
- auto priv = reuseExistingType ? const_cast<QQmlTypePrivate *>(existingType.d.data()) : new QQmlTypePrivate { RegistrationType::InlineComponentType } ;
- priv->setName( QString::fromUtf8(typeName()), name);
- auto icUrl = QUrl(sourceUrl());
- icUrl.setFragment(QString::number(objectID));
- priv->extraData.id->url = icUrl;
- priv->extraData.id->containingType = d.data();
- priv->extraData.id->objectId = objectID;
- priv->typeId = metaTypeIds.id;
- priv->listId = metaTypeIds.listId;
- d->namesToInlineComponentObjectIndex.insert(name, objectID);
- QQmlType icType(priv);
- d->objectIdToICType.insert(objectID, icType);
- if (!reuseExistingType)
- priv->release();
-}
-
-void QQmlType::setPendingResolutionName(const QString &name)
-{
- Q_ASSERT(d && d->regType == QQmlType::RegistrationType::InlineComponentType);
- Q_ASSERT(d->extraData.id->inlineComponentName == name|| d->extraData.id->inlineComponentName.isEmpty());
- d->extraData.id->inlineComponentName = name;
-}
-
-QString QQmlType::pendingResolutionName() const
-{
- Q_ASSERT(d && d->regType == QQmlType::RegistrationType::InlineComponentType);
- return d->extraData.id->inlineComponentName;
-}
-
void QQmlType::createProxy(QObject *instance) const
{
- if (!d->metaObjects.isEmpty())
- (void)new QQmlProxyMetaObject(instance, &d->metaObjects);
+ const QQmlTypePrivate::ProxyMetaObjects *proxies = d->init();
+ if (!proxies->data.isEmpty())
+ (void)new QQmlProxyMetaObject(instance, &proxies->data);
}
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmltype_p.h b/src/qml/qml/qqmltype_p.h
index cbbfe955cc..622e91a4b2 100644
--- a/src/qml/qml/qqmltype_p.h
+++ b/src/qml/qml/qqmltype_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 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$
-**
-****************************************************************************/
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLTYPE_P_H
#define QQMLTYPE_P_H
@@ -75,9 +39,8 @@ class QQmlPropertyCache;
namespace QV4 {
struct String;
}
-struct CompositeMetaTypeIds;
-class Q_QML_PRIVATE_EXPORT QQmlType
+class Q_QML_EXPORT QQmlType
{
public:
QQmlType();
@@ -88,10 +51,6 @@ public:
explicit QQmlType(const QQmlTypePrivate *priv);
~QQmlType();
- bool operator ==(const QQmlType &other) const {
- return d.data() == other.d.data();
- }
-
bool isValid() const { return !d.isNull(); }
QByteArray typeName() const;
@@ -107,8 +66,12 @@ public:
typedef QVariant (*CreateValueTypeFunc)(const QJSValue &);
CreateValueTypeFunc createValueTypeFunction() const;
+ bool canConstructValueType() const;
+ bool canPopulateValueType() const;
+
QObject *create() const;
- void create(QObject **, void **, size_t) const;
+ QObject *create(void **, size_t) const;
+ QObject *createWithQQmlData() const;
typedef void (*CreateFunc)(void *, void *);
CreateFunc createFunction() const;
@@ -129,11 +92,17 @@ public:
bool isQObjectSingleton() const;
bool isQJSValueSingleton() const;
bool isSequentialContainer() const;
+ bool isValueType() const;
QMetaType typeId() const;
QMetaType qListTypeId() const;
+ QMetaSequence listMetaSequence() const;
const QMetaObject *metaObject() const;
+
+ // Precondition: The type is actually a value type!
+ const QMetaObject *metaObjectForValueType() const;
+
const QMetaObject *baseMetaObject() const;
QTypeRevision metaObjectRevision() const;
bool containsRevisionedAttributes() const;
@@ -145,21 +114,30 @@ public:
const char *interfaceIId() const;
int propertyValueSourceCast() const;
int propertyValueInterceptorCast() const;
+ int finalizerCast() const;
int index() const;
bool isInlineComponentType() const;
- int inlineComponentId() const;
- struct Q_QML_PRIVATE_EXPORT SingletonInstanceInfo
+ struct Q_QML_EXPORT SingletonInstanceInfo final
+ : public QQmlRefCounted<SingletonInstanceInfo>
{
+ using Ptr = QQmlRefPointer<SingletonInstanceInfo>;
+ using ConstPtr = QQmlRefPointer<const SingletonInstanceInfo>;
+
+ static Ptr create() { return Ptr(new SingletonInstanceInfo, Ptr::Adopt); }
+
std::function<QJSValue(QQmlEngine *, QJSEngine *)> scriptCallback = {};
std::function<QObject *(QQmlEngine *, QJSEngine *)> qobjectCallback = {};
- const QMetaObject *instanceMetaObject = nullptr;
- QString typeName;
+ QByteArray typeName;
QUrl url; // used by composite singletons
+
+ private:
+ Q_DISABLE_COPY_MOVE(SingletonInstanceInfo)
+ SingletonInstanceInfo() = default;
};
- SingletonInstanceInfo *singletonInstanceInfo() const;
+ SingletonInstanceInfo::ConstPtr singletonInstanceInfo() const;
QUrl sourceUrl() const;
@@ -171,10 +149,7 @@ public:
int scopedEnumIndex(QQmlEnginePrivate *engine, const QString &, bool *ok) const;
int scopedEnumValue(QQmlEnginePrivate *engine, int index, const QV4::String *, bool *ok) const;
int scopedEnumValue(QQmlEnginePrivate *engine, int index, const QString &, bool *ok) const;
- int scopedEnumValue(QQmlEnginePrivate *engine, const QByteArray &, const QByteArray &, bool *ok) const;
- int scopedEnumValue(QQmlEnginePrivate *engine, QStringView, QStringView, bool *ok) const;
- int inlineComponentObjectId() const;
- void setInlineComponentObjectId(int id) const; // TODO: const setters are BAD
+ int scopedEnumValue(QQmlEnginePrivate *engine, const QHashedStringRef &, const QHashedStringRef &, bool *ok) const;
const QQmlTypePrivate *priv() const { return d.data(); }
static void refHandle(const QQmlTypePrivate *priv);
@@ -192,20 +167,20 @@ public:
AnyRegistrationType = 255
};
- QQmlType containingType() const;
- int lookupInlineComponentIdByName(const QString &name) const;
- QQmlType lookupInlineComponentById(int objectid) const;
- int generatePlaceHolderICId() const;
-
- void associateInlineComponent(const QString &name, int objectID, const CompositeMetaTypeIds &metaTypeIds, QQmlType existingType);
- void setPendingResolutionName(const QString &name);
- QString pendingResolutionName() const;
-
void createProxy(QObject *instance) const;
private:
friend class QQmlTypePrivate;
friend size_t qHash(const QQmlType &t, size_t seed);
+ friend bool operator==(const QQmlType &a, const QQmlType &b) noexcept
+ {
+ return a.d.data() == b.d.data();
+ }
+ friend bool operator!=(const QQmlType &a, const QQmlType &b) noexcept
+ {
+ return !(a == b);
+ }
+
QQmlRefPointer<const QQmlTypePrivate> d;
};
diff --git a/src/qml/qml/qqmltype_p_p.h b/src/qml/qml/qqmltype_p_p.h
index 2a375baa83..2bf83ddb8b 100644
--- a/src/qml/qml/qqmltype_p_p.h
+++ b/src/qml/qml/qqmltype_p_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 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$
-**
-****************************************************************************/
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLTYPE_P_P_H
#define QQMLTYPE_P_P_H
@@ -57,32 +21,52 @@
#include <private/qqmlrefcount_p.h>
#include <private/qqmlpropertycache_p.h>
#include <private/qqmlmetatype_p.h>
+#include <private/qqmltypeloader_p.h>
+#include <private/qv4executablecompilationunit_p.h>
+#include <private/qv4engine_p.h>
#include <QAtomicInteger>
QT_BEGIN_NAMESPACE
-class QQmlTypePrivate : public QQmlRefCount
+class QQmlTypePrivate final : public QQmlRefCounted<QQmlTypePrivate>
{
Q_DISABLE_COPY_MOVE(QQmlTypePrivate)
public:
+ struct ProxyMetaObjects
+ {
+ ~ProxyMetaObjects()
+ {
+ for (const QQmlProxyMetaObject::ProxyData &metaObject : data)
+ free(metaObject.metaObject);
+ }
+
+ QList<QQmlProxyMetaObject::ProxyData> data;
+ bool containsRevisionedAttributes = false;
+ };
+
+ struct Enums
+ {
+ ~Enums() { qDeleteAll(scopedEnums); }
+
+ QStringHash<int> enums;
+ QStringHash<int> scopedEnumIndex; // maps from enum name to index in scopedEnums
+ QList<QStringHash<int> *> scopedEnums;
+ };
+
QQmlTypePrivate(QQmlType::RegistrationType type);
- void init() const;
- void initEnums(QQmlEnginePrivate *engine) const;
- void insertEnums(const QMetaObject *metaObject) const;
- void insertEnumsFromPropertyCache(const QQmlPropertyCache *cache) const;
- void setContainingType(QQmlType *containingType);
+ const ProxyMetaObjects *init() const;
QUrl sourceUrl() const
{
switch (regType) {
case QQmlType::CompositeType:
- return extraData.fd->url;
+ return extraData.compositeTypeData;
case QQmlType::CompositeSingletonType:
- return extraData.sd->singletonInstanceInfo->url;
+ return extraData.singletonTypeData->singletonInstanceInfo->url;
case QQmlType::InlineComponentType:
- return extraData.id->url;
+ return extraData.inlineComponentTypeData;
default:
return QUrl();
}
@@ -92,7 +76,7 @@ public:
{
for (const QQmlTypePrivate *d = this; d; d = d->resolveCompositeBaseType(engine).d.data()) {
if (d->regType == QQmlType::CppType)
- return d->extraData.cd->attachedPropertiesType ? d : nullptr;
+ return d->extraData.cppTypeData->attachedPropertiesType ? d : nullptr;
if (d->regType != QQmlType::CompositeType)
return nullptr;
@@ -105,10 +89,13 @@ public:
return regType == QQmlType::CompositeType || regType == QQmlType::CompositeSingletonType;
}
- QQmlType resolveCompositeBaseType(QQmlEnginePrivate *engine) const;
- QQmlPropertyCache *compositePropertyCache(QQmlEnginePrivate *engine) const;
+ bool isValueType() const
+ {
+ return regType == QQmlType::CppType && !(typeId.flags() & QMetaType::PointerToQObject);
+ }
- QQmlType::RegistrationType regType;
+ QQmlType resolveCompositeBaseType(QQmlEnginePrivate *engine) const;
+ QQmlPropertyCache::ConstPtr compositePropertyCache(QQmlEnginePrivate *engine) const;
struct QQmlCppTypeData
{
@@ -125,71 +112,155 @@ public:
const QMetaObject *attachedPropertiesType;
int propertyValueSourceCast;
int propertyValueInterceptorCast;
+ int finalizerCast;
bool registerEnumClassesUnscoped;
+ bool registerEnumsFromRelatedTypes;
+ bool constructValueType;
+ bool populateValueType;
};
struct QQmlSingletonTypeData
{
- QQmlType::SingletonInstanceInfo *singletonInstanceInfo;
+ QQmlType::SingletonInstanceInfo::ConstPtr singletonInstanceInfo;
QObject *(*extFunc)(QObject *);
const QMetaObject *extMetaObject;
};
- struct QQmlCompositeTypeData
- {
- QUrl url;
- };
-
- struct QQmlInlineTypeData
- {
- QUrl url = QUrl();
- // The containing type stores a pointer to the inline component type
- // Using QQmlType here would create a reference cycle
- // As the inline component type cannot outlive the containing type
- // this should still be fine
- QQmlTypePrivate const * containingType = nullptr;
- QString inlineComponentName = QString();
- int objectId = -1;
- };
-
- using QQmlSequenceTypeData = QMetaSequence;
+ int index = -1;
union extraData {
- QQmlCppTypeData* cd;
- QQmlSingletonTypeData* sd;
- QQmlCompositeTypeData* fd;
- QQmlInlineTypeData* id;
- QQmlSequenceTypeData* ld;
+ extraData() {} // QQmlTypePrivate() does the actual construction.
+ ~extraData() {} // ~QQmlTypePrivate() does the actual destruction.
+
+ QQmlCppTypeData *cppTypeData;
+ QQmlSingletonTypeData *singletonTypeData;
+ QUrl compositeTypeData;
+ QUrl inlineComponentTypeData;
+ QMetaSequence sequentialContainerTypeData;
+ const char *interfaceTypeData;
} extraData;
+ static_assert(sizeof(extraData) == sizeof(void *));
- const char *iid;
QHashedString module;
QString name;
QString elementName;
QMetaType typeId;
QMetaType listId;
+ QQmlType::RegistrationType regType;
QTypeRevision version;
- QTypeRevision revision;
- mutable bool containsRevisionedAttributes;
- mutable QQmlType superType;
- const QMetaObject *baseMetaObject;
-
- int index;
- mutable QAtomicInteger<bool> isSetup;
- mutable QAtomicInteger<bool> isEnumFromCacheSetup;
- mutable QAtomicInteger<bool> isEnumFromBaseSetup;
- mutable bool haveSuperType;
- mutable QList<QQmlProxyMetaObject::ProxyData> metaObjects;
- mutable QStringHash<int> enums;
- mutable QStringHash<int> scopedEnumIndex; // maps from enum name to index in scopedEnums
- mutable QList<QStringHash<int>*> scopedEnums;
+ QTypeRevision revision = QTypeRevision::zero();
+ const QMetaObject *baseMetaObject = nullptr;
void setName(const QString &uri, const QString &element);
- mutable QHash<QString, int> namesToInlineComponentObjectIndex;
- mutable QHash<int, QQmlType> objectIdToICType;
+
+ template<typename String>
+ static int enumValue(
+ const QQmlRefPointer<const QQmlTypePrivate> &d, QQmlEnginePrivate *engine,
+ const String &name, bool *ok)
+ {
+ return doGetEnumValue(d, engine, [&](const QQmlTypePrivate::Enums *enums) {
+ return enums->enums.value(name);
+ }, ok);
+ }
+
+ template<typename String>
+ static int scopedEnumIndex(
+ const QQmlRefPointer<const QQmlTypePrivate> &d, QQmlEnginePrivate *engine,
+ const String &name, bool *ok)
+ {
+ return doGetEnumValue(d, engine, [&](const QQmlTypePrivate::Enums *enums) {
+ return enums->scopedEnumIndex.value(name);
+ }, ok);
+ }
+
+ template<typename String>
+ static int scopedEnumValue(
+ const QQmlRefPointer<const QQmlTypePrivate> &d, QQmlEnginePrivate *engine, int index,
+ const String &name, bool *ok)
+ {
+ return doGetEnumValue(d, engine, [&](const QQmlTypePrivate::Enums *enums) {
+ Q_ASSERT(index > -1 && index < enums->scopedEnums.size());
+ return enums->scopedEnums.at(index)->value(name);
+ }, ok);
+ }
+
+ template<typename String1, typename String2>
+ static int scopedEnumValue(
+ const QQmlRefPointer<const QQmlTypePrivate> &d, QQmlEnginePrivate *engine,
+ const String1 &scopedEnumName, const String2 &name, bool *ok)
+ {
+ return doGetEnumValue(d, engine, [&](const QQmlTypePrivate::Enums *enums) -> const int * {
+ const int *rv = enums->scopedEnumIndex.value(scopedEnumName);
+ if (!rv)
+ return nullptr;
+
+ const int index = *rv;
+ Q_ASSERT(index > -1 && index < enums->scopedEnums.size());
+ return enums->scopedEnums.at(index)->value(name);
+ }, ok);
+ }
+
+ const QMetaObject *metaObject() const
+ {
+ if (isValueType())
+ return metaObjectForValueType();
+
+ const QQmlTypePrivate::ProxyMetaObjects *proxies = init();
+ return proxies->data.isEmpty()
+ ? baseMetaObject
+ : proxies->data.constFirst().metaObject;
+ }
+
+ const QMetaObject *metaObjectForValueType() const
+ {
+ Q_ASSERT(isValueType());
+
+ // Prefer the extension meta object, if any.
+ // Extensions allow registration of non-gadget value types.
+ if (const QMetaObject *extensionMetaObject = extraData.cppTypeData->extMetaObject) {
+ // This may be a namespace even if the original metaType isn't.
+ // You can do such things with QML_FOREIGN declarations.
+ if (extensionMetaObject->metaType().flags() & QMetaType::IsGadget)
+ return extensionMetaObject;
+ }
+
+ if (baseMetaObject) {
+ // This may be a namespace even if the original metaType isn't.
+ // You can do such things with QML_FOREIGN declarations.
+ if (baseMetaObject->metaType().flags() & QMetaType::IsGadget)
+ return baseMetaObject;
+ }
+
+ return nullptr;
+ }
+
+ static QQmlType compositeQmlType(
+ const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &unit,
+ QQmlTypeLoader *typeLoader, const QString &type)
+ {
+ Q_ASSERT(typeLoader);
+
+ const QQmlType qmltype
+ = unit->typeNameCache->query<QQmlImport::AllowRecursion>(type, typeLoader).type;
+ if (!qmltype.isValid())
+ return qmltype;
+
+ if (qmltype.isInlineComponentType()
+ && !QQmlMetaType::obtainCompilationUnit(qmltype.typeId())) {
+ // If it seems to be an IC type, make sure there is an actual
+ // compilation unit for it. We create inline component types speculatively.
+ return QQmlType();
+ }
+
+ return qmltype;
+ }
private:
- ~QQmlTypePrivate() override;
+ mutable QAtomicPointer<const ProxyMetaObjects> proxyMetaObjects;
+ mutable QAtomicPointer<const Enums> enums;
+
+ ~QQmlTypePrivate();
+ friend class QQmlRefCounted<QQmlTypePrivate>;
struct EnumInfo {
QStringList path;
@@ -200,6 +271,29 @@ private:
bool scoped;
};
+ template<typename Op>
+ static int doGetEnumValue(
+ const QQmlRefPointer<const QQmlTypePrivate> &d, QQmlEnginePrivate *engine,
+ Op &&op, bool *ok)
+ {
+ Q_ASSERT(ok);
+ if (d) {
+ if (const QQmlTypePrivate::Enums *enums = d->initEnums(engine)) {
+ if (const int *rv = op(enums)) {
+ *ok = true;
+ return *rv;
+ }
+ }
+ }
+
+ *ok = false;
+ return -1;
+ }
+
+ const Enums *initEnums(QQmlEnginePrivate *engine) const;
+ void insertEnums(Enums *enums, const QMetaObject *metaObject) const;
+ void insertEnumsFromPropertyCache(Enums *enums, const QQmlPropertyCache::ConstPtr &cache) const;
+
void createListOfPossibleConflictingItems(const QMetaObject *metaObject, QList<EnumInfo> &enumInfoList, QStringList path) const;
void createEnumConflictReport(const QMetaObject *metaObject, const QString &conflictingKey) const;
};
diff --git a/src/qml/qml/qqmltypecompiler.cpp b/src/qml/qml/qqmltypecompiler.cpp
index 88c3a29fbf..cdabd6d5bc 100644
--- a/src/qml/qml/qqmltypecompiler.cpp
+++ b/src/qml/qml/qqmltypecompiler.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the tools applications 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qqmltypecompiler_p.h"
@@ -44,6 +8,8 @@
#include <private/qqmlvmemetaobject_p.h>
#include <private/qqmlcomponent_p.h>
#include <private/qqmlpropertyresolver_p.h>
+#include <private/qqmlcomponentandaliasresolver_p.h>
+#include <private/qqmlsignalnames_p.h>
#define COMPILE_EXCEPTION(token, desc) \
{ \
@@ -53,19 +19,24 @@
QT_BEGIN_NAMESPACE
-QQmlTypeCompiler::QQmlTypeCompiler(QQmlEnginePrivate *engine, QQmlTypeData *typeData,
- QmlIR::Document *parsedQML, const QQmlRefPointer<QQmlTypeNameCache> &typeNameCache,
- QV4::ResolvedTypeReferenceMap *resolvedTypeCache, const QV4::CompiledData::DependentTypesHasher &dependencyHasher)
+DEFINE_BOOL_CONFIG_OPTION(
+ disableInternalDeferredProperties, QML_DISABLE_INTERNAL_DEFERRED_PROPERTIES);
+
+Q_LOGGING_CATEGORY(lcQmlTypeCompiler, "qt.qml.typecompiler");
+
+QQmlTypeCompiler::QQmlTypeCompiler(
+ QQmlEnginePrivate *engine, QQmlTypeData *typeData, QmlIR::Document *parsedQML,
+ QV4::CompiledData::ResolvedTypeReferenceMap *resolvedTypeCache,
+ const QV4::CompiledData::DependentTypesHasher &dependencyHasher)
: resolvedTypes(resolvedTypeCache)
, engine(engine)
, dependencyHasher(dependencyHasher)
, document(parsedQML)
- , typeNameCache(typeNameCache)
, typeData(typeData)
{
}
-QQmlRefPointer<QV4::ExecutableCompilationUnit> QQmlTypeCompiler::compile()
+QQmlRefPointer<QV4::CompiledData::CompilationUnit> QQmlTypeCompiler::compile()
{
// Build property caches and VME meta object data
@@ -82,11 +53,30 @@ QQmlRefPointer<QV4::ExecutableCompilationUnit> QQmlTypeCompiler::compile()
{
QQmlPropertyCacheCreator<QQmlTypeCompiler> propertyCacheBuilder(&m_propertyCaches, &pendingGroupPropertyBindings,
engine, this, imports(), typeData->typeClassName());
- QQmlError error = propertyCacheBuilder.buildMetaObjects();
- if (error.isValid()) {
- recordError(error);
+ QQmlError cycleError = propertyCacheBuilder.verifyNoICCycle();
+ if (cycleError.isValid()) {
+ recordError(cycleError);
return nullptr;
}
+ QQmlPropertyCacheCreatorBase::IncrementalResult result;
+ do {
+ result = propertyCacheBuilder.buildMetaObjectsIncrementally();
+ const QQmlError &error = result.error;
+ if (error.isValid()) {
+ recordError(error);
+ return nullptr;
+ } else {
+ // Resolve component boundaries and aliases
+
+ QQmlComponentAndAliasResolver resolver(this, enginePrivate(), &m_propertyCaches);
+ if (QQmlError error = resolver.resolve(result.processedRoot); error.isValid()) {
+ recordError(error);
+ return nullptr;
+ }
+ pendingGroupPropertyBindings.resolveMissingPropertyCaches(&m_propertyCaches);
+ pendingGroupPropertyBindings.clear(); // anything that can be processed is now processed
+ }
+ } while (result.canResume);
}
{
@@ -94,18 +84,6 @@ QQmlRefPointer<QV4::ExecutableCompilationUnit> QQmlTypeCompiler::compile()
merger.mergeDefaultProperties();
}
-
- // Resolve component boundaries and aliases
-
- {
- // Scan for components, determine their scopes and resolve aliases within the scope.
- QQmlComponentAndAliasResolver resolver(this);
- if (!resolver.resolve())
- return nullptr;
-
- pendingGroupPropertyBindings.resolveMissingPropertyCaches(engine, &m_propertyCaches);
- }
-
{
SignalHandlerResolver converter(this);
if (!converter.resolveSignalHandlerExpressions())
@@ -134,7 +112,7 @@ QQmlRefPointer<QV4::ExecutableCompilationUnit> QQmlTypeCompiler::compile()
return nullptr;
}
- if (!document->javaScriptCompilationUnit.unitData()) {
+ if (!document->javaScriptCompilationUnit || !document->javaScriptCompilationUnit->unitData()) {
// Compile JS binding expressions and signal handlers if necessary
{
// We can compile script strings ahead of time, but they must be compiled
@@ -146,11 +124,13 @@ QQmlRefPointer<QV4::ExecutableCompilationUnit> QQmlTypeCompiler::compile()
document->jsModule.fileName = typeData->urlString();
document->jsModule.finalUrl = typeData->finalUrlString();
QmlIR::JSCodeGen v4CodeGenerator(document, engine->v4engine()->illegalNames());
- if (!v4CodeGenerator.generateCodeForComponents(componentRoots())) {
- recordError(v4CodeGenerator.error());
- return nullptr;
+ for (QmlIR::Object *object : std::as_const(document->objects)) {
+ if (!v4CodeGenerator.generateRuntimeFunctions(object)) {
+ Q_ASSERT(v4CodeGenerator.hasError());
+ recordError(v4CodeGenerator.error());
+ return nullptr;
+ }
}
-
document->javaScriptCompilationUnit = v4CodeGenerator.generateCompilationUnit(/*generated unit data*/false);
}
@@ -162,21 +142,14 @@ QQmlRefPointer<QV4::ExecutableCompilationUnit> QQmlTypeCompiler::compile()
if (!errors.isEmpty())
return nullptr;
- QQmlRefPointer<QV4::ExecutableCompilationUnit> compilationUnit
- = QV4::ExecutableCompilationUnit::create(std::move(
- document->javaScriptCompilationUnit));
- compilationUnit->typeNameCache = typeNameCache;
- compilationUnit->resolvedTypes = *resolvedTypes;
- compilationUnit->propertyCaches = std::move(m_propertyCaches);
- Q_ASSERT(compilationUnit->propertyCaches.count() == static_cast<int>(compilationUnit->objectCount()));
- return compilationUnit;
+ return std::move(document->javaScriptCompilationUnit);
}
void QQmlTypeCompiler::recordError(const QV4::CompiledData::Location &location, const QString &description)
{
QQmlError error;
- error.setLine(qmlConvertSourceCoordinate<quint32, int>(location.line));
- error.setColumn(qmlConvertSourceCoordinate<quint32, int>(location.column));
+ error.setLine(qmlConvertSourceCoordinate<quint32, int>(location.line()));
+ error.setColumn(qmlConvertSourceCoordinate<quint32, int>(location.column()));
error.setDescription(description);
error.setUrl(url());
errors << error;
@@ -216,12 +189,12 @@ int QQmlTypeCompiler::registerConstant(QV4::ReturnedValue v)
const QV4::CompiledData::Unit *QQmlTypeCompiler::qmlUnit() const
{
- return document->javaScriptCompilationUnit.unitData();
+ return document->javaScriptCompilationUnit->unitData();
}
const QQmlImports *QQmlTypeCompiler::imports() const
{
- return &typeData->imports();
+ return typeData->imports();
}
QVector<QmlIR::Object *> *QQmlTypeCompiler::qmlObjects() const
@@ -229,10 +202,9 @@ QVector<QmlIR::Object *> *QQmlTypeCompiler::qmlObjects() const
return &document->objects;
}
-void QQmlTypeCompiler::setPropertyCaches(QQmlPropertyCacheVector &&caches)
+QQmlPropertyCacheVector *QQmlTypeCompiler::propertyCaches()
{
- m_propertyCaches = std::move(caches);
- Q_ASSERT(m_propertyCaches.count() > 0);
+ return &m_propertyCaches;
}
const QQmlPropertyCacheVector *QQmlTypeCompiler::propertyCaches() const
@@ -240,11 +212,6 @@ const QQmlPropertyCacheVector *QQmlTypeCompiler::propertyCaches() const
return &m_propertyCaches;
}
-QQmlPropertyCacheVector &&QQmlTypeCompiler::takePropertyCaches()
-{
- return std::move(m_propertyCaches);
-}
-
QQmlJS::MemoryPool *QQmlTypeCompiler::memoryPool()
{
return document->jsParserEngine.pool();
@@ -270,7 +237,7 @@ void QQmlTypeCompiler::addImport(const QString &module, const QString &qualifier
const quint32 moduleIdx = registerString(module);
const quint32 qualifierIdx = registerString(qualifier);
- for (int i = 0, count = document->imports.count(); i < count; ++i) {
+ for (int i = 0, count = document->imports.size(); i < count; ++i) {
const QV4::CompiledData::Import *existingImport = document->imports.at(i);
if (existingImport->type == QV4::CompiledData::Import::ImportLibrary
&& existingImport->uriIndex == moduleIdx
@@ -286,9 +253,9 @@ void QQmlTypeCompiler::addImport(const QString &module, const QString &qualifier
document->imports.append(import);
}
-CompositeMetaTypeIds QQmlTypeCompiler::typeIdsForComponent(int objectId) const
+QQmlType QQmlTypeCompiler::qmlTypeForComponent(const QString &inlineComponentName) const
{
- return typeData->typeIds(objectId);
+ return typeData->qmlType(inlineComponentName);
}
QQmlCompilePass::QQmlCompilePass(QQmlTypeCompiler *typeCompiler)
@@ -309,9 +276,9 @@ SignalHandlerResolver::SignalHandlerResolver(QQmlTypeCompiler *typeCompiler)
bool SignalHandlerResolver::resolveSignalHandlerExpressions()
{
- for (int objectIndex = 0; objectIndex < qmlObjects.count(); ++objectIndex) {
+ for (int objectIndex = 0; objectIndex < qmlObjects.size(); ++objectIndex) {
const QmlIR::Object * const obj = qmlObjects.at(objectIndex);
- QQmlPropertyCache *cache = propertyCaches->at(objectIndex);
+ QQmlPropertyCache::ConstPtr cache = propertyCaches->at(objectIndex);
if (!cache)
continue;
if (QQmlCustomParser *customParser = customParsers.value(obj->inheritedTypeNameIndex)) {
@@ -325,9 +292,9 @@ bool SignalHandlerResolver::resolveSignalHandlerExpressions()
return true;
}
-bool SignalHandlerResolver::resolveSignalHandlerExpressions(const QmlIR::Object *obj,
- const QString &typeName,
- QQmlPropertyCache *propertyCache)
+bool SignalHandlerResolver::resolveSignalHandlerExpressions(
+ const QmlIR::Object *obj, const QString &typeName,
+ const QQmlPropertyCache::ConstPtr &propertyCache)
{
// map from signal name defined in qml itself to list of parameters
QHash<QString, QStringList> customSignals;
@@ -335,40 +302,48 @@ bool SignalHandlerResolver::resolveSignalHandlerExpressions(const QmlIR::Object
for (QmlIR::Binding *binding = obj->firstBinding(); binding; binding = binding->next) {
const QString bindingPropertyName = stringAt(binding->propertyNameIndex);
// Attached property?
- if (binding->type == QV4::CompiledData::Binding::Type_AttachedProperty) {
+ const QV4::CompiledData::Binding::Type bindingType = binding->type();
+ if (bindingType == QV4::CompiledData::Binding::Type_AttachedProperty) {
const QmlIR::Object *attachedObj = qmlObjects.at(binding->value.objectIndex);
auto *typeRef = resolvedType(binding->propertyNameIndex);
QQmlType type = typeRef ? typeRef->type() : QQmlType();
- if (!type.isValid())
- imports->resolveType(bindingPropertyName, &type, nullptr, nullptr, nullptr);
+ if (!type.isValid()) {
+ imports->resolveType(
+ QQmlTypeLoader::get(enginePrivate), bindingPropertyName, &type, nullptr,
+ nullptr);
+ }
const QMetaObject *attachedType = type.attachedPropertiesType(enginePrivate);
if (!attachedType)
COMPILE_EXCEPTION(binding, tr("Non-existent attached object"));
- QQmlPropertyCache *cache = compiler->enginePrivate()->cache(attachedType);
+ QQmlPropertyCache::ConstPtr cache = QQmlMetaType::propertyCache(attachedType);
if (!resolveSignalHandlerExpressions(attachedObj, bindingPropertyName, cache))
return false;
continue;
}
- if (!QmlIR::IRBuilder::isSignalPropertyName(bindingPropertyName))
+ QString qPropertyName;
+ QString signalName;
+ if (auto propertyName =
+ QQmlSignalNames::changedHandlerNameToPropertyName(bindingPropertyName)) {
+ qPropertyName = *propertyName;
+ signalName = *QQmlSignalNames::changedHandlerNameToSignalName(bindingPropertyName);
+ } else {
+ signalName = QQmlSignalNames::handlerNameToSignalName(bindingPropertyName)
+ .value_or(QString());
+ }
+ if (signalName.isEmpty())
continue;
QQmlPropertyResolver resolver(propertyCache);
- const QString signalName = QmlIR::IRBuilder::signalNameFromSignalPropertyName(
- bindingPropertyName);
-
- QString qPropertyName;
- if (signalName.endsWith(QLatin1String("Changed")))
- qPropertyName = signalName.mid(0, signalName.length() - static_cast<int>(strlen("Changed")));
-
bool notInRevision = false;
- QQmlPropertyData * const signal = resolver.signal(signalName, &notInRevision);
- QQmlPropertyData * const signalPropertyData = resolver.property(signalName, /*notInRevision ptr*/nullptr);
- QQmlPropertyData * const qPropertyData = !qPropertyName.isEmpty() ? resolver.property(qPropertyName) : nullptr;
+ const QQmlPropertyData * const signal = resolver.signal(signalName, &notInRevision);
+ const QQmlPropertyData * const signalPropertyData = resolver.property(signalName, /*notInRevision ptr*/nullptr);
+ const QQmlPropertyData * const qPropertyData = !qPropertyName.isEmpty() ? resolver.property(qPropertyName) : nullptr;
QString finalSignalHandlerPropertyName = signalName;
- uint flags = QV4::CompiledData::Binding::IsSignalHandlerExpression;
+ QV4::CompiledData::Binding::Flag flag
+ = QV4::CompiledData::Binding::IsSignalHandlerExpression;
const bool isPropertyObserver = !signalPropertyData && qPropertyData && qPropertyData->isBindable();
if (signal && !(qPropertyData && qPropertyData->isAlias() && isPropertyObserver)) {
@@ -378,7 +353,7 @@ bool SignalHandlerResolver::resolveSignalHandlerExpressions(const QmlIR::Object
bool unnamedParameter = false;
QList<QByteArray> parameterNames = propertyCache->signalParameterNames(sigIndex);
- for (int i = 0; i < parameterNames.count(); ++i) {
+ for (int i = 0; i < parameterNames.size(); ++i) {
const QString param = QString::fromUtf8(parameterNames.at(i));
if (param.isEmpty())
unnamedParameter = true;
@@ -390,7 +365,7 @@ bool SignalHandlerResolver::resolveSignalHandlerExpressions(const QmlIR::Object
}
} else if (isPropertyObserver) {
finalSignalHandlerPropertyName = qPropertyName;
- flags = QV4::CompiledData::Binding::IsPropertyObserver;
+ flag = QV4::CompiledData::Binding::IsPropertyObserver;
} else {
if (notInRevision) {
// Try assinging it as a property later
@@ -438,13 +413,13 @@ bool SignalHandlerResolver::resolveSignalHandlerExpressions(const QmlIR::Object
}
// Binding object to signal means connect the signal to the object's default method.
- if (binding->type == QV4::CompiledData::Binding::Type_Object) {
- binding->flags |= QV4::CompiledData::Binding::IsSignalHandlerObject;
+ if (bindingType == QV4::CompiledData::Binding::Type_Object) {
+ binding->setFlag(QV4::CompiledData::Binding::IsSignalHandlerObject);
continue;
}
- if (binding->type != QV4::CompiledData::Binding::Type_Script) {
- if (binding->type < QV4::CompiledData::Binding::Type_Script) {
+ if (bindingType != QV4::CompiledData::Binding::Type_Script) {
+ if (bindingType < QV4::CompiledData::Binding::Type_Script) {
COMPILE_EXCEPTION(binding, tr("Cannot assign a value to a signal (expecting a script to be run)"));
} else {
COMPILE_EXCEPTION(binding, tr("Incorrectly specified signal assignment"));
@@ -452,7 +427,7 @@ bool SignalHandlerResolver::resolveSignalHandlerExpressions(const QmlIR::Object
}
binding->propertyNameIndex = compiler->registerString(finalSignalHandlerPropertyName);
- binding->flags |= flags;
+ binding->setFlag(flag);
}
return true;
}
@@ -467,8 +442,8 @@ QQmlEnumTypeResolver::QQmlEnumTypeResolver(QQmlTypeCompiler *typeCompiler)
bool QQmlEnumTypeResolver::resolveEnumBindings()
{
- for (int i = 0; i < qmlObjects.count(); ++i) {
- QQmlPropertyCache *propertyCache = propertyCaches->at(i);
+ for (int i = 0; i < qmlObjects.size(); ++i) {
+ QQmlPropertyCache::ConstPtr propertyCache = propertyCaches->at(i);
if (!propertyCache)
continue;
const QmlIR::Object *obj = qmlObjects.at(i);
@@ -476,18 +451,19 @@ bool QQmlEnumTypeResolver::resolveEnumBindings()
QQmlPropertyResolver resolver(propertyCache);
for (QmlIR::Binding *binding = obj->firstBinding(); binding; binding = binding->next) {
- if (binding->flags & QV4::CompiledData::Binding::IsSignalHandlerExpression
- || binding->flags & QV4::CompiledData::Binding::IsSignalHandlerObject
- || binding->flags & QV4::CompiledData::Binding::IsPropertyObserver)
+ const QV4::CompiledData::Binding::Flags bindingFlags = binding->flags();
+ if (bindingFlags & QV4::CompiledData::Binding::IsSignalHandlerExpression
+ || bindingFlags & QV4::CompiledData::Binding::IsSignalHandlerObject
+ || bindingFlags & QV4::CompiledData::Binding::IsPropertyObserver)
continue;
- if (binding->type != QV4::CompiledData::Binding::Type_Script)
+ if (binding->type() != QV4::CompiledData::Binding::Type_Script)
continue;
const QString propertyName = stringAt(binding->propertyNameIndex);
bool notInRevision = false;
- QQmlPropertyData *pd = resolver.property(propertyName, &notInRevision);
- if (!pd)
+ const QQmlPropertyData *pd = resolver.property(propertyName, &notInRevision);
+ if (!pd || pd->isQList())
continue;
if (!pd->isEnum() && pd->propType().id() != QMetaType::Int)
@@ -503,37 +479,49 @@ bool QQmlEnumTypeResolver::resolveEnumBindings()
bool QQmlEnumTypeResolver::assignEnumToBinding(QmlIR::Binding *binding, QStringView, int enumValue, bool)
{
- binding->type = QV4::CompiledData::Binding::Type_Number;
+ binding->setType(QV4::CompiledData::Binding::Type_Number);
binding->value.constantValueIndex = compiler->registerConstant(QV4::Encode((double)enumValue));
// binding->setNumberValueInternal((double)enumValue);
- binding->flags |= QV4::CompiledData::Binding::IsResolvedEnum;
+ binding->setFlag(QV4::CompiledData::Binding::IsResolvedEnum);
return true;
}
-bool QQmlEnumTypeResolver::tryQualifiedEnumAssignment(const QmlIR::Object *obj, const QQmlPropertyCache *propertyCache, const QQmlPropertyData *prop, QmlIR::Binding *binding)
+bool QQmlEnumTypeResolver::tryQualifiedEnumAssignment(
+ const QmlIR::Object *obj, const QQmlPropertyCache::ConstPtr &propertyCache,
+ const QQmlPropertyData *prop, QmlIR::Binding *binding)
{
bool isIntProp = (prop->propType().id() == QMetaType::Int) && !prop->isEnum();
if (!prop->isEnum() && !isIntProp)
return true;
- if (!prop->isWritable() && !(binding->flags & QV4::CompiledData::Binding::InitializerForReadOnlyDeclaration))
- COMPILE_EXCEPTION(binding, tr("Invalid property assignment: \"%1\" is a read-only property").arg(stringAt(binding->propertyNameIndex)));
+ if (!prop->isWritable()
+ && !(binding->hasFlag(QV4::CompiledData::Binding::InitializerForReadOnlyDeclaration))) {
+ COMPILE_EXCEPTION(binding, tr("Invalid property assignment: \"%1\" is a read-only property")
+ .arg(stringAt(binding->propertyNameIndex)));
+ }
- Q_ASSERT(binding->type == QV4::CompiledData::Binding::Type_Script);
+ Q_ASSERT(binding->type() == QV4::CompiledData::Binding::Type_Script);
const QString string = compiler->bindingAsString(obj, binding->value.compiledScriptIndex);
if (!string.constData()->isUpper())
return true;
+ // reject any "complex" expression (even simple arithmetic)
+ // we do this by excluding everything that is not part of a
+ // valid identifier or a dot
+ for (const QChar &c : string)
+ if (!(c.isLetterOrNumber() || c == u'.' || c == u'_' || c.isSpace()))
+ return true;
+
// we support one or two '.' in the enum phrase:
// * <TypeName>.<EnumValue>
// * <TypeName>.<ScopedEnumName>.<EnumValue>
int dot = string.indexOf(QLatin1Char('.'));
- if (dot == -1 || dot == string.length()-1)
+ if (dot == -1 || dot == string.size()-1)
return true;
int dot2 = string.indexOf(QLatin1Char('.'), dot+1);
- if (dot2 != -1 && dot2 != string.length()-1) {
+ if (dot2 != -1 && dot2 != string.size()-1) {
if (!string.at(dot+1).isUpper())
return true;
if (string.indexOf(QLatin1Char('.'), dot2+1) != -1)
@@ -557,7 +545,8 @@ bool QQmlEnumTypeResolver::tryQualifiedEnumAssignment(const QmlIR::Object *obj,
return true;
}
QQmlType type;
- imports->resolveType(typeName, &type, nullptr, nullptr, nullptr);
+ imports->resolveType(
+ QQmlTypeLoader::get(compiler->enginePrivate()), typeName, &type, nullptr, nullptr);
if (!type.isValid() && !isQtObject)
return true;
@@ -619,12 +608,13 @@ int QQmlEnumTypeResolver::evaluateEnum(const QString &scope, QStringView enumNam
if (scope != QLatin1String("Qt")) {
QQmlType type;
- imports->resolveType(scope, &type, nullptr, nullptr, nullptr);
+ imports->resolveType(
+ QQmlTypeLoader::get(compiler->enginePrivate()), scope, &type, nullptr, nullptr);
if (!type.isValid())
return -1;
if (!enumName.isEmpty())
return type.scopedEnumValue(compiler->enginePrivate(), enumName, enumValue, ok);
- return type.enumValue(compiler->enginePrivate(), QHashedStringRef(enumValue.constData(), enumValue.length()), ok);
+ return type.enumValue(compiler->enginePrivate(), QHashedStringRef(enumValue.constData(), enumValue.size()), ok);
}
const QMetaObject *mo = &Qt::staticMetaObject;
@@ -649,7 +639,7 @@ void QQmlCustomParserScriptIndexer::annotateBindingsWithScriptStrings()
{
scanObjectRecursively(/*root object*/0);
for (int i = 0; i < qmlObjects.size(); ++i)
- if (qmlObjects.at(i)->isInlineComponent)
+ if (qmlObjects.at(i)->flags & QV4::CompiledData::Object::IsInlineComponentRoot)
scanObjectRecursively(i);
}
@@ -659,15 +649,21 @@ void QQmlCustomParserScriptIndexer::scanObjectRecursively(int objectIndex, bool
if (!annotateScriptBindings)
annotateScriptBindings = customParsers.contains(obj->inheritedTypeNameIndex);
for (QmlIR::Binding *binding = obj->firstBinding(); binding; binding = binding->next) {
- if (binding->type >= QV4::CompiledData::Binding::Type_Object) {
+ switch (binding->type()) {
+ case QV4::CompiledData::Binding::Type_Script:
+ if (annotateScriptBindings) {
+ binding->stringIndex = compiler->registerString(
+ compiler->bindingAsString(obj, binding->value.compiledScriptIndex));
+ }
+ break;
+ case QV4::CompiledData::Binding::Type_Object:
+ case QV4::CompiledData::Binding::Type_AttachedProperty:
+ case QV4::CompiledData::Binding::Type_GroupProperty:
scanObjectRecursively(binding->value.objectIndex, annotateScriptBindings);
- continue;
- } else if (binding->type != QV4::CompiledData::Binding::Type_Script)
- continue;
- if (!annotateScriptBindings)
- continue;
- const QString script = compiler->bindingAsString(obj, binding->value.compiledScriptIndex);
- binding->stringIndex = compiler->registerString(script);
+ break;
+ default:
+ break;
+ }
}
}
@@ -680,23 +676,23 @@ QQmlAliasAnnotator::QQmlAliasAnnotator(QQmlTypeCompiler *typeCompiler)
void QQmlAliasAnnotator::annotateBindingsToAliases()
{
- for (int i = 0; i < qmlObjects.count(); ++i) {
- QQmlPropertyCache *propertyCache = propertyCaches->at(i);
+ for (int i = 0; i < qmlObjects.size(); ++i) {
+ QQmlPropertyCache::ConstPtr propertyCache = propertyCaches->at(i);
if (!propertyCache)
continue;
const QmlIR::Object *obj = qmlObjects.at(i);
QQmlPropertyResolver resolver(propertyCache);
- QQmlPropertyData *defaultProperty = obj->indexOfDefaultPropertyOrAlias != -1 ? propertyCache->parent()->defaultProperty() : propertyCache->defaultProperty();
+ const QQmlPropertyData *defaultProperty = obj->indexOfDefaultPropertyOrAlias != -1 ? propertyCache->parent()->defaultProperty() : propertyCache->defaultProperty();
for (QmlIR::Binding *binding = obj->firstBinding(); binding; binding = binding->next) {
if (!binding->isValueBinding())
continue;
bool notInRevision = false;
- QQmlPropertyData *pd = binding->propertyNameIndex != quint32(0) ? resolver.property(stringAt(binding->propertyNameIndex), &notInRevision) : defaultProperty;
+ const QQmlPropertyData *pd = binding->propertyNameIndex != quint32(0) ? resolver.property(stringAt(binding->propertyNameIndex), &notInRevision) : defaultProperty;
if (pd && pd->isAlias())
- binding->flags |= QV4::CompiledData::Binding::IsBindingToAlias;
+ binding->setFlag(QV4::CompiledData::Binding::IsBindingToAlias);
}
}
}
@@ -712,21 +708,21 @@ QQmlScriptStringScanner::QQmlScriptStringScanner(QQmlTypeCompiler *typeCompiler)
void QQmlScriptStringScanner::scan()
{
const QMetaType scriptStringMetaType = QMetaType::fromType<QQmlScriptString>();
- for (int i = 0; i < qmlObjects.count(); ++i) {
- QQmlPropertyCache *propertyCache = propertyCaches->at(i);
+ for (int i = 0; i < qmlObjects.size(); ++i) {
+ QQmlPropertyCache::ConstPtr propertyCache = propertyCaches->at(i);
if (!propertyCache)
continue;
const QmlIR::Object *obj = qmlObjects.at(i);
QQmlPropertyResolver resolver(propertyCache);
- QQmlPropertyData *defaultProperty = obj->indexOfDefaultPropertyOrAlias != -1 ? propertyCache->parent()->defaultProperty() : propertyCache->defaultProperty();
+ const QQmlPropertyData *defaultProperty = obj->indexOfDefaultPropertyOrAlias != -1 ? propertyCache->parent()->defaultProperty() : propertyCache->defaultProperty();
for (QmlIR::Binding *binding = obj->firstBinding(); binding; binding = binding->next) {
- if (binding->type != QV4::CompiledData::Binding::Type_Script)
+ if (binding->type() != QV4::CompiledData::Binding::Type_Script)
continue;
bool notInRevision = false;
- QQmlPropertyData *pd = binding->propertyNameIndex != quint32(0) ? resolver.property(stringAt(binding->propertyNameIndex), &notInRevision) : defaultProperty;
+ const QQmlPropertyData *pd = binding->propertyNameIndex != quint32(0) ? resolver.property(stringAt(binding->propertyNameIndex), &notInRevision) : defaultProperty;
if (!pd || pd->propType() != scriptStringMetaType)
continue;
@@ -736,311 +732,99 @@ void QQmlScriptStringScanner::scan()
}
}
-QQmlComponentAndAliasResolver::QQmlComponentAndAliasResolver(QQmlTypeCompiler *typeCompiler)
- : QQmlCompilePass(typeCompiler)
- , enginePrivate(typeCompiler->enginePrivate())
- , pool(typeCompiler->memoryPool())
- , qmlObjects(typeCompiler->qmlObjects())
- , propertyCaches(std::move(typeCompiler->takePropertyCaches()))
+template<>
+void QQmlComponentAndAliasResolver<QQmlTypeCompiler>::allocateNamedObjects(
+ QmlIR::Object *object) const
{
+ object->namedObjectsInComponent.allocate(m_compiler->memoryPool(), m_idToObjectIndex);
}
-static bool isUsableComponent(const QMetaObject *metaObject)
+template<>
+bool QQmlComponentAndAliasResolver<QQmlTypeCompiler>::markAsComponent(int index) const
{
- // The metaObject is a component we're interested in if it either is a QQmlComponent itself
- // or if any of its parents is a QQmlAbstractDelegateComponent. We don't want to include
- // qqmldelegatecomponent_p.h because it belongs to QtQmlModels.
-
- if (metaObject == &QQmlComponent::staticMetaObject)
- return true;
-
- for (; metaObject; metaObject = metaObject->superClass()) {
- if (qstrcmp(metaObject->className(), "QQmlAbstractDelegateComponent") == 0)
- return true;
- }
-
- return false;
+ m_compiler->qmlObjects()->at(index)->flags |= QV4::CompiledData::Object::IsComponent;
+ return true;
}
-void QQmlComponentAndAliasResolver::findAndRegisterImplicitComponents(const QmlIR::Object *obj, QQmlPropertyCache *propertyCache)
+template<>
+void QQmlComponentAndAliasResolver<QQmlTypeCompiler>::setObjectId(int index) const
{
- QQmlPropertyResolver propertyResolver(propertyCache);
-
- QQmlPropertyData *defaultProperty = obj->indexOfDefaultPropertyOrAlias != -1 ? propertyCache->parent()->defaultProperty() : propertyCache->defaultProperty();
-
- for (QmlIR::Binding *binding = obj->firstBinding(); binding; binding = binding->next) {
- if (binding->type != QV4::CompiledData::Binding::Type_Object)
- continue;
- if (binding->flags & QV4::CompiledData::Binding::IsSignalHandlerObject)
- continue;
-
- const QmlIR::Object *targetObject = qmlObjects->at(binding->value.objectIndex);
- auto *tr = resolvedType(targetObject->inheritedTypeNameIndex);
- Q_ASSERT(tr);
-
- const QMetaObject *firstMetaObject = nullptr;
- const auto type = tr->type();
- if (type.isValid())
- firstMetaObject = type.metaObject();
- else if (const auto compilationUnit = tr->compilationUnit())
- firstMetaObject = compilationUnit->rootPropertyCache()->firstCppMetaObject();
- if (isUsableComponent(firstMetaObject))
- continue;
- // if here, not a QQmlComponent, so needs wrapping
-
- QQmlPropertyData *pd = nullptr;
- if (binding->propertyNameIndex != quint32(0)) {
- bool notInRevision = false;
- pd = propertyResolver.property(stringAt(binding->propertyNameIndex), &notInRevision);
- } else {
- pd = defaultProperty;
- }
- if (!pd || !pd->isQObject())
- continue;
-
- // If the version is given, use it and look up by QQmlType.
- // Otherwise, make sure we look up by metaobject.
- // TODO: Is this correct?
- QQmlPropertyCache *pc = pd->typeVersion().hasMinorVersion()
- ? enginePrivate->rawPropertyCacheForType(pd->propType().id(), pd->typeVersion())
- : enginePrivate->rawPropertyCacheForType(pd->propType().id());
- const QMetaObject *mo = pc ? pc->firstCppMetaObject() : nullptr;
- while (mo) {
- if (mo == &QQmlComponent::staticMetaObject)
- break;
- mo = mo->superClass();
- }
-
- if (!mo)
- continue;
-
- // emulate "import Qml 2.0 as QmlInternals" and then wrap the component in "QmlInternals.Component {}"
- QQmlType componentType = QQmlMetaType::qmlType(&QQmlComponent::staticMetaObject);
- Q_ASSERT(componentType.isValid());
- const QString qualifier = QStringLiteral("QmlInternals");
-
- compiler->addImport(componentType.module(), qualifier, componentType.version());
-
- QmlIR::Object *syntheticComponent = pool->New<QmlIR::Object>();
- syntheticComponent->init(
- pool,
- compiler->registerString(qualifier + QLatin1Char('.') + componentType.elementName()),
- compiler->registerString(QString()), binding->valueLocation);
- syntheticComponent->flags |= QV4::CompiledData::Object::IsComponent;
-
- if (!containsResolvedType(syntheticComponent->inheritedTypeNameIndex)) {
- auto typeRef = new QV4::ResolvedTypeReference;
- typeRef->setType(componentType);
- typeRef->setVersion(componentType.version());
- insertResolvedType(syntheticComponent->inheritedTypeNameIndex, typeRef);
- }
-
- qmlObjects->append(syntheticComponent);
- const int componentIndex = qmlObjects->count() - 1;
- // Keep property caches symmetric
- QQmlPropertyCache *componentCache = enginePrivate->cache(&QQmlComponent::staticMetaObject);
- propertyCaches.append(componentCache);
-
- QmlIR::Binding *syntheticBinding = pool->New<QmlIR::Binding>();
- *syntheticBinding = *binding;
- syntheticBinding->type = QV4::CompiledData::Binding::Type_Object;
- QString error = syntheticComponent->appendBinding(syntheticBinding, /*isListBinding*/false);
- Q_ASSERT(error.isEmpty());
- Q_UNUSED(error);
-
- binding->value.objectIndex = componentIndex;
-
- componentRoots.append(componentIndex);
- }
+ m_compiler->qmlObjects()->at(index)->id = m_idToObjectIndex.size();
}
-bool QQmlComponentAndAliasResolver::resolve()
+template<>
+bool QQmlComponentAndAliasResolver<QQmlTypeCompiler>::wrapImplicitComponent(QmlIR::Binding *binding)
{
- // Detect real Component {} objects as well as implicitly defined components, such as
- // someItemDelegate: Item {}
- // In the implicit case Item is surrounded by a synthetic Component {} because the property
- // on the left hand side is of QQmlComponent type.
- const int objCountWithoutSynthesizedComponents = qmlObjects->count();
- for (int i = 0; i < objCountWithoutSynthesizedComponents; ++i) {
- QmlIR::Object *obj = qmlObjects->at(i);
- if (obj->isInlineComponent) {
- componentRoots.append(i);
- continue;
- }
- QQmlPropertyCache *cache = propertyCaches.at(i);
- if (obj->inheritedTypeNameIndex == 0 && !cache)
- continue;
-
- bool isExplicitComponent = false;
-
- if (obj->inheritedTypeNameIndex) {
- auto *tref = resolvedType(obj->inheritedTypeNameIndex);
- Q_ASSERT(tref);
- if (tref->type().metaObject() == &QQmlComponent::staticMetaObject)
- isExplicitComponent = true;
- }
- if (!isExplicitComponent) {
- if (cache)
- findAndRegisterImplicitComponents(obj, cache);
- continue;
- }
-
- obj->flags |= QV4::CompiledData::Object::IsComponent;
-
- if (obj->functionCount() > 0)
- COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new functions."));
- if (obj->propertyCount() > 0 || obj->aliasCount() > 0)
- COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new properties."));
- if (obj->signalCount() > 0)
- COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new signals."));
-
- if (obj->bindingCount() == 0)
- COMPILE_EXCEPTION(obj, tr("Cannot create empty component specification"));
-
- const QmlIR::Binding *rootBinding = obj->firstBinding();
-
- for (const QmlIR::Binding *b = rootBinding; b; b = b->next) {
- if (b->propertyNameIndex != 0)
- COMPILE_EXCEPTION(rootBinding, tr("Component elements may not contain properties other than id"));
- }
-
- if (rootBinding->next || rootBinding->type != QV4::CompiledData::Binding::Type_Object)
- COMPILE_EXCEPTION(obj, tr("Invalid component body specification"));
-
- // For the root object, we are going to collect ids/aliases and resolve them for as a separate
- // last pass.
- if (i != 0)
- componentRoots.append(i);
-
- }
-
- for (int i = 0; i < componentRoots.count(); ++i) {
- QmlIR::Object *component = qmlObjects->at(componentRoots.at(i));
- const QmlIR::Binding *rootBinding = component->firstBinding();
-
- _idToObjectIndex.clear();
-
- _objectsWithAliases.clear();
-
- if (!collectIdsAndAliases(component->isInlineComponent ? componentRoots.at(i) : rootBinding->value.objectIndex))
- return false;
-
- component->namedObjectsInComponent.allocate(pool, _idToObjectIndex);
-
- if (!resolveAliases(componentRoots.at(i)))
- return false;
+ QQmlJS::MemoryPool *pool = m_compiler->memoryPool();
+ QVector<QmlIR::Object *> *qmlObjects = m_compiler->qmlObjects();
+
+ // emulate "import QML 1.0" and then wrap the component in "QML.Component {}"
+ QQmlType componentType = QQmlMetaType::qmlType(
+ &QQmlComponent::staticMetaObject, QStringLiteral("QML"),
+ QTypeRevision::fromVersion(1, 0));
+ Q_ASSERT(componentType.isValid());
+ const QString qualifier = QStringLiteral("QML");
+
+ m_compiler->addImport(componentType.module(), qualifier, componentType.version());
+
+ QmlIR::Object *syntheticComponent = pool->New<QmlIR::Object>();
+ syntheticComponent->init(
+ pool,
+ m_compiler->registerString(
+ qualifier + QLatin1Char('.') + componentType.elementName()),
+ m_compiler->registerString(QString()), binding->valueLocation);
+ syntheticComponent->flags |= QV4::CompiledData::Object::IsComponent;
+
+ if (!m_compiler->resolvedTypes->contains(syntheticComponent->inheritedTypeNameIndex)) {
+ auto typeRef = new QV4::ResolvedTypeReference;
+ typeRef->setType(componentType);
+ typeRef->setVersion(componentType.version());
+ m_compiler->resolvedTypes->insert(syntheticComponent->inheritedTypeNameIndex, typeRef);
}
- // Collect ids and aliases for root
- _idToObjectIndex.clear();
- _objectsWithAliases.clear();
+ qmlObjects->append(syntheticComponent);
+ const int componentIndex = qmlObjects->size() - 1;
+ // Keep property caches symmetric
+ QQmlPropertyCache::ConstPtr componentCache
+ = QQmlMetaType::propertyCache(&QQmlComponent::staticMetaObject);
+ m_propertyCaches->append(componentCache);
- collectIdsAndAliases(/*root object*/0);
+ QmlIR::Binding *syntheticBinding = pool->New<QmlIR::Binding>();
+ *syntheticBinding = *binding;
- QmlIR::Object *rootComponent = qmlObjects->at(/*root object*/0);
- rootComponent->namedObjectsInComponent.allocate(pool, _idToObjectIndex);
+ // The synthetic binding inside Component has no name. It's just "Component { Foo {} }".
+ syntheticBinding->propertyNameIndex = 0;
- if (!resolveAliases(/*root object*/0))
- return false;
+ syntheticBinding->setType(QV4::CompiledData::Binding::Type_Object);
+ QString error = syntheticComponent->appendBinding(syntheticBinding, /*isListBinding*/false);
+ Q_ASSERT(error.isEmpty());
+ Q_UNUSED(error);
- // Implicit component insertion may have added objects and thus we also need
- // to extend the symmetric propertyCaches.
- compiler->setPropertyCaches(std::move(propertyCaches));
- compiler->setComponentRoots(componentRoots);
+ binding->value.objectIndex = componentIndex;
+ m_componentRoots.append(componentIndex);
return true;
}
-bool QQmlComponentAndAliasResolver::collectIdsAndAliases(int objectIndex)
+template<>
+void QQmlComponentAndAliasResolver<QQmlTypeCompiler>::resolveGeneralizedGroupProperty(
+ const CompiledObject &component, CompiledBinding *binding)
{
- QmlIR::Object *obj = qmlObjects->at(objectIndex);
-
- if (obj->idNameIndex != 0) {
- if (_idToObjectIndex.contains(obj->idNameIndex)) {
- recordError(obj->locationOfIdProperty, tr("id is not unique"));
- return false;
- }
- obj->id = _idToObjectIndex.count();
- _idToObjectIndex.insert(obj->idNameIndex, objectIndex);
- }
-
- if (obj->aliasCount() > 0)
- _objectsWithAliases.append(objectIndex);
-
- // Stop at Component boundary
- if (obj->flags & QV4::CompiledData::Object::IsComponent && objectIndex != /*root object*/0)
- return true;
-
- for (const QmlIR::Binding *binding = obj->firstBinding(); binding; binding = binding->next) {
- if (binding->type != QV4::CompiledData::Binding::Type_Object
- && binding->type != QV4::CompiledData::Binding::Type_AttachedProperty
- && binding->type != QV4::CompiledData::Binding::Type_GroupProperty)
- continue;
-
- if (!collectIdsAndAliases(binding->value.objectIndex))
- return false;
- }
-
- return true;
+ Q_UNUSED(component);
+ // We cannot make it fail here. It might be a custom-parsed property
+ const int targetObjectIndex = m_idToObjectIndex.value(binding->propertyNameIndex, -1);
+ if (targetObjectIndex != -1)
+ m_propertyCaches->set(binding->value.objectIndex, m_propertyCaches->at(targetObjectIndex));
}
-bool QQmlComponentAndAliasResolver::resolveAliases(int componentIndex)
+template<>
+typename QQmlComponentAndAliasResolver<QQmlTypeCompiler>::AliasResolutionResult
+QQmlComponentAndAliasResolver<QQmlTypeCompiler>::resolveAliasesInObject(
+ const CompiledObject &component, int objectIndex, QQmlError *error)
{
- if (_objectsWithAliases.isEmpty())
- return true;
-
- QQmlPropertyCacheAliasCreator<QQmlTypeCompiler> aliasCacheCreator(&propertyCaches, compiler);
+ Q_UNUSED(component);
- bool atLeastOneAliasResolved;
- do {
- atLeastOneAliasResolved = false;
- QVector<int> pendingObjects;
-
- for (int objectIndex: qAsConst(_objectsWithAliases)) {
-
- QQmlError error;
- const auto result = resolveAliasesInObject(objectIndex, &error);
-
- if (error.isValid()) {
- recordError(error);
- return false;
- }
-
- if (result == AllAliasesResolved) {
- QQmlError error = aliasCacheCreator.appendAliasesToPropertyCache(*qmlObjects->at(componentIndex), objectIndex, enginePrivate);
- if (error.isValid()) {
- recordError(error);
- return false;
- }
- atLeastOneAliasResolved = true;
- } else if (result == SomeAliasesResolved) {
- atLeastOneAliasResolved = true;
- pendingObjects.append(objectIndex);
- } else {
- pendingObjects.append(objectIndex);
- }
- }
- qSwap(_objectsWithAliases, pendingObjects);
- } while (!_objectsWithAliases.isEmpty() && atLeastOneAliasResolved);
-
- if (!atLeastOneAliasResolved && !_objectsWithAliases.isEmpty()) {
- const QmlIR::Object *obj = qmlObjects->at(_objectsWithAliases.first());
- for (auto alias = obj->aliasesBegin(), end = obj->aliasesEnd(); alias != end; ++alias) {
- if (!(alias->flags & QV4::CompiledData::Alias::Resolved)) {
- recordError(alias->location, tr("Circular alias reference detected"));
- return false;
- }
- }
- }
-
- return true;
-}
-
-QQmlComponentAndAliasResolver::AliasResolutionResult
-QQmlComponentAndAliasResolver::resolveAliasesInObject(int objectIndex,
- QQmlError *error)
-{
- const QmlIR::Object * const obj = qmlObjects->at(objectIndex);
+ const QmlIR::Object * const obj = m_compiler->objectAt(objectIndex);
if (!obj->aliasCount())
return AllAliasesResolved;
@@ -1048,13 +832,13 @@ QQmlComponentAndAliasResolver::resolveAliasesInObject(int objectIndex,
bool seenUnresolvedAlias = false;
for (QmlIR::Alias *alias = obj->firstAlias(); alias; alias = alias->next) {
- if (alias->flags & QV4::CompiledData::Alias::Resolved)
+ if (alias->hasFlag(QV4::CompiledData::Alias::Resolved))
continue;
seenUnresolvedAlias = true;
- const int idIndex = alias->idIndex;
- const int targetObjectIndex = _idToObjectIndex.value(idIndex, -1);
+ const int idIndex = alias->idIndex();
+ const int targetObjectIndex = m_idToObjectIndex.value(idIndex, -1);
if (targetObjectIndex == -1) {
*error = qQmlCompileError(
alias->referenceLocation,
@@ -1062,10 +846,10 @@ QQmlComponentAndAliasResolver::resolveAliasesInObject(int objectIndex,
break;
}
- const QmlIR::Object *targetObject = qmlObjects->at(targetObjectIndex);
+ const QmlIR::Object *targetObject = m_compiler->objectAt(targetObjectIndex);
Q_ASSERT(targetObject->id >= 0);
- alias->targetObjectId = targetObject->id;
- alias->aliasToLocalAlias = false;
+ alias->setTargetObjectId(targetObject->id);
+ alias->setIsAliasToLocalAlias(false);
const QString aliasPropertyValue = stringAt(alias->propertyNameIndex);
@@ -1082,9 +866,9 @@ QQmlComponentAndAliasResolver::resolveAliasesInObject(int objectIndex,
QQmlPropertyIndex propIdx;
if (property.isEmpty()) {
- alias->flags |= QV4::CompiledData::Alias::AliasPointsToPointerObject;
+ alias->setFlag(QV4::CompiledData::Alias::AliasPointsToPointerObject);
} else {
- QQmlPropertyCache *targetCache = propertyCaches.at(targetObjectIndex);
+ QQmlPropertyCache::ConstPtr targetCache = m_propertyCaches->at(targetObjectIndex);
if (!targetCache) {
*error = qQmlCompileError(
alias->referenceLocation,
@@ -1094,14 +878,14 @@ QQmlComponentAndAliasResolver::resolveAliasesInObject(int objectIndex,
QQmlPropertyResolver resolver(targetCache);
- QQmlPropertyData *targetProperty = resolver.property(property.toString());
+ const QQmlPropertyData *targetProperty = resolver.property(property.toString());
// If it's an alias that we haven't resolved yet, try again later.
if (!targetProperty) {
bool aliasPointsToOtherAlias = false;
int localAliasIndex = 0;
for (auto targetAlias = targetObject->aliasesBegin(), end = targetObject->aliasesEnd(); targetAlias != end; ++targetAlias, ++localAliasIndex) {
- if (stringAt(targetAlias->nameIndex) == property) {
+ if (stringAt(targetAlias->nameIndex()) == property) {
aliasPointsToOtherAlias = true;
break;
}
@@ -1109,14 +893,14 @@ QQmlComponentAndAliasResolver::resolveAliasesInObject(int objectIndex,
if (aliasPointsToOtherAlias) {
if (targetObjectIndex == objectIndex) {
alias->localAliasIndex = localAliasIndex;
- alias->aliasToLocalAlias = true;
- alias->flags |= QV4::CompiledData::Alias::Resolved;
+ alias->setIsAliasToLocalAlias(true);
+ alias->setFlag(QV4::CompiledData::Alias::Resolved);
++numResolvedAliases;
continue;
}
// restore
- alias->idIndex = idIndex;
+ alias->setIdIndex(idIndex);
// Try again later and resolve the target alias first.
break;
}
@@ -1132,7 +916,7 @@ QQmlComponentAndAliasResolver::resolveAliasesInObject(int objectIndex,
propIdx = QQmlPropertyIndex(targetProperty->coreIndex());
if (!subProperty.isEmpty()) {
- const QMetaObject *valueTypeMetaObject = QQmlMetaType::metaObjectForMetaType(targetProperty->propType());
+ const QMetaObject *valueTypeMetaObject = QQmlMetaType::metaObjectForValueType(targetProperty->propType());
if (!valueTypeMetaObject) {
// could be a deep alias
bool isDeepAlias = subProperty.at(0).isLower();
@@ -1140,9 +924,9 @@ QQmlComponentAndAliasResolver::resolveAliasesInObject(int objectIndex,
isDeepAlias = false;
for (auto it = targetObject->bindingsBegin(); it != targetObject->bindingsEnd(); ++it) {
auto binding = *it;
- if (compiler->stringAt(binding.propertyNameIndex) == property) {
- resolver = QQmlPropertyResolver(propertyCaches.at(binding.value.objectIndex));
- QQmlPropertyData *actualProperty = resolver.property(subProperty.toString());
+ if (m_compiler->stringAt(binding.propertyNameIndex) == property) {
+ resolver = QQmlPropertyResolver(m_propertyCaches->at(binding.value.objectIndex));
+ const QQmlPropertyData *actualProperty = resolver.property(subProperty.toString());
if (actualProperty) {
propIdx = QQmlPropertyIndex(propIdx.coreIndex(), actualProperty->coreIndex());
isDeepAlias = true;
@@ -1172,12 +956,12 @@ QQmlComponentAndAliasResolver::resolveAliasesInObject(int objectIndex,
}
} else {
if (targetProperty->isQObject())
- alias->flags |= QV4::CompiledData::Alias::AliasPointsToPointerObject;
+ alias->setFlag(QV4::CompiledData::Alias::AliasPointsToPointerObject);
}
}
alias->encodedMetaPropertyIndex = propIdx.toEncoded();
- alias->flags |= QV4::CompiledData::Alias::Resolved;
+ alias->setFlag(QV4::CompiledData::Alias::Resolved);
numResolvedAliases++;
}
@@ -1198,33 +982,40 @@ QQmlDeferredAndCustomParserBindingScanner::QQmlDeferredAndCustomParserBindingSca
bool QQmlDeferredAndCustomParserBindingScanner::scanObject()
{
- for (int i = 0; i < qmlObjects->size(); ++i)
- if (qmlObjects->at(i)->isInlineComponent)
- scanObject(i);
- return scanObject(/*root object*/0);
+ for (int i = 0; i < qmlObjects->size(); ++i) {
+ if ((qmlObjects->at(i)->flags & QV4::CompiledData::Object::IsInlineComponentRoot)
+ && !scanObject(i, ScopeDeferred::False)) {
+ return false;
+ }
+ }
+ return scanObject(/*root object*/0, ScopeDeferred::False);
}
-bool QQmlDeferredAndCustomParserBindingScanner::scanObject(int objectIndex)
+bool QQmlDeferredAndCustomParserBindingScanner::scanObject(
+ int objectIndex, ScopeDeferred scopeDeferred)
{
+ using namespace QV4::CompiledData;
+
QmlIR::Object *obj = qmlObjects->at(objectIndex);
if (obj->idNameIndex != 0)
_seenObjectWithId = true;
- if (obj->flags & QV4::CompiledData::Object::IsComponent && !obj->isInlineComponent) {
+ if (obj->flags & Object::IsComponent) {
Q_ASSERT(obj->bindingCount() == 1);
- const QV4::CompiledData::Binding *componentBinding = obj->firstBinding();
- Q_ASSERT(componentBinding->type == QV4::CompiledData::Binding::Type_Object);
- return scanObject(componentBinding->value.objectIndex);
+ const Binding *componentBinding = obj->firstBinding();
+ Q_ASSERT(componentBinding->type() == Binding::Type_Object);
+ // Components are separate from their surrounding scope. They cannot be deferred.
+ return scanObject(componentBinding->value.objectIndex, ScopeDeferred::False);
}
- QQmlPropertyCache *propertyCache = propertyCaches->at(objectIndex);
+ QQmlPropertyCache::ConstPtr propertyCache = propertyCaches->at(objectIndex);
if (!propertyCache)
return true;
QString defaultPropertyName;
- QQmlPropertyData *defaultProperty = nullptr;
+ const QQmlPropertyData *defaultProperty = nullptr;
if (obj->indexOfDefaultPropertyOrAlias != -1) {
- QQmlPropertyCache *cache = propertyCache->parent();
+ const QQmlPropertyCache *cache = propertyCache->parent().data();
defaultPropertyName = cache->defaultPropertyName();
defaultProperty = cache->defaultProperty();
} else {
@@ -1237,75 +1028,126 @@ bool QQmlDeferredAndCustomParserBindingScanner::scanObject(int objectIndex)
QQmlPropertyResolver propertyResolver(propertyCache);
QStringList deferredPropertyNames;
+ QStringList immediatePropertyNames;
{
const QMetaObject *mo = propertyCache->firstCppMetaObject();
- const int namesIndex = mo->indexOfClassInfo("DeferredPropertyNames");
- if (namesIndex != -1) {
- QMetaClassInfo classInfo = mo->classInfo(namesIndex);
- deferredPropertyNames = QString::fromUtf8(classInfo.value()).split(QLatin1Char(','));
+ const int deferredNamesIndex = mo->indexOfClassInfo("DeferredPropertyNames");
+ const int immediateNamesIndex = mo->indexOfClassInfo("ImmediatePropertyNames");
+ if (deferredNamesIndex != -1) {
+ if (immediateNamesIndex != -1) {
+ COMPILE_EXCEPTION(obj, tr("You cannot define both DeferredPropertyNames and "
+ "ImmediatePropertyNames on the same type."));
+ }
+ const QMetaClassInfo classInfo = mo->classInfo(deferredNamesIndex);
+ deferredPropertyNames = QString::fromUtf8(classInfo.value()).split(u',');
+ } else if (immediateNamesIndex != -1) {
+ const QMetaClassInfo classInfo = mo->classInfo(immediateNamesIndex);
+ immediatePropertyNames = QString::fromUtf8(classInfo.value()).split(u',');
+
+ // If the property contains an empty string, all properties shall be deferred.
+ if (immediatePropertyNames.isEmpty())
+ immediatePropertyNames.append(QString());
}
}
for (QmlIR::Binding *binding = obj->firstBinding(); binding; binding = binding->next) {
- QQmlPropertyData *pd = nullptr;
QString name = stringAt(binding->propertyNameIndex);
if (customParser) {
- if (binding->type == QV4::CompiledData::Binding::Type_AttachedProperty) {
+ if (binding->type() == Binding::Type_AttachedProperty) {
if (customParser->flags() & QQmlCustomParser::AcceptsAttachedProperties) {
- binding->flags |= QV4::CompiledData::Binding::IsCustomParserBinding;
- obj->flags |= QV4::CompiledData::Object::HasCustomParserBindings;
+ binding->setFlag(Binding::IsCustomParserBinding);
+ obj->flags |= Object::HasCustomParserBindings;
continue;
}
- } else if (QmlIR::IRBuilder::isSignalPropertyName(name)
+ } else if (QQmlSignalNames::isHandlerName(name)
&& !(customParser->flags() & QQmlCustomParser::AcceptsSignalHandlers)) {
- obj->flags |= QV4::CompiledData::Object::HasCustomParserBindings;
- binding->flags |= QV4::CompiledData::Binding::IsCustomParserBinding;
+ obj->flags |= Object::HasCustomParserBindings;
+ binding->setFlag(Binding::IsCustomParserBinding);
continue;
}
}
- if (name.isEmpty()) {
- pd = defaultProperty;
- name = defaultPropertyName;
- } else {
- if (name.constData()->isUpper())
- continue;
-
- bool notInRevision = false;
- pd = propertyResolver.property(name, &notInRevision,
- QQmlPropertyResolver::CheckRevision);
- }
+ const bool hasPropertyData = [&]() {
+ if (name.isEmpty()) {
+ name = defaultPropertyName;
+ if (defaultProperty)
+ return true;
+ } else if (name.constData()->isUpper()) {
+ // Upper case names cannot be custom-parsed unless they are attached properties
+ // and the custom parser explicitly accepts them. See above for that case.
+ return false;
+ } else {
+ bool notInRevision = false;
+ if (propertyResolver.property(
+ name, &notInRevision, QQmlPropertyResolver::CheckRevision)) {
+ return true;
+ }
+ }
- bool seenSubObjectWithId = false;
+ if (!customParser)
+ return false;
- if (binding->type >= QV4::CompiledData::Binding::Type_Object && (pd || binding->isAttachedProperty())) {
- qSwap(_seenObjectWithId, seenSubObjectWithId);
- const bool subObjectValid = scanObject(binding->value.objectIndex);
- qSwap(_seenObjectWithId, seenSubObjectWithId);
- if (!subObjectValid)
+ const Binding::Flags bindingFlags = binding->flags();
+ if (bindingFlags & Binding::IsSignalHandlerExpression
+ || bindingFlags & Binding::IsSignalHandlerObject
+ || bindingFlags & Binding::IsPropertyObserver) {
+ // These signal handlers cannot be custom-parsed. We have already established
+ // that the signal exists.
return false;
- _seenObjectWithId |= seenSubObjectWithId;
- }
+ }
- if (!seenSubObjectWithId && binding->type != QV4::CompiledData::Binding::Type_GroupProperty
- && !deferredPropertyNames.isEmpty() && deferredPropertyNames.contains(name)) {
+ // If the property isn't found, we may want to custom-parse the binding.
+ obj->flags |= Object::HasCustomParserBindings;
+ binding->setFlag(Binding::IsCustomParserBinding);
+ return false;
+ }();
- binding->flags |= QV4::CompiledData::Binding::IsDeferredBinding;
- obj->flags |= QV4::CompiledData::Object::HasDeferredBindings;
+ bool seenSubObjectWithId = false;
+ bool isExternal = false;
+ if (binding->type() >= Binding::Type_Object) {
+ const bool isOwnProperty = hasPropertyData || binding->isAttachedProperty();
+ isExternal = !isOwnProperty && binding->isGroupProperty();
+ if (isOwnProperty || isExternal) {
+ qSwap(_seenObjectWithId, seenSubObjectWithId);
+ const bool subObjectValid = scanObject(
+ binding->value.objectIndex,
+ (isExternal || scopeDeferred == ScopeDeferred::True)
+ ? ScopeDeferred::True
+ : ScopeDeferred::False);
+ qSwap(_seenObjectWithId, seenSubObjectWithId);
+ if (!subObjectValid)
+ return false;
+ _seenObjectWithId |= seenSubObjectWithId;
+ }
}
- if (binding->flags & QV4::CompiledData::Binding::IsSignalHandlerExpression
- || binding->flags & QV4::CompiledData::Binding::IsSignalHandlerObject
- || binding->flags & QV4::CompiledData::Binding::IsPropertyObserver)
- continue;
+ bool isDeferred = false;
+ if (!immediatePropertyNames.isEmpty() && !immediatePropertyNames.contains(name)) {
+ if (seenSubObjectWithId) {
+ COMPILE_EXCEPTION(binding, tr("You cannot assign an id to an object assigned "
+ "to a deferred property."));
+ }
+ if (isExternal || !disableInternalDeferredProperties())
+ isDeferred = true;
+ } else if (!deferredPropertyNames.isEmpty() && deferredPropertyNames.contains(name)) {
+ if (!seenSubObjectWithId && binding->type() != Binding::Type_GroupProperty) {
+ if (isExternal || !disableInternalDeferredProperties())
+ isDeferred = true;
+ }
+ }
- if (!pd) {
- if (customParser) {
- obj->flags |= QV4::CompiledData::Object::HasCustomParserBindings;
- binding->flags |= QV4::CompiledData::Binding::IsCustomParserBinding;
+ if (binding->type() >= Binding::Type_Object) {
+ if (isExternal && !isDeferred && !customParser) {
+ COMPILE_EXCEPTION(
+ binding, tr("Cannot assign to non-existent property \"%1\"").arg(name));
}
}
+
+ if (isDeferred) {
+ binding->setFlag(Binding::IsDeferredBinding);
+ obj->flags |= Object::HasDeferredBindings;
+ }
}
return true;
@@ -1321,13 +1163,13 @@ QQmlDefaultPropertyMerger::QQmlDefaultPropertyMerger(QQmlTypeCompiler *typeCompi
void QQmlDefaultPropertyMerger::mergeDefaultProperties()
{
- for (int i = 0; i < qmlObjects.count(); ++i)
+ for (int i = 0; i < qmlObjects.size(); ++i)
mergeDefaultProperties(i);
}
void QQmlDefaultPropertyMerger::mergeDefaultProperties(int objectIndex)
{
- QQmlPropertyCache *propertyCache = propertyCaches->at(objectIndex);
+ QQmlPropertyCache::ConstPtr propertyCache = propertyCaches->at(objectIndex);
if (!propertyCache)
return;
diff --git a/src/qml/qml/qqmltypecompiler_p.h b/src/qml/qml/qqmltypecompiler_p.h
index 4d65e76e91..6d9e5a77ca 100644
--- a/src/qml/qml/qqmltypecompiler_p.h
+++ b/src/qml/qml/qqmltypecompiler_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the tools applications 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLTYPECOMPILER_P_H
#define QQMLTYPECOMPILER_P_H
@@ -82,21 +46,35 @@ public:
QQmlTypeCompiler(QQmlEnginePrivate *engine,
QQmlTypeData *typeData,
QmlIR::Document *document,
- const QQmlRefPointer<QQmlTypeNameCache> &typeNameCache,
- QV4::ResolvedTypeReferenceMap *resolvedTypeCache,
+ QV4::CompiledData::ResolvedTypeReferenceMap *resolvedTypeCache,
const QV4::CompiledData::DependentTypesHasher &dependencyHasher);
// --- interface used by QQmlPropertyCacheCreator
typedef QmlIR::Object CompiledObject;
+ typedef QmlIR::Binding CompiledBinding;
+ using ListPropertyAssignBehavior = QmlIR::Pragma::ListPropertyAssignBehaviorValue;
+
+ // Deliberate choice of map over hash here to ensure stable generated output.
+ using IdToObjectMap = QMap<int, int>;
+
const QmlIR::Object *objectAt(int index) const { return document->objects.at(index); }
- int objectCount() const { return document->objects.count(); }
+ QmlIR::Object *objectAt(int index) { return document->objects.at(index); }
+ int objectCount() const { return document->objects.size(); }
QString stringAt(int idx) const;
QmlIR::PoolList<QmlIR::Function>::Iterator objectFunctionsBegin(const QmlIR::Object *object) const { return object->functionsBegin(); }
QmlIR::PoolList<QmlIR::Function>::Iterator objectFunctionsEnd(const QmlIR::Object *object) const { return object->functionsEnd(); }
- QV4::ResolvedTypeReferenceMap *resolvedTypes = nullptr;
+ QV4::CompiledData::ResolvedTypeReferenceMap *resolvedTypes = nullptr;
+ ListPropertyAssignBehavior listPropertyAssignBehavior() const
+ {
+ for (const QmlIR::Pragma *pragma: document->pragmas) {
+ if (pragma->type == QmlIR::Pragma::ListPropertyAssignBehavior)
+ return pragma->listPropertyAssignBehavior;
+ }
+ return ListPropertyAssignBehavior::Append;
+ }
// ---
- QQmlRefPointer<QV4::ExecutableCompilationUnit> compile();
+ QQmlRefPointer<QV4::CompiledData::CompilationUnit> compile();
QList<QQmlError> compilationErrors() const { return errors; }
void recordError(const QV4::CompiledData::Location &location, const QString &description);
@@ -112,11 +90,8 @@ public:
QQmlEnginePrivate *enginePrivate() const { return engine; }
const QQmlImports *imports() const;
QVector<QmlIR::Object *> *qmlObjects() const;
- void setPropertyCaches(QQmlPropertyCacheVector &&caches);
+ QQmlPropertyCacheVector *propertyCaches();
const QQmlPropertyCacheVector *propertyCaches() const;
- QQmlPropertyCacheVector &&takePropertyCaches();
- void setComponentRoots(const QVector<quint32> &roots) { m_componentRoots = roots; }
- const QVector<quint32> &componentRoots() const { return m_componentRoots; }
QQmlJS::MemoryPool *memoryPool();
QStringView newStringRef(const QString &string);
const QV4::Compiler::StringTableGenerator *stringPool() const;
@@ -132,7 +107,16 @@ public:
return resolvedTypes->value(id);
}
- CompositeMetaTypeIds typeIdsForComponent(int objectId = 0) const;
+ QV4::ResolvedTypeReference *resolvedType(QMetaType type) const
+ {
+ for (QV4::ResolvedTypeReference *ref : std::as_const(*resolvedTypes)) {
+ if (ref->type().typeId() == type)
+ return ref;
+ }
+ return nullptr;
+ }
+
+ QQmlType qmlTypeForComponent(const QString &inlineComponentName = QString()) const;
private:
QList<QQmlError> errors;
@@ -143,10 +127,8 @@ private:
QHash<int, QQmlCustomParser*> customParsers;
// index in first hash is component index, vector inside contains object indices of objects with id property
- QVector<quint32> m_componentRoots;
QQmlPropertyCacheVector m_propertyCaches;
- QQmlRefPointer<QQmlTypeNameCache> typeNameCache;
QQmlTypeData *typeData;
};
@@ -158,16 +140,9 @@ struct QQmlCompilePass
protected:
void recordError(const QV4::CompiledData::Location &location, const QString &description) const
{ compiler->recordError(location, description); }
- void recordError(const QQmlError &error)
- { compiler->recordError(error); }
QV4::ResolvedTypeReference *resolvedType(int id) const
{ return compiler->resolvedType(id); }
- bool containsResolvedType(int id) const
- { return compiler->resolvedTypes->contains(id); }
- QV4::ResolvedTypeReferenceMap::iterator insertResolvedType(
- int id, QV4::ResolvedTypeReference *value)
- { return compiler->resolvedTypes->insert(id, value); }
QQmlTypeCompiler *compiler;
};
@@ -185,7 +160,7 @@ public:
private:
bool resolveSignalHandlerExpressions(const QmlIR::Object *obj, const QString &typeName,
- QQmlPropertyCache *propertyCache);
+ const QQmlPropertyCache::ConstPtr &propertyCache);
QQmlEnginePrivate *enginePrivate;
const QVector<QmlIR::Object*> &qmlObjects;
@@ -212,9 +187,9 @@ private:
{
return assignEnumToBinding(binding, QStringView(enumName), enumValue, isQtObject);
}
- bool tryQualifiedEnumAssignment(const QmlIR::Object *obj, const QQmlPropertyCache *propertyCache,
- const QQmlPropertyData *prop,
- QmlIR::Binding *binding);
+ bool tryQualifiedEnumAssignment(
+ const QmlIR::Object *obj, const QQmlPropertyCache::ConstPtr &propertyCache,
+ const QQmlPropertyData *prop, QmlIR::Binding *binding);
int evaluateEnum(const QString &scope, QStringView enumName, QStringView enumValue, bool *ok) const;
@@ -261,52 +236,17 @@ private:
const QQmlPropertyCacheVector * const propertyCaches;
};
-class QQmlComponentAndAliasResolver : public QQmlCompilePass
-{
- Q_DECLARE_TR_FUNCTIONS(QQmlAnonymousComponentResolver)
-public:
- QQmlComponentAndAliasResolver(QQmlTypeCompiler *typeCompiler);
-
- bool resolve();
-
-protected:
- void findAndRegisterImplicitComponents(const QmlIR::Object *obj, QQmlPropertyCache *propertyCache);
- bool collectIdsAndAliases(int objectIndex);
- bool resolveAliases(int componentIndex);
- void propertyDataForAlias(QmlIR::Alias *alias, int *type, quint32 *propertyFlags);
-
- enum AliasResolutionResult {
- NoAliasResolved,
- SomeAliasesResolved,
- AllAliasesResolved
- };
-
- AliasResolutionResult resolveAliasesInObject(int objectIndex, QQmlError *error);
-
- QQmlEnginePrivate *enginePrivate;
- QQmlJS::MemoryPool *pool;
-
- QVector<QmlIR::Object*> *qmlObjects;
-
- // indices of the objects that are actually Component {}
- QVector<quint32> componentRoots;
-
- // Deliberate choice of map over hash here to ensure stable generated output.
- QMap<int, int> _idToObjectIndex;
- QVector<int> _objectsWithAliases;
-
- QQmlPropertyCacheVector propertyCaches;
-};
-
class QQmlDeferredAndCustomParserBindingScanner : public QQmlCompilePass
{
+ Q_DECLARE_TR_FUNCTIONS(QQmlDeferredAndCustomParserBindingScanner)
public:
QQmlDeferredAndCustomParserBindingScanner(QQmlTypeCompiler *typeCompiler);
bool scanObject();
private:
- bool scanObject(int objectIndex);
+ enum class ScopeDeferred { False, True };
+ bool scanObject(int objectIndex, ScopeDeferred scopeDeferred);
QVector<QmlIR::Object*> *qmlObjects;
const QQmlPropertyCacheVector * const propertyCaches;
diff --git a/src/qml/qml/qqmltypedata.cpp b/src/qml/qml/qqmltypedata.cpp
index ab2d83e57a..9acd801672 100644
--- a/src/qml/qml/qqmltypedata.cpp
+++ b/src/qml/qml/qqmltypedata.cpp
@@ -1,56 +1,25 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-#include <private/qqmltypedata_p.h>
+#include <private/qqmlcomponentandaliasresolver_p.h>
#include <private/qqmlengine_p.h>
-#include <private/qqmlpropertycachecreator_p.h>
-#include <private/qqmlpropertyvalidator_p.h>
#include <private/qqmlirbuilder_p.h>
#include <private/qqmlirloader_p.h>
+#include <private/qqmlpropertycachecreator_p.h>
+#include <private/qqmlpropertyvalidator_p.h>
#include <private/qqmlscriptblob_p.h>
#include <private/qqmlscriptdata_p.h>
#include <private/qqmltypecompiler_p.h>
+#include <private/qqmltypedata_p.h>
+#include <private/qqmltypeloaderqmldircontent_p.h>
#include <QtCore/qloggingcategory.h>
#include <QtCore/qcryptographichash.h>
+#include <memory>
+
Q_DECLARE_LOGGING_CATEGORY(DBG_DISK_CACHE)
+Q_LOGGING_CATEGORY(lcCycle, "qt.qml.typeresolution.cycle", QtWarningMsg)
QT_BEGIN_NAMESPACE
@@ -82,35 +51,11 @@ QQmlTypeData::~QQmlTypeData()
m_resolvedTypes.clear();
}
-const QList<QQmlTypeData::ScriptReference> &QQmlTypeData::resolvedScripts() const
-{
- return m_scripts;
-}
-
-QV4::ExecutableCompilationUnit *QQmlTypeData::compilationUnit() const
+QV4::CompiledData::CompilationUnit *QQmlTypeData::compilationUnit() const
{
return m_compiledData.data();
}
-QV4::ExecutableCompilationUnit *QQmlTypeData::compilationUnitForInlineComponent(unsigned int icObjectId) const
-{
- Q_ASSERT(m_document || m_compiledData);
- if (m_compiledData)
- return m_compiledData.data();
- for (auto it = m_document->objects.begin(); it != m_document->objects.end(); ++it) {
- auto object = *it;
- auto icIt = std::find_if(object->inlineComponentsBegin(), object->inlineComponentsEnd(), [&](const QV4::CompiledData::InlineComponent &ic) {
- return ic.objectIndex == icObjectId;
- });
- if (icIt != object->inlineComponentsEnd()) {
- Q_ASSERT(m_inlineComponentToCompiledData.contains(icIt->nameIndex));
- return m_inlineComponentToCompiledData[icIt->nameIndex].data();
- }
- }
- Q_UNREACHABLE();
- return nullptr; // make integrity happy
-}
-
void QQmlTypeData::registerCallback(TypeDataCallback *callback)
{
Q_ASSERT(!m_callbacks.contains(callback));
@@ -124,23 +69,19 @@ void QQmlTypeData::unregisterCallback(TypeDataCallback *callback)
Q_ASSERT(!m_callbacks.contains(callback));
}
-CompositeMetaTypeIds QQmlTypeData::typeIds(int objectId) const
+QQmlType QQmlTypeData::qmlType(const QString &inlineComponentName) const
{
- if (objectId != 0)
- return m_inlineComponentData[objectId].typeIds;
- return m_typeIds;
+ if (inlineComponentName.isEmpty())
+ return m_qmlType;
+ return m_inlineComponentData[inlineComponentName].qmlType;
}
bool QQmlTypeData::tryLoadFromDiskCache()
{
- if (!diskCacheEnabled())
+ if (!readCacheFile())
return false;
- QV4::ExecutionEngine *v4 = typeLoader()->engine()->handle();
- if (!v4)
- return false;
-
- QQmlRefPointer<QV4::ExecutableCompilationUnit> unit = QV4::ExecutableCompilationUnit::create();
+ auto unit = QQml::makeRefPointer<QV4::CompiledData::CompilationUnit>();
{
QString error;
if (!unit->loadFromDisk(url(), m_backupSourceCode.sourceTimeStamp(), &error)) {
@@ -150,11 +91,11 @@ bool QQmlTypeData::tryLoadFromDiskCache()
}
if (unit->unitData()->flags & QV4::CompiledData::Unit::PendingTypeCompilation) {
- restoreIR(std::move(*unit));
+ restoreIR(unit);
return true;
}
- m_compiledData = unit;
+ m_compiledData = std::move(unit);
QVector<QV4::CompiledData::InlineComponent> ics;
for (int i = 0, count = m_compiledData->objectCount(); i < count; ++i) {
@@ -166,7 +107,7 @@ bool QQmlTypeData::tryLoadFromDiskCache()
}
}
- m_importCache.setBaseUrl(finalUrl(), finalUrlString());
+ m_importCache->setBaseUrl(finalUrl(), finalUrlString());
// For remote URLs, we don't delay the loading of the implicit import
// because the loading probably requires an asynchronous fetch of the
@@ -185,7 +126,9 @@ bool QQmlTypeData::tryLoadFromDiskCache()
&& !import->version.hasMajorVersion()
&& !import->version.hasMinorVersion()) {
QList<QQmlError> errors;
- auto pendingImport = std::make_shared<PendingImport>(this, import);
+ auto pendingImport = std::make_shared<PendingImport>(
+ this, import, QQmlImports::ImportNoFlag);
+ pendingImport->precedence = QQmlImportInstance::Implicit;
if (!fetchQmldir(qmldirUrl, pendingImport, 1, &errors)) {
setError(errors);
return false;
@@ -202,72 +145,158 @@ bool QQmlTypeData::tryLoadFromDiskCache()
if (!addImport(import, {}, &errors)) {
Q_ASSERT(errors.size());
QQmlError error(errors.takeFirst());
- error.setUrl(m_importCache.baseUrl());
- error.setLine(qmlConvertSourceCoordinate<quint32, int>(import->location.line));
- error.setColumn(qmlConvertSourceCoordinate<quint32, int>(import->location.column));
+ error.setUrl(m_importCache->baseUrl());
+ error.setLine(qmlConvertSourceCoordinate<quint32, int>(import->location.line()));
+ error.setColumn(qmlConvertSourceCoordinate<quint32, int>(import->location.column()));
errors.prepend(error); // put it back on the list after filling out information.
setError(errors);
return false;
}
}
- QQmlType containingType;
- auto containingTypeName = finalUrl().fileName().split(QLatin1Char('.')).first();
- QTypeRevision version;
- QQmlImportNamespace *ns = nullptr;
- m_importCache.resolveType(containingTypeName, &containingType, &version, &ns);
for (auto&& ic: ics) {
QString const nameString = m_compiledData->stringAt(ic.nameIndex);
- QByteArray const name = nameString.toUtf8();
auto importUrl = finalUrl();
- importUrl.setFragment(QString::number(ic.objectIndex));
+ importUrl.setFragment(nameString);
auto import = new QQmlImportInstance();
- m_importCache.addInlineComponentImport(import, nameString, importUrl, containingType);
+ m_importCache->addInlineComponentImport(import, nameString, importUrl);
}
return true;
}
-void QQmlTypeData::createTypeAndPropertyCaches(
+template<>
+void QQmlComponentAndAliasResolver<QV4::CompiledData::CompilationUnit>::allocateNamedObjects(
+ const QV4::CompiledData::Object *object) const
+{
+ Q_UNUSED(object);
+}
+
+template<>
+bool QQmlComponentAndAliasResolver<QV4::CompiledData::CompilationUnit>::markAsComponent(int index) const
+{
+ return m_compiler->objectAt(index)->hasFlag(QV4::CompiledData::Object::IsComponent);
+}
+
+template<>
+void QQmlComponentAndAliasResolver<QV4::CompiledData::CompilationUnit>::setObjectId(int index) const
+{
+ Q_UNUSED(index)
+ // we cannot sanity-check the index here because bindings are sorted in a different order
+ // in the CU vs the IR.
+}
+
+template<>
+void QQmlComponentAndAliasResolver<QV4::CompiledData::CompilationUnit>::resolveGeneralizedGroupProperty(
+ const CompiledObject &component, CompiledBinding *binding)
+{
+ // We cannot make it fail here. It might be a custom-parsed property
+ for (int i = 0, count = component.namedObjectsInComponentCount(); i < count; ++i) {
+ const int candidateIndex = component.namedObjectsInComponentTable()[i];
+ if (m_compiler->objectAt(candidateIndex)->idNameIndex == binding->propertyNameIndex) {
+ m_propertyCaches->set(binding->value.objectIndex, m_propertyCaches->at(candidateIndex));
+ return;
+ }
+ }
+}
+
+template<>
+typename QQmlComponentAndAliasResolver<QV4::CompiledData::CompilationUnit>::AliasResolutionResult
+QQmlComponentAndAliasResolver<QV4::CompiledData::CompilationUnit>::resolveAliasesInObject(
+ const CompiledObject &component, int objectIndex, QQmlError *error)
+{
+ const CompiledObject *obj = m_compiler->objectAt(objectIndex);
+ for (auto alias = obj->aliasesBegin(), end = obj->aliasesEnd(); alias != end; ++alias) {
+ if (!alias->hasFlag(QV4::CompiledData::Alias::Resolved)) {
+ *error = qQmlCompileError( alias->referenceLocation, tr("Unresolved alias found"));
+ return NoAliasResolved;
+ }
+
+ if (alias->isAliasToLocalAlias() || alias->encodedMetaPropertyIndex == -1)
+ continue;
+
+ const int targetObjectIndex
+ = objectForId(m_compiler, component, alias->targetObjectId());
+ const int coreIndex
+ = QQmlPropertyIndex::fromEncoded(alias->encodedMetaPropertyIndex).coreIndex();
+
+ QQmlPropertyCache::ConstPtr targetCache = m_propertyCaches->at(targetObjectIndex);
+ Q_ASSERT(targetCache);
+
+ if (!targetCache->property(coreIndex))
+ return SomeAliasesResolved;
+ }
+
+ return AllAliasesResolved;
+}
+
+template<>
+bool QQmlComponentAndAliasResolver<QV4::CompiledData::CompilationUnit>::wrapImplicitComponent(
+ const QV4::CompiledData::Binding *binding)
+{
+ // This should have been done when creating the CU.
+ Q_UNUSED(binding);
+ return false;
+}
+
+QQmlError QQmlTypeData::createTypeAndPropertyCaches(
const QQmlRefPointer<QQmlTypeNameCache> &typeNameCache,
- const QV4::ResolvedTypeReferenceMap &resolvedTypeCache)
+ const QV4::CompiledData::ResolvedTypeReferenceMap &resolvedTypeCache)
{
Q_ASSERT(m_compiledData);
m_compiledData->typeNameCache = typeNameCache;
m_compiledData->resolvedTypes = resolvedTypeCache;
+ m_compiledData->inlineComponentData = m_inlineComponentData;
QQmlEnginePrivate * const engine = QQmlEnginePrivate::get(typeLoader()->engine());
QQmlPendingGroupPropertyBindings pendingGroupPropertyBindings;
{
- QQmlPropertyCacheCreator<QV4::ExecutableCompilationUnit> propertyCacheCreator(
+ QQmlPropertyCacheCreator<QV4::CompiledData::CompilationUnit> propertyCacheCreator(
&m_compiledData->propertyCaches, &pendingGroupPropertyBindings, engine,
- m_compiledData.data(), &m_importCache, typeClassName());
- QQmlError error = propertyCacheCreator.buildMetaObjects();
- if (error.isValid()) {
- setError(error);
- return;
- }
- }
+ m_compiledData.data(), m_importCache.data(), typeClassName());
+
+ QQmlError error = propertyCacheCreator.verifyNoICCycle();
+ if (error.isValid())
+ return error;
+
+ QQmlPropertyCacheCreatorBase::IncrementalResult result;
+ do {
+ result = propertyCacheCreator.buildMetaObjectsIncrementally();
+ if (result.error.isValid()) {
+ return result.error;
+ } else {
+ QQmlComponentAndAliasResolver resolver(
+ m_compiledData.data(), engine, &m_compiledData->propertyCaches);
+ if (const QQmlError error = resolver.resolve(result.processedRoot);
+ error.isValid()) {
+ return error;
+ }
+ pendingGroupPropertyBindings.resolveMissingPropertyCaches(
+ &m_compiledData->propertyCaches);
+ pendingGroupPropertyBindings.clear(); // anything that can be processed is now processed
+ }
- QQmlPropertyCacheAliasCreator<QV4::ExecutableCompilationUnit> aliasCreator(
- &m_compiledData->propertyCaches, m_compiledData.data());
- aliasCreator.appendAliasPropertiesToMetaObjects(engine);
+ } while (result.canResume);
+ }
- pendingGroupPropertyBindings.resolveMissingPropertyCaches(engine, &m_compiledData->propertyCaches);
+ pendingGroupPropertyBindings.resolveMissingPropertyCaches(&m_compiledData->propertyCaches);
+ return QQmlError();
}
-static bool addTypeReferenceChecksumsToHash(const QList<QQmlTypeData::TypeReference> &typeRefs, QCryptographicHash *hash, QQmlEngine *engine)
+static bool addTypeReferenceChecksumsToHash(
+ const QList<QQmlTypeData::TypeReference> &typeRefs,
+ QHash<quintptr, QByteArray> *checksums, QCryptographicHash *hash)
{
for (const auto &typeRef: typeRefs) {
if (typeRef.typeData) {
const auto unit = typeRef.typeData->compilationUnit()->unitData();
- hash->addData(unit->md5Checksum, sizeof(unit->md5Checksum));
- } else if (typeRef.type.isValid()) {
- const auto propertyCache = QQmlEnginePrivate::get(engine)->cache(typeRef.type.metaObject());
+ hash->addData({unit->md5Checksum, sizeof(unit->md5Checksum)});
+ } else if (const QMetaObject *mo = typeRef.type.metaObject()) {
+ const auto propertyCache = QQmlMetaType::propertyCache(mo);
bool ok = false;
- hash->addData(propertyCache->checksum(&ok));
+ hash->addData(propertyCache->checksum(checksums, &ok));
if (!ok)
return false;
}
@@ -277,15 +306,25 @@ static bool addTypeReferenceChecksumsToHash(const QList<QQmlTypeData::TypeRefere
// local helper function for inline components
namespace {
+using InlineComponentData = QV4::CompiledData::InlineComponentData;
+
template<typename ObjectContainer>
-void setupICs(const ObjectContainer &container, QHash<int, InlineComponentData> *icData, const QUrl &finalUrl) {
+void setupICs(
+ const ObjectContainer &container, QHash<QString, InlineComponentData> *icData,
+ const QUrl &baseUrl,
+ const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &compilationUnit) {
Q_ASSERT(icData->empty());
for (int i = 0; i != container->objectCount(); ++i) {
auto root = container->objectAt(i);
for (auto it = root->inlineComponentsBegin(); it != root->inlineComponentsEnd(); ++it) {
- const QByteArray &className = QQmlPropertyCacheCreatorBase::createClassNameForInlineComponent(finalUrl, it->objectIndex);
- InlineComponentData icDatum(CompositeMetaTypeIds::fromCompositeName(className), int(it->objectIndex), int(it->nameIndex), 0, 0, 0);
- icData->insert(it->objectIndex, icDatum);
+ // We cannot re-use a previously finalized inline component type here. We need our own.
+ // We can and should re-use speculative type references, though.
+ InlineComponentData icDatum(
+ QQmlMetaType::findInlineComponentType(
+ baseUrl, container->stringAt(it->nameIndex), compilationUnit),
+ int(it->objectIndex), int(it->nameIndex), 0, 0, 0);
+
+ icData->insert(container->stringAt(it->nameIndex), icDatum);
}
}
};
@@ -313,13 +352,14 @@ void QQmlTypeData::setCompileUnit(const Container &container)
void QQmlTypeData::done()
{
auto cleanup = qScopeGuard([this]{
+ m_backupSourceCode = SourceCodeData();
m_document.reset();
m_typeReferences.clear();
if (isError()) {
const auto encounteredErrors = errors();
for (const QQmlError &e : encounteredErrors)
qCDebug(DBG_DISK_CACHE) << e.toString();
- m_compiledData = nullptr;
+ m_compiledData.reset();
}
});
@@ -327,15 +367,15 @@ void QQmlTypeData::done()
return;
// Check all script dependencies for errors
- for (int ii = 0; ii < m_scripts.count(); ++ii) {
+ for (int ii = 0; ii < m_scripts.size(); ++ii) {
const ScriptReference &script = m_scripts.at(ii);
Q_ASSERT(script.script->isCompleteOrError());
if (script.script->isError()) {
QList<QQmlError> errors = script.script->errors();
QQmlError error;
error.setUrl(url());
- error.setLine(qmlConvertSourceCoordinate<quint32, int>(script.location.line));
- error.setColumn(qmlConvertSourceCoordinate<quint32, int>(script.location.column));
+ error.setLine(qmlConvertSourceCoordinate<quint32, int>(script.location.line()));
+ error.setColumn(qmlConvertSourceCoordinate<quint32, int>(script.location.column()));
error.setDescription(QQmlTypeLoader::tr("Script %1 unavailable").arg(script.script->urlString()));
errors.prepend(error);
setError(errors);
@@ -344,75 +384,70 @@ void QQmlTypeData::done()
}
// Check all type dependencies for errors
- for (auto it = qAsConst(m_resolvedTypes).begin(), end = qAsConst(m_resolvedTypes).end(); it != end;
+ auto createError = [&](const TypeReference &type , const QString &message) {
+ QList<QQmlError> errors = type.typeData ? type.typeData->errors() : QList<QQmlError>{};
+ QQmlError error;
+ error.setUrl(url());
+ error.setLine(qmlConvertSourceCoordinate<quint32, int>(type.location.line()));
+ error.setColumn(qmlConvertSourceCoordinate<quint32, int>(type.location.column()));
+ error.setDescription(message);
+ errors.prepend(error);
+ setError(errors);
+ };
+ for (auto it = std::as_const(m_resolvedTypes).begin(), end = std::as_const(m_resolvedTypes).end(); it != end;
++it) {
const TypeReference &type = *it;
Q_ASSERT(!type.typeData || type.typeData->isCompleteOrError() || type.type.isInlineComponentType());
- if (type.type.isInlineComponentType() && !type.type.pendingResolutionName().isEmpty()) {
- auto containingType = type.type.containingType();
- auto objectId = containingType.lookupInlineComponentIdByName(type.type.pendingResolutionName());
- if (objectId < 0) { // can be any negative number if we tentatively resolved it in QQmlImport but it actually was not an inline component
- const QString typeName = stringAt(it.key());
- int lastDot = typeName.lastIndexOf(u'.');
- QList<QQmlError> errors = type.typeData ? type.typeData->errors() : QList<QQmlError>{};
- QQmlError error;
- error.setUrl(url());
- error.setLine(qmlConvertSourceCoordinate<quint32, int>(type.location.line));
- error.setColumn(qmlConvertSourceCoordinate<quint32, int>(type.location.column));
- error.setDescription(QQmlTypeLoader::tr("Type %1 has no inline component type called %2").arg(QStringView{typeName}.left(lastDot), type.type.pendingResolutionName()));
- errors.prepend(error);
- setError(errors);
+ if (type.type.isInlineComponentType()) {
+ const QUrl url = type.type.sourceUrl();
+ if (!QQmlMetaType::equalBaseUrls(url, finalUrl())
+ && !QQmlMetaType::obtainCompilationUnit(type.type.typeId())) {
+ const QString &typeName = stringAt(it.key());
+ int lastDot = typeName.lastIndexOf(u'.');
+ createError(
+ type,
+ QQmlTypeLoader::tr("Type %1 has no inline component type called %2")
+ .arg(QStringView{typeName}.left(lastDot), type.type.elementName()));
return;
- } else {
- type.type.setInlineComponentObjectId(objectId);
}
}
if (type.typeData && type.typeData->isError()) {
- const QString typeName = stringAt(it.key());
-
- QList<QQmlError> errors = type.typeData->errors();
- QQmlError error;
- error.setUrl(url());
- error.setLine(qmlConvertSourceCoordinate<quint32, int>(type.location.line));
- error.setColumn(qmlConvertSourceCoordinate<quint32, int>(type.location.column));
- error.setDescription(QQmlTypeLoader::tr("Type %1 unavailable").arg(typeName));
- errors.prepend(error);
- setError(errors);
+ const QString &typeName = stringAt(it.key());
+ createError(type, QQmlTypeLoader::tr("Type %1 unavailable").arg(typeName));
return;
}
}
// Check all composite singleton type dependencies for errors
- for (int ii = 0; ii < m_compositeSingletons.count(); ++ii) {
+ for (int ii = 0; ii < m_compositeSingletons.size(); ++ii) {
const TypeReference &type = m_compositeSingletons.at(ii);
Q_ASSERT(!type.typeData || type.typeData->isCompleteOrError());
if (type.typeData && type.typeData->isError()) {
QString typeName = type.type.qmlTypeName();
- QList<QQmlError> errors = type.typeData->errors();
- QQmlError error;
- error.setUrl(url());
- error.setLine(qmlConvertSourceCoordinate<quint32, int>(type.location.line));
- error.setColumn(qmlConvertSourceCoordinate<quint32, int>(type.location.column));
- error.setDescription(QQmlTypeLoader::tr("Type %1 unavailable").arg(typeName));
- errors.prepend(error);
- setError(errors);
+ createError(type, QQmlTypeLoader::tr("Type %1 unavailable").arg(typeName));
return;
}
}
- m_typeClassName = QQmlPropertyCacheCreatorBase::createClassNameTypeByUrl(finalUrl());
- if (!m_typeClassName.isEmpty())
- m_typeIds = CompositeMetaTypeIds::fromCompositeName(m_typeClassName);
-
- if (m_document) {
- setupICs(m_document, &m_inlineComponentData, finalUrl());
- } else {
- setupICs(m_compiledData, &m_inlineComponentData, finalUrl());
+ if (QQmlPropertyCacheCreatorBase::canCreateClassNameTypeByUrl(finalUrl())) {
+ const bool isSingleton = m_document
+ ? m_document.data()->isSingleton()
+ : (m_compiledData->unitData()->flags & QV4::CompiledData::Unit::IsSingleton);
+ m_qmlType = QQmlMetaType::findCompositeType(
+ finalUrl(), m_compiledData, isSingleton
+ ? QQmlMetaType::Singleton
+ : QQmlMetaType::NonSingleton);
+ m_typeClassName = QByteArray(m_qmlType.typeId().name()).chopped(1);
}
- QV4::ResolvedTypeReferenceMap resolvedTypeCache;
+ if (m_document)
+ setupICs(m_document, &m_inlineComponentData, finalUrl(), m_compiledData);
+ else
+ setupICs(m_compiledData, &m_inlineComponentData, finalUrl(), m_compiledData);
+
+ QV4::CompiledData::ResolvedTypeReferenceMap resolvedTypeCache;
QQmlRefPointer<QQmlTypeNameCache> typeNameCache;
{
QQmlError error = buildTypeResolutionCaches(&typeNameCache, &resolvedTypeCache);
@@ -423,45 +458,73 @@ void QQmlTypeData::done()
}
}
- QQmlEngine *const engine = typeLoader()->engine();
-
- const auto dependencyHasher = [engine, &resolvedTypeCache, this]() {
+ const auto dependencyHasher = [&resolvedTypeCache, this]() {
QCryptographicHash hash(QCryptographicHash::Md5);
- return (resolvedTypeCache.addToHash(&hash, engine)
- && ::addTypeReferenceChecksumsToHash(m_compositeSingletons, &hash, engine))
+ return (resolvedTypeCache.addToHash(&hash, typeLoader()->checksumCache())
+ && ::addTypeReferenceChecksumsToHash(
+ m_compositeSingletons, typeLoader()->checksumCache(), &hash))
? hash.result()
: QByteArray();
};
// verify if any dependencies changed if we're using a cache
- if (m_document.isNull() && !m_compiledData->verifyChecksum(dependencyHasher)) {
- qCDebug(DBG_DISK_CACHE) << "Checksum mismatch for cached version of" << m_compiledData->fileName();
- if (!loadFromSource())
- return;
- m_backupSourceCode = SourceCodeData();
- m_compiledData = nullptr;
+ if (m_document.isNull()) {
+ const QQmlError error = createTypeAndPropertyCaches(typeNameCache, resolvedTypeCache);
+ if (!error.isValid() && m_compiledData->verifyChecksum(dependencyHasher)) {
+ setCompileUnit(m_compiledData);
+ } else {
+
+ if (error.isValid()) {
+ qCDebug(DBG_DISK_CACHE)
+ << "Failed to create property caches for"
+ << m_compiledData->fileName()
+ << "because" << error.description();
+ } else {
+ qCDebug(DBG_DISK_CACHE)
+ << "Checksum mismatch for cached version of"
+ << m_compiledData->fileName();
+ }
+
+ if (!loadFromSource())
+ return;
+
+ // We want to keep our resolve types ...
+ m_compiledData->resolvedTypes.clear();
+ // ... but we don't want the property caches we've created for the broken CU.
+ for (QV4::ResolvedTypeReference *ref: std::as_const(resolvedTypeCache)) {
+ const auto compilationUnit = ref->compilationUnit();
+ if (compilationUnit.isNull()) {
+ // Inline component references without CU belong to the surrounding CU.
+ // We have to clear them. Inline component references to other documents
+ // have a CU.
+ if (!ref->type().isInlineComponentType())
+ continue;
+ } else if (compilationUnit != m_compiledData) {
+ continue;
+ }
+ ref->setTypePropertyCache(QQmlPropertyCache::ConstPtr());
+ ref->setCompilationUnit(QQmlRefPointer<QV4::CompiledData::CompilationUnit>());
+ }
+
+ m_compiledData.reset();
+ }
}
if (!m_document.isNull()) {
// Compile component
compile(typeNameCache, &resolvedTypeCache, dependencyHasher);
- if (!isError())
+ if (isError())
+ return;
+ else
setCompileUnit(m_document);
- } else {
- createTypeAndPropertyCaches(typeNameCache, resolvedTypeCache);
- if (!isError())
- setCompileUnit(m_compiledData);
}
- if (isError())
- return;
-
{
- QQmlEnginePrivate *const enginePrivate = QQmlEnginePrivate::get(engine);
+ QQmlEnginePrivate *const enginePrivate = QQmlEnginePrivate::get(typeLoader()->engine());
m_compiledData->inlineComponentData = m_inlineComponentData;
{
// Sanity check property bindings
- QQmlPropertyValidator validator(enginePrivate, m_importCache, m_compiledData);
+ QQmlPropertyValidator validator(enginePrivate, m_importCache.data(), m_compiledData);
QVector<QQmlError> errors = validator.validate();
if (!errors.isEmpty()) {
setError(errors);
@@ -469,7 +532,7 @@ void QQmlTypeData::done()
}
}
- m_compiledData->finalizeCompositeType(enginePrivate, typeIds());
+ m_compiledData->finalizeCompositeType(qmlType());
}
{
@@ -497,30 +560,10 @@ void QQmlTypeData::done()
}
}
- // associate inline components to root component
- {
- auto typeName = QStringView{finalUrlString()}.split(u'/').last().split(u'.').first().toString();
- // typeName can be empty if a QQmlComponent was constructed with an empty QUrl parameter
- if (!typeName.isEmpty() && typeName.at(0).isUpper() && !m_inlineComponentData.isEmpty()) {
- QHashedStringRef const hashedStringRef { typeName };
- QList<QQmlError> errors;
- auto type = QQmlMetaType::typeForUrl(finalUrlString(), hashedStringRef, false, &errors);
- Q_ASSERT(errors.empty());
- if (type.isValid()) {
- for (auto const &icDatum : m_inlineComponentData) {
- Q_ASSERT(icDatum.typeIds.isValid());
- QQmlType existingType = type.lookupInlineComponentById(type.lookupInlineComponentIdByName(m_compiledData->stringAt(icDatum.nameIndex)));
- type.associateInlineComponent(m_compiledData->stringAt(icDatum.nameIndex),
- icDatum.objectIndex, icDatum.typeIds, existingType);
- }
- }
- }
- }
-
{
// Collect imported scripts
- m_compiledData->dependentScripts.reserve(m_scripts.count());
- for (int scriptIndex = 0; scriptIndex < m_scripts.count(); ++scriptIndex) {
+ m_compiledData->dependentScripts.reserve(m_scripts.size());
+ for (int scriptIndex = 0; scriptIndex < m_scripts.size(); ++scriptIndex) {
const QQmlTypeData::ScriptReference &script = m_scripts.at(scriptIndex);
QStringView qualifier(script.qualifier);
@@ -532,7 +575,8 @@ void QQmlTypeData::done()
qualifier = qualifier.mid(lastDotIndex+1);
}
- m_compiledData->typeNameCache->add(qualifier.toString(), scriptIndex, enclosingNamespace);
+ m_compiledData->typeNameCache->add(
+ qualifier.toString(), scriptIndex, enclosingNamespace);
QQmlRefPointer<QQmlScriptData> scriptData = script.script->scriptData();
m_compiledData->dependentScripts << scriptData;
}
@@ -552,14 +596,28 @@ bool QQmlTypeData::loadImplicitImport()
{
m_implicitImportLoaded = true; // Even if we hit an error, count as loaded (we'd just keep hitting the error)
- m_importCache.setBaseUrl(finalUrl(), finalUrlString());
+ m_importCache->setBaseUrl(finalUrl(), finalUrlString());
- QQmlImportDatabase *importDatabase = typeLoader()->importDatabase();
// For local urls, add an implicit import "." as most overridden lookup.
// This will also trigger the loading of the qmldir and the import of any native
// types from available plugins.
QList<QQmlError> implicitImportErrors;
- m_importCache.addImplicitImport(importDatabase, &implicitImportErrors);
+ QString localQmldir;
+ m_importCache->addImplicitImport(typeLoader(), &localQmldir, &implicitImportErrors);
+
+ // When loading with QQmlImports::ImportImplicit, the imports are _appended_ to the namespace
+ // in the order they are loaded. Therefore, the addImplicitImport above gets the highest
+ // precedence. This is in contrast to normal priority imports. Those are _prepended_ in the
+ // order they are loaded.
+ if (!localQmldir.isEmpty()) {
+ const QQmlTypeLoaderQmldirContent qmldir = typeLoader()->qmldirContent(localQmldir);
+ const QList<QQmlDirParser::Import> moduleImports
+ = QQmlMetaType::moduleImports(qmldir.typeNamespace(), QTypeRevision())
+ + qmldir.imports();
+ loadDependentImports(moduleImports, QString(), QTypeRevision(),
+ QQmlImportInstance::Implicit + 1, QQmlImports::ImportNoFlag,
+ &implicitImportErrors);
+ }
if (!implicitImportErrors.isEmpty()) {
setError(implicitImportErrors);
@@ -602,7 +660,10 @@ void QQmlTypeData::initializeFromCachedUnit(const QQmlPrivate::CachedQmlUnit *un
loader.load();
m_document->jsModule.fileName = urlString();
m_document->jsModule.finalUrl = finalUrlString();
- m_document->javaScriptCompilationUnit = QV4::CompiledData::CompilationUnit(unit->qmlData, unit->aotCompiledFunctions);
+ m_document->javaScriptCompilationUnit
+ = QQmlRefPointer<QV4::CompiledData::CompilationUnit>(
+ new QV4::CompiledData::CompilationUnit(unit->qmlData, unit->aotCompiledFunctions),
+ QQmlRefPointer<QV4::CompiledData::CompilationUnit>::Adopt);
continueLoadFromIR();
}
@@ -622,8 +683,8 @@ bool QQmlTypeData::loadFromSource()
if (!compiler.generateFromQml(source, finalUrlString(), m_document.data())) {
QList<QQmlError> errors;
- errors.reserve(compiler.errors.count());
- for (const QQmlJS::DiagnosticMessage &msg : qAsConst(compiler.errors)) {
+ errors.reserve(compiler.errors.size());
+ for (const QQmlJS::DiagnosticMessage &msg : std::as_const(compiler.errors)) {
QQmlError e;
e.setUrl(url());
e.setLine(qmlConvertSourceCoordinate<quint32, int>(msg.loc.startLine));
@@ -637,37 +698,31 @@ bool QQmlTypeData::loadFromSource()
return true;
}
-void QQmlTypeData::restoreIR(QV4::CompiledData::CompilationUnit &&unit)
+void QQmlTypeData::restoreIR(const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &unit)
{
m_document.reset(new QmlIR::Document(isDebugging()));
- QQmlIRLoader loader(unit.unitData(), m_document.data());
+ QQmlIRLoader loader(unit->unitData(), m_document.data());
loader.load();
m_document->jsModule.fileName = urlString();
m_document->jsModule.finalUrl = finalUrlString();
- m_document->javaScriptCompilationUnit = std::move(unit);
+ m_document->javaScriptCompilationUnit = unit;
continueLoadFromIR();
}
void QQmlTypeData::continueLoadFromIR()
{
- QQmlType containingType;
- auto containingTypeName = finalUrl().fileName().split(QLatin1Char('.')).first();
- QTypeRevision version;
- QQmlImportNamespace *ns = nullptr;
- m_importCache.resolveType(containingTypeName, &containingType, &version, &ns);
for (auto const& object: m_document->objects) {
for (auto it = object->inlineComponentsBegin(); it != object->inlineComponentsEnd(); ++it) {
QString const nameString = m_document->stringAt(it->nameIndex);
- QByteArray const name = nameString.toUtf8();
auto importUrl = finalUrl();
- importUrl.setFragment(QString::number(it->objectIndex));
+ importUrl.setFragment(nameString);
auto import = new QQmlImportInstance(); // Note: The cache takes ownership of the QQmlImportInstance
- m_importCache.addInlineComponentImport(import, nameString, importUrl, containingType);
+ m_importCache->addInlineComponentImport(import, nameString, importUrl);
}
}
m_typeReferences.collectFromObjects(m_document->objects.constBegin(), m_document->objects.constEnd());
- m_importCache.setBaseUrl(finalUrl(), finalUrlString());
+ m_importCache->setBaseUrl(finalUrl(), finalUrlString());
// For remote URLs, we don't delay the loading of the implicit import
// because the loading probably requires an asynchronous fetch of the
@@ -692,15 +747,18 @@ void QQmlTypeData::continueLoadFromIR()
QList<QQmlError> errors;
- for (const QV4::CompiledData::Import *import : qAsConst(m_document->imports)) {
+ for (const QV4::CompiledData::Import *import : std::as_const(m_document->imports)) {
if (!addImport(import, {}, &errors)) {
Q_ASSERT(errors.size());
- QQmlError error(errors.takeFirst());
- error.setUrl(m_importCache.baseUrl());
- error.setLine(qmlConvertSourceCoordinate<quint32, int>(import->location.line));
- error.setColumn(qmlConvertSourceCoordinate<quint32, int>(import->location.column));
- errors.prepend(error); // put it back on the list after filling out information.
- setError(errors);
+
+ // We're only interested in the chronoligically last error. The previous
+ // errors might be from unsuccessfully trying to load a module from the
+ // resource file system.
+ QQmlError error = errors.first();
+ error.setUrl(m_importCache->baseUrl());
+ error.setLine(qmlConvertSourceCoordinate<quint32, int>(import->location.line()));
+ error.setColumn(qmlConvertSourceCoordinate<quint32, int>(import->location.column()));
+ setError(error);
return;
}
}
@@ -720,12 +778,14 @@ void QQmlTypeData::allDependenciesDone()
for (auto keyIt = m_unresolvedImports.constBegin(),
keyEnd = m_unresolvedImports.constEnd();
keyIt != keyEnd; ++keyIt) {
- PendingImportPtr import = *keyIt;
+ const PendingImportPtr &import = *keyIt;
QQmlError error;
error.setDescription(QQmlTypeLoader::tr("module \"%1\" is not installed").arg(import->uri));
- error.setUrl(m_importCache.baseUrl());
- error.setLine(qmlConvertSourceCoordinate<quint32, int>(import->location.line));
- error.setColumn(qmlConvertSourceCoordinate<quint32, int>(import->location.column));
+ error.setUrl(m_importCache->baseUrl());
+ error.setLine(qmlConvertSourceCoordinate<quint32, int>(
+ import->location.line()));
+ error.setColumn(qmlConvertSourceCoordinate<quint32, int>(
+ import->location.column()));
errors.prepend(error);
}
}
@@ -742,7 +802,7 @@ void QQmlTypeData::allDependenciesDone()
void QQmlTypeData::downloadProgressChanged(qreal p)
{
- for (int ii = 0; ii < m_callbacks.count(); ++ii) {
+ for (int ii = 0; ii < m_callbacks.size(); ++ii) {
TypeDataCallback *callback = m_callbacks.at(ii);
callback->typeDataProgress(this, p);
}
@@ -756,42 +816,58 @@ QString QQmlTypeData::stringAt(int index) const
}
void QQmlTypeData::compile(const QQmlRefPointer<QQmlTypeNameCache> &typeNameCache,
- QV4::ResolvedTypeReferenceMap *resolvedTypeCache,
+ QV4::CompiledData::ResolvedTypeReferenceMap *resolvedTypeCache,
const QV4::CompiledData::DependentTypesHasher &dependencyHasher)
{
Q_ASSERT(m_compiledData.isNull());
- const bool typeRecompilation = m_document && m_document->javaScriptCompilationUnit.unitData()
- && (m_document->javaScriptCompilationUnit.unitData()->flags & QV4::CompiledData::Unit::PendingTypeCompilation);
+ const bool typeRecompilation = m_document
+ && m_document->javaScriptCompilationUnit
+ && m_document->javaScriptCompilationUnit->unitData()
+ && (m_document->javaScriptCompilationUnit->unitData()->flags
+ & QV4::CompiledData::Unit::PendingTypeCompilation);
QQmlEnginePrivate * const enginePrivate = QQmlEnginePrivate::get(typeLoader()->engine());
- QQmlTypeCompiler compiler(enginePrivate, this, m_document.data(), typeNameCache, resolvedTypeCache, dependencyHasher);
- m_compiledData = compiler.compile();
- if (!m_compiledData) {
+ QQmlTypeCompiler compiler(
+ enginePrivate, this, m_document.data(), resolvedTypeCache, dependencyHasher);
+ auto compilationUnit = compiler.compile();
+ if (!compilationUnit) {
qDeleteAll(*resolvedTypeCache);
resolvedTypeCache->clear();
setError(compiler.compilationErrors());
return;
}
- const bool trySaveToDisk = diskCacheEnabled() && !typeRecompilation;
+ const bool trySaveToDisk = writeCacheFile() && !typeRecompilation;
if (trySaveToDisk) {
QString errorString;
- if (m_compiledData->saveToDisk(url(), &errorString)) {
+ if (compilationUnit->saveToDisk(url(), &errorString)) {
QString error;
- if (!m_compiledData->loadFromDisk(url(), m_backupSourceCode.sourceTimeStamp(), &error)) {
+ if (!compilationUnit->loadFromDisk(url(), m_backupSourceCode.sourceTimeStamp(), &error)) {
// ignore error, keep using the in-memory compilation unit.
}
} else {
- qCDebug(DBG_DISK_CACHE) << "Error saving cached version of" << m_compiledData->fileName() << "to disk:" << errorString;
+ qCDebug(DBG_DISK_CACHE) << "Error saving cached version of"
+ << compilationUnit->fileName() << "to disk:" << errorString;
}
}
+
+ m_compiledData = std::move(compilationUnit);
+ m_compiledData->typeNameCache = typeNameCache;
+ m_compiledData->resolvedTypes = *resolvedTypeCache;
+ m_compiledData->propertyCaches = std::move(*compiler.propertyCaches());
+ Q_ASSERT(m_compiledData->propertyCaches.count()
+ == static_cast<int>(m_compiledData->objectCount()));
}
void QQmlTypeData::resolveTypes()
{
+ // Load the implicit import since it may have additional scripts.
+ if (!m_implicitImportLoaded && !loadImplicitImport())
+ return;
+
// Add any imported scripts to our resolved set
- const auto resolvedScripts = m_importCache.resolvedScripts();
+ const auto resolvedScripts = m_importCache->resolvedScripts();
for (const QQmlImports::ScriptReference &script : resolvedScripts) {
QQmlRefPointer<QQmlScriptBlob> blob = typeLoader()->getScript(script.location);
addDependency(blob.data());
@@ -812,7 +888,7 @@ void QQmlTypeData::resolveTypes()
}
// Lets handle resolved composite singleton types
- const auto resolvedCompositeSingletons = m_importCache.resolvedCompositeSingletons();
+ const auto resolvedCompositeSingletons = m_importCache->resolvedCompositeSingletons();
for (const QQmlImports::CompositeSingletonReference &csRef : resolvedCompositeSingletons) {
TypeReference ref;
QString typeName;
@@ -831,8 +907,8 @@ void QQmlTypeData::resolveTypes()
if (ref.type.isCompositeSingleton()) {
ref.typeData = typeLoader()->getType(ref.type.sourceUrl());
if (ref.typeData->isWaiting() || m_waitingOnMe.contains(ref.typeData.data())) {
- qWarning() << "Cyclic dependency detected between" << ref.typeData->urlString()
- << "and" << urlString();
+ qCDebug(lcCycle) << "Possible cyclic dependency detected between"
+ << ref.typeData->urlString() << "and" << urlString();
continue;
}
addDependency(ref.typeData.data());
@@ -855,8 +931,8 @@ void QQmlTypeData::resolveTypes()
bool *selfReferenceDetection = unresolvedRef->needsCreation ? nullptr : &ref.selfReference;
- if (!resolveType(name, version, ref, unresolvedRef->location.line,
- unresolvedRef->location.column, reportErrors,
+ if (!resolveType(name, version, ref, unresolvedRef->location.line(),
+ unresolvedRef->location.column(), reportErrors,
QQmlType::AnyRegistrationType, selfReferenceDetection) && reportErrors)
return;
@@ -865,21 +941,19 @@ void QQmlTypeData::resolveTypes()
addDependency(ref.typeData.data());
}
if (ref.type.isInlineComponentType()) {
- auto containingType = ref.type.containingType();
- if (containingType.isValid()) {
- auto const url = containingType.sourceUrl();
- if (url.isValid()) {
- auto typeData = typeLoader()->getType(url);
+ QUrl containingTypeUrl = ref.type.sourceUrl();
+ containingTypeUrl.setFragment(QString());
+ if (!containingTypeUrl.isEmpty()) {
+ auto typeData = typeLoader()->getType(containingTypeUrl);
+ if (typeData.data() != this) {
ref.typeData = typeData;
addDependency(typeData.data());
}
}
}
- ref.version = version;
-
- ref.location.line = unresolvedRef->location.line;
- ref.location.column = unresolvedRef->location.column;
+ ref.version = version;
+ ref.location = unresolvedRef->location;
ref.needsCreation = unresolvedRef->needsCreation;
m_resolvedTypes.insert(unresolvedRef.key(), ref);
}
@@ -891,8 +965,7 @@ void QQmlTypeData::resolveTypes()
QQmlError QQmlTypeData::buildTypeResolutionCaches(
QQmlRefPointer<QQmlTypeNameCache> *typeNameCache,
- QV4::ResolvedTypeReferenceMap *resolvedTypeCache
- ) const
+ QV4::CompiledData::ResolvedTypeReferenceMap *resolvedTypeCache) const
{
typeNameCache->adopt(new QQmlTypeNameCache(m_importCache));
@@ -903,12 +976,10 @@ QQmlError QQmlTypeData::buildTypeResolutionCaches(
for (const QQmlTypeData::TypeReference &singleton: m_compositeSingletons)
(*typeNameCache)->add(singleton.type.qmlTypeName(), singleton.type.sourceUrl(), singleton.prefix);
- m_importCache.populateCache(typeNameCache->data());
-
- QQmlEnginePrivate * const engine = QQmlEnginePrivate::get(typeLoader()->engine());
+ m_importCache->populateCache(typeNameCache->data());
for (auto resolvedType = m_resolvedTypes.constBegin(), end = m_resolvedTypes.constEnd(); resolvedType != end; ++resolvedType) {
- QScopedPointer<QV4::ResolvedTypeReference> ref(new QV4::ResolvedTypeReference);
+ auto ref = std::make_unique<QV4::ResolvedTypeReference>();
QQmlType qmlType = resolvedType->type;
if (resolvedType->typeData) {
if (resolvedType->needsCreation && qmlType.isCompositeSingleton()) {
@@ -917,37 +988,31 @@ QQmlError QQmlTypeData::buildTypeResolutionCaches(
ref->setCompilationUnit(resolvedType->typeData->compilationUnit());
if (resolvedType->type.isInlineComponentType()) {
// Inline component which is part of an already resolved type
- int objectId = -1;
- if (qmlType.containingType().isValid()) {
- objectId = qmlType.containingType().lookupInlineComponentIdByName(QString::fromUtf8(qmlType.typeName()));
- qmlType.setInlineComponentObjectId(objectId);
- } else {
- objectId = resolvedType->type.inlineComponentId();
- }
- Q_ASSERT(objectId != -1);
- ref->setTypePropertyCache(resolvedType->typeData->compilationUnit()->propertyCaches.at(objectId));
- ref->setType(qmlType);
+ QString icName = qmlType.elementName();
+ Q_ASSERT(!icName.isEmpty());
+
+ const auto compilationUnit = resolvedType->typeData->compilationUnit();
+ ref->setTypePropertyCache(compilationUnit->propertyCaches.at(
+ compilationUnit->inlineComponentId(icName)));
+ ref->setType(std::move(qmlType));
Q_ASSERT(ref->type().isInlineComponentType());
}
} else if (resolvedType->type.isInlineComponentType()) {
- // Inline component, defined in the file we are currently compiling
- if (!m_inlineComponentToCompiledData.contains(resolvedType.key())) {
- ref->setType(qmlType);
- if (qmlType.isValid()) {
- // this is required for inline components in singletons
- auto type = qmlType.lookupInlineComponentById(qmlType.inlineComponentId()).typeId();
- auto typeID = type.isValid() ? type.id() : -1;
- auto exUnit = engine->obtainExecutableCompilationUnit(typeID);
- if (exUnit) {
- ref->setCompilationUnit(exUnit);
- ref->setTypePropertyCache(engine->propertyCacheForType(typeID));
- }
+ ref->setType(qmlType);
+
+ // Inline component
+ // If it's defined in the same file we're currently compiling, we don't want to use it.
+ // We're going to fill in the property caches later after all.
+ if (qmlType.isValid()
+ && !QQmlMetaType::equalBaseUrls(finalUrl(), qmlType.sourceUrl())) {
+
+ // this is required for inline components in singletons
+ const QMetaType type = qmlType.typeId();
+ if (auto unit = QQmlMetaType::obtainCompilationUnit(type)) {
+ ref->setCompilationUnit(std::move(unit));
+ ref->setTypePropertyCache(QQmlMetaType::propertyCacheForType(type));
}
- } else {
- ref->setCompilationUnit(m_inlineComponentToCompiledData[resolvedType.key()]);
- ref->setTypePropertyCache(m_inlineComponentToCompiledData[resolvedType.key()]->rootPropertyCache());
}
-
} else if (qmlType.isValid() && !resolvedType->selfReference) {
ref->setType(qmlType);
Q_ASSERT(ref->type().isValid());
@@ -959,12 +1024,16 @@ QQmlError QQmlTypeData::buildTypeResolutionCaches(
return qQmlCompileError(resolvedType->location, reason);
}
- if (qmlType.containsRevisionedAttributes())
- ref->setTypePropertyCache(engine->cache(qmlType, resolvedType->version));
+ if (qmlType.containsRevisionedAttributes()) {
+ // It can only have (revisioned) properties or methods if it has a metaobject
+ Q_ASSERT(qmlType.metaObject());
+ ref->setTypePropertyCache(
+ QQmlMetaType::propertyCache(qmlType, resolvedType->version));
+ }
}
ref->setVersion(resolvedType->version);
ref->doDynamicTypeCheck();
- resolvedTypeCache->insert(resolvedType.key(), ref.take());
+ resolvedTypeCache->insert(resolvedType.key(), ref.release());
}
QQmlError noError;
return noError;
@@ -978,17 +1047,17 @@ bool QQmlTypeData::resolveType(const QString &typeName, QTypeRevision &version,
QQmlImportNamespace *typeNamespace = nullptr;
QList<QQmlError> errors;
- bool typeFound = m_importCache.resolveType(typeName, &ref.type, &version,
- &typeNamespace, &errors, registrationType,
- typeRecursionDetected);
+ bool typeFound = m_importCache->resolveType(
+ typeLoader(), typeName, &ref.type, &version, &typeNamespace, &errors, registrationType,
+ typeRecursionDetected);
if (!typeNamespace && !typeFound && !m_implicitImportLoaded) {
// Lazy loading of implicit import
if (loadImplicitImport()) {
// Try again to find the type
errors.clear();
- typeFound = m_importCache.resolveType(typeName, &ref.type, &version,
- &typeNamespace, &errors, registrationType,
- typeRecursionDetected);
+ typeFound = m_importCache->resolveType(
+ typeLoader(), typeName, &ref.type, &version, &typeNamespace, &errors,
+ registrationType, typeRecursionDetected);
} else {
return false; //loadImplicitImport() hit an error, and called setError already
}
@@ -1009,7 +1078,7 @@ bool QQmlTypeData::resolveType(const QString &typeName, QTypeRevision &version,
// Description should come from error provided by addImport() function.
error.setDescription(QQmlTypeLoader::tr("Unreported error adding script import to import database"));
}
- error.setUrl(m_importCache.baseUrl());
+ error.setUrl(m_importCache->baseUrl());
error.setDescription(QQmlTypeLoader::tr("%1 %2").arg(typeName).arg(error.description()));
}
@@ -1026,12 +1095,14 @@ bool QQmlTypeData::resolveType(const QString &typeName, QTypeRevision &version,
return true;
}
-void QQmlTypeData::scriptImported(const QQmlRefPointer<QQmlScriptBlob> &blob, const QV4::CompiledData::Location &location, const QString &qualifier, const QString &/*nameSpace*/)
+void QQmlTypeData::scriptImported(
+ const QQmlRefPointer<QQmlScriptBlob> &blob, const QV4::CompiledData::Location &location,
+ const QString &nameSpace, const QString &qualifier)
{
ScriptReference ref;
ref.script = blob;
ref.location = location;
- ref.qualifier = qualifier;
+ ref.qualifier = qualifier.isEmpty() ? nameSpace : qualifier + QLatin1Char('.') + nameSpace;
m_scripts << ref;
}
diff --git a/src/qml/qml/qqmltypedata_p.h b/src/qml/qml/qqmltypedata_p.h
index 2c56ede9bd..97419b916b 100644
--- a/src/qml/qml/qqmltypedata_p.h
+++ b/src/qml/qml/qqmltypedata_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 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$
-**
-****************************************************************************/
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLTYPEDATA_P_H
#define QQMLTYPEDATA_P_H
@@ -91,10 +55,7 @@ private:
public:
~QQmlTypeData() override;
- const QList<ScriptReference> &resolvedScripts() const;
-
- QV4::ExecutableCompilationUnit *compilationUnit() const;
- QV4::ExecutableCompilationUnit *compilationUnitForInlineComponent(unsigned int icObjectId) const;
+ QV4::CompiledData::CompilationUnit *compilationUnit() const;
// Used by QQmlComponent to get notifications
struct TypeDataCallback {
@@ -105,8 +66,9 @@ public:
void registerCallback(TypeDataCallback *);
void unregisterCallback(TypeDataCallback *);
- CompositeMetaTypeIds typeIds(int objectId = 0) const;
+ QQmlType qmlType(const QString &inlineComponentName = QString()) const;
QByteArray typeClassName() const { return m_typeClassName; }
+ SourceCodeData backupSourceCode() const { return m_backupSourceCode; }
protected:
void done() override;
@@ -119,27 +81,32 @@ protected:
QString stringAt(int index) const override;
private:
+ using InlineComponentData = QV4::CompiledData::InlineComponentData;
+
bool tryLoadFromDiskCache();
bool loadFromSource();
- void restoreIR(QV4::CompiledData::CompilationUnit &&unit);
+ void restoreIR(const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &unit);
void continueLoadFromIR();
void resolveTypes();
QQmlError buildTypeResolutionCaches(
QQmlRefPointer<QQmlTypeNameCache> *typeNameCache,
- QV4::ResolvedTypeReferenceMap *resolvedTypeCache
+ QV4::CompiledData::ResolvedTypeReferenceMap *resolvedTypeCache
) const;
void compile(const QQmlRefPointer<QQmlTypeNameCache> &typeNameCache,
- QV4::ResolvedTypeReferenceMap *resolvedTypeCache,
+ QV4::CompiledData::ResolvedTypeReferenceMap *resolvedTypeCache,
const QV4::CompiledData::DependentTypesHasher &dependencyHasher);
- void createTypeAndPropertyCaches(const QQmlRefPointer<QQmlTypeNameCache> &typeNameCache,
- const QV4::ResolvedTypeReferenceMap &resolvedTypeCache);
+ QQmlError createTypeAndPropertyCaches(
+ const QQmlRefPointer<QQmlTypeNameCache> &typeNameCache,
+ const QV4::CompiledData::ResolvedTypeReferenceMap &resolvedTypeCache);
bool resolveType(const QString &typeName, QTypeRevision &version,
TypeReference &ref, int lineNumber = -1, int columnNumber = -1,
bool reportErrors = true,
QQmlType::RegistrationType registrationType = QQmlType::AnyRegistrationType,
bool *typeRecursionDetected = nullptr);
- void scriptImported(const QQmlRefPointer<QQmlScriptBlob> &blob, const QV4::CompiledData::Location &location, const QString &qualifier, const QString &nameSpace) override;
+ void scriptImported(
+ const QQmlRefPointer<QQmlScriptBlob> &blob, const QV4::CompiledData::Location &location,
+ const QString &nameSpace, const QString &qualifier) override;
SourceCodeData m_backupSourceCode; // used when cache verification fails.
QScopedPointer<QmlIR::Document> m_document;
@@ -156,16 +123,15 @@ private:
QMap<int, TypeReference> m_resolvedTypes;
bool m_typesResolved:1;
- // Used for self-referencing types, otherwise -1.
- CompositeMetaTypeIds m_typeIds;
+ // Used for self-referencing types, otherwise invalid.
+ QQmlType m_qmlType;
QByteArray m_typeClassName; // used for meta-object later
- using ExecutableCompilationUnitPtr = QQmlRefPointer<QV4::ExecutableCompilationUnit>;
+ using CompilationUnitPtr = QQmlRefPointer<QV4::CompiledData::CompilationUnit>;
- QHash<int, InlineComponentData> m_inlineComponentData;
+ QHash<QString, InlineComponentData> m_inlineComponentData;
- ExecutableCompilationUnitPtr m_compiledData;
- QHash<int, ExecutableCompilationUnitPtr> m_inlineComponentToCompiledData;
+ CompilationUnitPtr m_compiledData;
QList<TypeDataCallback *> m_callbacks;
diff --git a/src/qml/qml/qqmltypeloader.cpp b/src/qml/qml/qqmltypeloader.cpp
index ce1625fb63..a74397bd93 100644
--- a/src/qml/qml/qqmltypeloader.cpp
+++ b/src/qml/qml/qqmltypeloader.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <private/qqmltypeloader_p.h>
@@ -82,6 +46,9 @@ namespace {
};
}
+Q_TRACE_POINT(qtqml, QQmlCompiling_entry, const QUrl &url)
+Q_TRACE_POINT(qtqml, QQmlCompiling_exit)
+
/*!
\class QQmlTypeLoader
\brief The QQmlTypeLoader class abstracts loading files and their dependencies over the network.
@@ -124,8 +91,6 @@ void QQmlTypeLoader::invalidate()
// Need to delete the network replies after
// the loader thread is shutdown as it could be
// getting new replies while we clear them
- for (NetworkReplies::Iterator iter = m_networkReplies.begin(); iter != m_networkReplies.end(); ++iter)
- (*iter)->release();
m_networkReplies.clear();
#endif // qml_network
}
@@ -217,9 +182,7 @@ void QQmlTypeLoader::doLoad(const Loader &loader, QQmlDataBlob *blob, Mode mode)
} else {
Q_ASSERT(mode == Synchronous);
while (!blob->isCompleteOrError()) {
- unlock();
m_thread->waitForNextMessage();
- lock();
}
}
}
@@ -250,21 +213,21 @@ void QQmlTypeLoader::loadWithCachedUnit(QQmlDataBlob *blob, const QQmlPrivate::C
doLoad(CachedLoader(unit), blob, mode);
}
-void QQmlTypeLoader::loadWithStaticDataThread(QQmlDataBlob *blob, const QByteArray &data)
+void QQmlTypeLoader::loadWithStaticDataThread(const QQmlDataBlob::Ptr &blob, const QByteArray &data)
{
ASSERT_LOADTHREAD();
setData(blob, data);
}
-void QQmlTypeLoader::loadWithCachedUnitThread(QQmlDataBlob *blob, const QQmlPrivate::CachedQmlUnit *unit)
+void QQmlTypeLoader::loadWithCachedUnitThread(const QQmlDataBlob::Ptr &blob, const QQmlPrivate::CachedQmlUnit *unit)
{
ASSERT_LOADTHREAD();
setCachedUnit(blob, unit);
}
-void QQmlTypeLoader::loadThread(QQmlDataBlob *blob)
+void QQmlTypeLoader::loadThread(const QQmlDataBlob::Ptr &blob)
{
ASSERT_LOADTHREAD();
@@ -290,7 +253,7 @@ void QQmlTypeLoader::loadThread(QQmlDataBlob *blob)
return;
}
- blob->m_data.setProgress(0xFF);
+ blob->m_data.setProgress(1.f);
if (blob->m_data.isAsync())
m_thread->callDownloadProgressChanged(blob, 1.);
@@ -300,7 +263,6 @@ void QQmlTypeLoader::loadThread(QQmlDataBlob *blob)
#if QT_CONFIG(qml_network)
QNetworkReply *reply = m_thread->networkAccessManager()->get(QNetworkRequest(blob->m_url));
QQmlTypeLoaderNetworkReplyProxy *nrp = m_thread->networkReplyProxy();
- blob->addref();
m_networkReplies.insert(reply, blob);
if (reply->isFinished()) {
@@ -332,7 +294,7 @@ void QQmlTypeLoader::networkReplyFinished(QNetworkReply *reply)
reply->deleteLater();
- QQmlDataBlob *blob = m_networkReplies.take(reply);
+ QQmlRefPointer<QQmlDataBlob> blob = m_networkReplies.take(reply);
Q_ASSERT(blob);
@@ -348,7 +310,7 @@ void QQmlTypeLoader::networkReplyFinished(QNetworkReply *reply)
QNetworkReply *reply = m_thread->networkAccessManager()->get(QNetworkRequest(url));
QObject *nrp = m_thread->networkReplyProxy();
QObject::connect(reply, SIGNAL(finished()), nrp, SLOT(finished()));
- m_networkReplies.insert(reply, blob);
+ m_networkReplies.insert(reply, std::move(blob));
#ifdef DATABLOB_DEBUG
qWarning("QQmlDataBlob: redirected to %s", qPrintable(blob->finalUrlString()));
#endif
@@ -362,8 +324,6 @@ void QQmlTypeLoader::networkReplyFinished(QNetworkReply *reply)
QByteArray data = reply->readAll();
setData(blob, data);
}
-
- blob->release();
}
void QQmlTypeLoader::networkReplyProgress(QNetworkReply *reply,
@@ -371,12 +331,12 @@ void QQmlTypeLoader::networkReplyProgress(QNetworkReply *reply,
{
Q_ASSERT(m_thread->isThisThread());
- QQmlDataBlob *blob = m_networkReplies.value(reply);
+ const QQmlRefPointer<QQmlDataBlob> blob = m_networkReplies.value(reply);
Q_ASSERT(blob);
if (bytesTotal != 0) {
- quint8 progress = 0xFF * (qreal(bytesReceived) / qreal(bytesTotal));
+ qreal progress = (qreal(bytesReceived) / qreal(bytesTotal));
blob->m_data.setProgress(progress);
if (blob->m_data.isAsync())
m_thread->callDownloadProgressChanged(blob, blob->m_data.progress());
@@ -420,7 +380,7 @@ void QQmlTypeLoader::initializeEngine(QQmlExtensionInterface *iface, const char
doInitializeEngine(iface, m_thread, engine(), uri);
}
-void QQmlTypeLoader::setData(QQmlDataBlob *blob, const QByteArray &data)
+void QQmlTypeLoader::setData(const QQmlDataBlob::Ptr &blob, const QByteArray &data)
{
QQmlDataBlob::SourceCodeData d;
d.inlineSourceCode = QString::fromUtf8(data);
@@ -428,17 +388,17 @@ void QQmlTypeLoader::setData(QQmlDataBlob *blob, const QByteArray &data)
setData(blob, d);
}
-void QQmlTypeLoader::setData(QQmlDataBlob *blob, const QString &fileName)
+void QQmlTypeLoader::setData(const QQmlDataBlob::Ptr &blob, const QString &fileName)
{
QQmlDataBlob::SourceCodeData d;
d.fileInfo = QFileInfo(fileName);
setData(blob, d);
}
-void QQmlTypeLoader::setData(QQmlDataBlob *blob, const QQmlDataBlob::SourceCodeData &d)
+void QQmlTypeLoader::setData(const QQmlDataBlob::Ptr &blob, const QQmlDataBlob::SourceCodeData &d)
{
Q_TRACE_SCOPE(QQmlCompiling, blob->url());
- QQmlCompilingProfiler prof(profiler(), blob);
+ QQmlCompilingProfiler prof(profiler(), blob.data());
blob->m_inCallback = true;
@@ -455,10 +415,10 @@ void QQmlTypeLoader::setData(QQmlDataBlob *blob, const QQmlDataBlob::SourceCodeD
blob->tryDone();
}
-void QQmlTypeLoader::setCachedUnit(QQmlDataBlob *blob, const QQmlPrivate::CachedQmlUnit *unit)
+void QQmlTypeLoader::setCachedUnit(const QQmlDataBlob::Ptr &blob, const QQmlPrivate::CachedQmlUnit *unit)
{
Q_TRACE_SCOPE(QQmlCompiling, blob->url());
- QQmlCompilingProfiler prof(profiler(), blob);
+ QQmlCompilingProfiler prof(profiler(), blob.data());
blob->m_inCallback = true;
@@ -481,17 +441,21 @@ void QQmlTypeLoader::shutdownThread()
m_thread->shutdown();
}
-QQmlTypeLoader::Blob::PendingImport::PendingImport(QQmlTypeLoader::Blob *blob, const QV4::CompiledData::Import *import)
+QQmlTypeLoader::Blob::PendingImport::PendingImport(
+ QQmlTypeLoader::Blob *blob, const QV4::CompiledData::Import *import,
+ QQmlImports::ImportFlags flags)
+ : uri(blob->stringAt(import->uriIndex))
+ , qualifier(blob->stringAt(import->qualifierIndex))
+ , type(static_cast<QV4::CompiledData::Import::ImportType>(quint32(import->type)))
+ , location(import->location)
+ , flags(flags)
+ , version(import->version)
{
- type = static_cast<QV4::CompiledData::Import::ImportType>(quint32(import->type));
- uri = blob->stringAt(import->uriIndex);
- qualifier = blob->stringAt(import->qualifierIndex);
- version = import->version;
- location = import->location;
}
QQmlTypeLoader::Blob::Blob(const QUrl &url, QQmlDataBlob::Type type, QQmlTypeLoader *loader)
- : QQmlDataBlob(url, type, loader), m_importCache(loader)
+ : QQmlDataBlob(url, type, loader)
+ , m_importCache(new QQmlImports(), QQmlRefPointer<QQmlImports>::Adopt)
{
}
@@ -503,8 +467,7 @@ bool QQmlTypeLoader::Blob::fetchQmldir(const QUrl &url, PendingImportPtr import,
{
QQmlRefPointer<QQmlQmldirData> data = typeLoader()->getQmldir(url);
- data->setImport(this, std::move(import));
- data->setPriority(this, priority);
+ data->setPriority(this, std::move(import), priority);
if (data->status() == Error) {
// This qmldir must not exist - which is not an error
@@ -519,16 +482,55 @@ bool QQmlTypeLoader::Blob::fetchQmldir(const QUrl &url, PendingImportPtr import,
return true;
}
-bool QQmlTypeLoader::Blob::updateQmldir(const QQmlRefPointer<QQmlQmldirData> &data, PendingImportPtr import, QList<QQmlError> *errors)
+/*!
+ * \internal
+ * Import any qualified scripts of for \a import as listed in \a qmldir.
+ * Precondition is that \a import is actually qualified.
+ */
+void QQmlTypeLoader::Blob::importQmldirScripts(
+ const QQmlTypeLoader::Blob::PendingImportPtr &import,
+ const QQmlTypeLoaderQmldirContent &qmldir, const QUrl &qmldirUrl)
+{
+ const auto qmldirScripts = qmldir.scripts();
+ for (const QQmlDirParser::Script &script : qmldirScripts) {
+ const QUrl scriptUrl = qmldirUrl.resolved(QUrl(script.fileName));
+ QQmlRefPointer<QQmlScriptBlob> blob = typeLoader()->getScript(scriptUrl);
+ addDependency(blob.data());
+ scriptImported(blob, import->location, script.nameSpace, import->qualifier);
+ }
+}
+
+template<typename URL>
+void postProcessQmldir(
+ QQmlTypeLoader::Blob *self,
+ const QQmlTypeLoader::Blob::PendingImportPtr &import, const QString &qmldirFilePath,
+ const URL &qmldirUrl)
+{
+ const QQmlTypeLoaderQmldirContent qmldir = self->typeLoader()->qmldirContent(qmldirFilePath);
+ if (!import->qualifier.isEmpty())
+ self->importQmldirScripts(import, qmldir, QUrl(qmldirUrl));
+
+ if (qmldir.plugins().isEmpty()) {
+ // If the qmldir does not register a plugin, we might still have declaratively
+ // registered types (if we are dealing with an application instead of a library)
+ // We should use module name given in the qmldir rather than the one given by the
+ // import since the import may be a directory import.
+ auto module = QQmlMetaType::typeModule(qmldir.typeNamespace(), import->version);
+ if (!module)
+ QQmlMetaType::qmlRegisterModuleTypes(qmldir.typeNamespace());
+ // else: If the module already exists, the types must have been already registered
+ }
+}
+
+bool QQmlTypeLoader::Blob::updateQmldir(const QQmlRefPointer<QQmlQmldirData> &data, const QQmlTypeLoader::Blob::PendingImportPtr &import, QList<QQmlError> *errors)
{
QString qmldirIdentifier = data->urlString();
QString qmldirUrl = qmldirIdentifier.left(qmldirIdentifier.lastIndexOf(QLatin1Char('/')) + 1);
typeLoader()->setQmldirContent(qmldirIdentifier, data->content());
- const QTypeRevision version = m_importCache.updateQmldirContent(
- typeLoader()->importDatabase(), import->uri, import->qualifier, qmldirIdentifier,
- qmldirUrl, errors);
+ const QTypeRevision version = m_importCache->updateQmldirContent(
+ typeLoader(), import->uri, import->qualifier, qmldirIdentifier, qmldirUrl, errors);
if (!version.isValid())
return false;
@@ -536,233 +538,283 @@ bool QQmlTypeLoader::Blob::updateQmldir(const QQmlRefPointer<QQmlQmldirData> &da
if (version.hasMajorVersion())
import->version = version;
- if (!loadImportDependencies(import, qmldirIdentifier, errors))
+ if (!loadImportDependencies(import, qmldirIdentifier, import->flags, errors))
return false;
- import->priority = data->priority(this);
+ import->priority = 0;
// Release this reference at destruction
m_qmldirs << data;
- if (!import->qualifier.isEmpty()) {
- // Does this library contain any qualified scripts?
- QUrl libraryUrl(qmldirUrl);
- const QQmlTypeLoaderQmldirContent qmldir = typeLoader()->qmldirContent(qmldirIdentifier);
- const auto qmldirScripts = qmldir.scripts();
- for (const QQmlDirParser::Script &script : qmldirScripts) {
- QUrl scriptUrl = libraryUrl.resolved(QUrl(script.fileName));
- QQmlRefPointer<QQmlScriptBlob> blob = typeLoader()->getScript(scriptUrl);
- addDependency(blob.data());
-
- scriptImported(blob, import->location, script.nameSpace, import->qualifier);
- }
- }
+ postProcessQmldir(this, import, qmldirIdentifier, qmldirUrl);
+ return true;
+}
+bool QQmlTypeLoader::Blob::addScriptImport(const QQmlTypeLoader::Blob::PendingImportPtr &import)
+{
+ const QUrl url(import->uri);
+ QQmlTypeLoader *loader = typeLoader();
+ QQmlRefPointer<QQmlScriptBlob> blob = loader->injectedScript(url);
+ if (!blob)
+ blob = loader->getScript(finalUrl().resolved(url));
+ else
+ Q_ASSERT(blob->status() == QQmlDataBlob::Status::Complete);
+ addDependency(blob.data());
+ scriptImported(blob, import->location, import->qualifier, QString());
return true;
}
-bool QQmlTypeLoader::Blob::addImport(const QV4::CompiledData::Import *import, uint flags,
- QList<QQmlError> *errors)
+bool QQmlTypeLoader::Blob::addFileImport(const QQmlTypeLoader::Blob::PendingImportPtr &import, QList<QQmlError> *errors)
{
- return addImport(std::make_shared<PendingImport>(this, import), flags, errors);
+ QQmlImports::ImportFlags flags;
+
+ QUrl importUrl(import->uri);
+ QString path = importUrl.path();
+ path.append(QLatin1String(path.endsWith(QLatin1Char('/')) ? "qmldir" : "/qmldir"));
+ importUrl.setPath(path);
+ QUrl qmldirUrl = finalUrl().resolved(importUrl);
+ if (!QQmlImports::isLocal(qmldirUrl)) {
+ // This is a remote file; the import is currently incomplete
+ flags = QQmlImports::ImportIncomplete;
+ }
+
+ const QTypeRevision version = m_importCache->addFileImport(
+ typeLoader(), import->uri, import->qualifier, import->version, flags,
+ import->precedence, nullptr, errors);
+ if (!version.isValid())
+ return false;
+
+ // Use more specific version for the qmldir if possible
+ if (version.hasMajorVersion())
+ import->version = version;
+
+ if (flags & QQmlImports::ImportIncomplete) {
+ if (!fetchQmldir(qmldirUrl, import, 1, errors))
+ return false;
+ } else {
+ const QString qmldirFilePath = QQmlFile::urlToLocalFileOrQrc(qmldirUrl);
+ if (!loadImportDependencies(import, qmldirFilePath, import->flags, errors))
+ return false;
+
+ postProcessQmldir(this, import, qmldirFilePath, qmldirUrl);
+ }
+
+ return true;
}
-bool QQmlTypeLoader::Blob::addImport(QQmlTypeLoader::Blob::PendingImportPtr import, uint flags,
- QList<QQmlError> *errors)
+static void addDependencyImportError(
+ const QQmlTypeLoader::Blob::PendingImportPtr &import, QList<QQmlError> *errors)
{
- Q_ASSERT(errors);
+ QQmlError error;
+ QString reason = errors->front().description();
+ if (reason.size() > 512)
+ reason = reason.first(252) + QLatin1String("... ...") + reason.last(252);
+ if (import->version.hasMajorVersion()) {
+ error.setDescription(QQmlImportDatabase::tr(
+ "module \"%1\" version %2.%3 cannot be imported because:\n%4")
+ .arg(import->uri).arg(import->version.majorVersion())
+ .arg(import->version.hasMinorVersion()
+ ? QString::number(import->version.minorVersion())
+ : QLatin1String("x"))
+ .arg(reason));
+ } else {
+ error.setDescription(QQmlImportDatabase::tr("module \"%1\" cannot be imported because:\n%2")
+ .arg(import->uri, reason));
+ }
+ errors->prepend(error);
+}
+bool QQmlTypeLoader::Blob::addLibraryImport(const QQmlTypeLoader::Blob::PendingImportPtr &import, QList<QQmlError> *errors)
+{
QQmlImportDatabase *importDatabase = typeLoader()->importDatabase();
- if (import->type == QV4::CompiledData::Import::ImportScript) {
- QUrl scriptUrl = finalUrl().resolved(QUrl(import->uri));
- QQmlRefPointer<QQmlScriptBlob> blob = typeLoader()->getScript(scriptUrl);
- addDependency(blob.data());
+ const QQmlImportDatabase::LocalQmldirSearchLocation searchMode =
+ QQmlMetaType::isStronglyLockedModule(import->uri, import->version)
+ ? QQmlImportDatabase::QmldirCacheOnly
+ : QQmlImportDatabase::QmldirFileAndCache;
+
+ const QQmlImportDatabase::LocalQmldirResult qmldirResult
+ = importDatabase->locateLocalQmldir(
+ import->uri, import->version, searchMode,
+ [&](const QString &qmldirFilePath, const QString &qmldirUrl) {
+ // This is a local library import
+ const QTypeRevision actualVersion = m_importCache->addLibraryImport(
+ typeLoader(), import->uri, import->qualifier, import->version, qmldirFilePath,
+ qmldirUrl, import->flags, import->precedence, errors);
+ if (!actualVersion.isValid())
+ return false;
- scriptImported(blob, import->location, import->qualifier, QString());
- } else if (import->type == QV4::CompiledData::Import::ImportLibrary) {
- QString qmldirFilePath;
- QString qmldirUrl;
-
- const QQmlImports::LocalQmldirResult qmldirResult = m_importCache.locateLocalQmldir(
- importDatabase, import->uri, import->version,
- &qmldirFilePath, &qmldirUrl);
- if (qmldirResult == QQmlImports::QmldirFound) {
- // This is a local library import
- const QTypeRevision actualVersion = m_importCache.addLibraryImport(
- importDatabase, import->uri, import->qualifier,
- import->version, qmldirFilePath, qmldirUrl, flags, errors);
- if (!actualVersion.isValid())
- return false;
+ // Use more specific version for dependencies if possible
+ if (actualVersion.hasMajorVersion())
+ import->version = actualVersion;
- // Use more specific version for dependencies if possible
- if (actualVersion.hasMajorVersion())
- import->version = actualVersion;
+ if (!loadImportDependencies(import, qmldirFilePath, import->flags, errors)) {
+ addDependencyImportError(import, errors);
+ return false;
+ }
- if (!loadImportDependencies(import, qmldirFilePath, errors))
- return false;
+ postProcessQmldir(this, import, qmldirFilePath, qmldirUrl);
+ return true;
+ });
- const QQmlTypeLoaderQmldirContent qmldir = typeLoader()->qmldirContent(qmldirFilePath);
- if (!import->qualifier.isEmpty()) {
- // Does this library contain any qualified scripts?
- QUrl libraryUrl(qmldirUrl);
- const auto qmldirScripts = qmldir.scripts();
- for (const QQmlDirParser::Script &script : qmldirScripts) {
- QUrl scriptUrl = libraryUrl.resolved(QUrl(script.fileName));
- QQmlRefPointer<QQmlScriptBlob> blob = typeLoader()->getScript(scriptUrl);
- addDependency(blob.data());
-
- scriptImported(blob, import->location, script.nameSpace, import->qualifier);
- }
- }
- if (!qmldir.plugins().count()) {
- // If the qmldir does not register a plugin, we might still have declaratively
- // registered types (if we are dealing with an application instead of a library)
- auto module = QQmlMetaType::typeModule(import->uri, import->version);
- // If the module already exists, the types must have been already registered
- if (!module)
- QQmlMetaType::qmlRegisterModuleTypes(import->uri);
- }
- } else if (
- // Major version of module already registered:
- // We believe that the registration is complete.
- QQmlMetaType::typeModule(import->uri, import->version)
-
- // Otherwise, try to register further module types.
- || (qmldirResult != QQmlImports::QmldirInterceptedToRemote
- && QQmlMetaType::qmlRegisterModuleTypes(import->uri))
-
- // Otherwise, there is no way to register any further types.
- // Try with any module of that name.
- || QQmlMetaType::latestModuleVersion(import->uri).isValid()) {
-
- if (!m_importCache.addLibraryImport(
- importDatabase, import->uri, import->qualifier, import->version,
- QString(), QString(), flags, errors).isValid()) {
+ switch (qmldirResult) {
+ case QQmlImportDatabase::QmldirFound:
+ return true;
+ case QQmlImportDatabase::QmldirNotFound: {
+ if (!loadImportDependencies(import, QString(), import->flags, errors)) {
+ addDependencyImportError(import, errors);
+ return false;
+ }
+ break;
+ }
+ case QQmlImportDatabase::QmldirInterceptedToRemote:
+ break;
+ case QQmlImportDatabase::QmldirRejected:
+ return false;
+ }
+
+ // If there is a qmldir we cannot see, yet, then we have to wait.
+ // The qmldir might contain import directives.
+ if (qmldirResult != QQmlImportDatabase::QmldirInterceptedToRemote && (
+ // Major version of module already registered:
+ // We believe that the registration is complete.
+ QQmlMetaType::typeModule(import->uri, import->version)
+
+ // Otherwise, try to register further module types.
+ || QQmlMetaType::qmlRegisterModuleTypes(import->uri)
+
+ // Otherwise, there is no way to register any further types.
+ // Try with any module of that name.
+ || QQmlMetaType::latestModuleVersion(import->uri).isValid())) {
+
+ if (!m_importCache->addLibraryImport(
+ typeLoader(), import->uri, import->qualifier, import->version, QString(),
+ QString(), import->flags, import->precedence, errors).isValid()) {
+ return false;
+ }
+ } else {
+ // We haven't yet resolved this import
+ m_unresolvedImports << import;
+
+ const QQmlEngine *engine = typeLoader()->engine();
+ const bool hasInterceptors
+ = !(QQmlEnginePrivate::get(engine)->urlInterceptors.isEmpty());
+
+ // Query any network import paths for this library.
+ // Interceptor might redirect local paths.
+ QStringList remotePathList = importDatabase->importPathList(
+ hasInterceptors ? QQmlImportDatabase::LocalOrRemote
+ : QQmlImportDatabase::Remote);
+ if (!remotePathList.isEmpty()) {
+ // Add this library and request the possible locations for it
+ const QTypeRevision version = m_importCache->addLibraryImport(
+ typeLoader(), import->uri, import->qualifier, import->version, QString(),
+ QString(), import->flags | QQmlImports::ImportIncomplete, import->precedence,
+ errors);
+
+ if (!version.isValid())
return false;
- }
- } else {
- // We haven't yet resolved this import
- m_unresolvedImports << import;
-
- const QQmlEngine *engine = typeLoader()->engine();
- const bool hasInterceptors
- = !(QQmlEnginePrivate::get(engine)->urlInterceptors.isEmpty());
-
- // Query any network import paths for this library.
- // Interceptor might redirect local paths.
- QStringList remotePathList = importDatabase->importPathList(
- hasInterceptors ? QQmlImportDatabase::LocalOrRemote
- : QQmlImportDatabase::Remote);
- if (!remotePathList.isEmpty()) {
- // Add this library and request the possible locations for it
- const QTypeRevision version = m_importCache.addLibraryImport(
- importDatabase, import->uri, import->qualifier, import->version,
- QString(), QString(), flags | QQmlImports::ImportIncomplete, errors);
-
- if (!version.isValid())
- return false;
- // Use more specific version for finding the qmldir if possible
- if (version.hasMajorVersion())
- import->version = version;
-
- // Probe for all possible locations
- int priority = 0;
- const QStringList qmlDirPaths = QQmlImports::completeQmldirPaths(
- import->uri, remotePathList, import->version);
- for (const QString &qmldirPath : qmlDirPaths) {
- if (hasInterceptors) {
- QUrl url = engine->interceptUrl(
- QQmlImports::urlFromLocalFileOrQrcOrUrl(qmldirPath),
- QQmlAbstractUrlInterceptor::QmldirFile);
- if (!QQmlFile::isLocalFile(url)
- && !fetchQmldir(url, import, ++priority, errors)) {
- return false;
- }
- } else if (!fetchQmldir(QUrl(qmldirPath), import, ++priority, errors)) {
+ // Use more specific version for finding the qmldir if possible
+ if (version.hasMajorVersion())
+ import->version = version;
+
+ // Probe for all possible locations
+ int priority = 0;
+ const QStringList qmlDirPaths = QQmlImports::completeQmldirPaths(
+ import->uri, remotePathList, import->version);
+ for (const QString &qmldirPath : qmlDirPaths) {
+ if (hasInterceptors) {
+ QUrl url = engine->interceptUrl(
+ QQmlImports::urlFromLocalFileOrQrcOrUrl(qmldirPath),
+ QQmlAbstractUrlInterceptor::QmldirFile);
+ if (!QQmlFile::isLocalFile(url)
+ && !fetchQmldir(url, import, ++priority, errors)) {
return false;
}
-
+ } else if (!fetchQmldir(QUrl(qmldirPath), import, ++priority, errors)) {
+ return false;
}
+
}
}
- } else {
- Q_ASSERT(import->type == QV4::CompiledData::Import::ImportFile);
-
- bool incomplete = false;
-
- QUrl importUrl(import->uri);
- QString path = importUrl.path();
- path.append(QLatin1String(path.endsWith(QLatin1Char('/')) ? "qmldir" : "/qmldir"));
- importUrl.setPath(path);
- QUrl qmldirUrl = finalUrl().resolved(importUrl);
- if (!QQmlImports::isLocal(qmldirUrl)) {
- // This is a remote file; the import is currently incomplete
- incomplete = true;
- }
+ }
- const QTypeRevision version = m_importCache.addFileImport(
- importDatabase, import->uri, import->qualifier, import->version, incomplete,
- errors);
- if (!version.isValid())
- return false;
+ return true;
+}
- // Use more specific version for the qmldir if possible
- if (version.hasMajorVersion())
- import->version = version;
+bool QQmlTypeLoader::Blob::addImport(const QV4::CompiledData::Import *import,
+ QQmlImports::ImportFlags flags, QList<QQmlError> *errors)
+{
+ return addImport(std::make_shared<PendingImport>(this, import, flags), errors);
+}
- if (incomplete) {
- if (!fetchQmldir(qmldirUrl, import, 1, errors))
- return false;
- }
+bool QQmlTypeLoader::Blob::addImport(
+ QQmlTypeLoader::Blob::PendingImportPtr import, QList<QQmlError> *errors)
+{
+ Q_ASSERT(errors);
+
+ switch (import->type)
+ {
+ case QV4::CompiledData::Import::ImportLibrary:
+ return addLibraryImport(import, errors);
+ case QV4::CompiledData::Import::ImportFile:
+ return addFileImport(import ,errors);
+ case QV4::CompiledData::Import::ImportScript:
+ return addScriptImport(import);
+ case QV4::CompiledData::Import::ImportInlineComponent:
+ Q_UNREACHABLE_RETURN(false); // addImport is never called with an inline component import
}
- return true;
+ Q_UNREACHABLE_RETURN(false);
}
void QQmlTypeLoader::Blob::dependencyComplete(QQmlDataBlob *blob)
{
if (blob->type() == QQmlDataBlob::QmldirFile) {
QQmlQmldirData *data = static_cast<QQmlQmldirData *>(blob);
-
- PendingImportPtr import = data->import(this);
-
QList<QQmlError> errors;
if (!qmldirDataAvailable(data, &errors)) {
Q_ASSERT(errors.size());
QQmlError error(errors.takeFirst());
- error.setUrl(m_importCache.baseUrl());
- error.setLine(qmlConvertSourceCoordinate<quint32, int>(import->location.line));
- error.setColumn(qmlConvertSourceCoordinate<quint32, int>(import->location.column));
+ error.setUrl(m_importCache->baseUrl());
+ const QV4::CompiledData::Location importLocation = data->importLocation(this);
+ error.setLine(qmlConvertSourceCoordinate<quint32, int>(importLocation.line()));
+ error.setColumn(qmlConvertSourceCoordinate<quint32, int>(importLocation.column()));
errors.prepend(error); // put it back on the list after filling out information.
setError(errors);
}
}
}
-bool QQmlTypeLoader::Blob::loadImportDependencies(PendingImportPtr currentImport, const QString &qmldirUri, QList<QQmlError> *errors)
+bool QQmlTypeLoader::Blob::loadDependentImports(
+ const QList<QQmlDirParser::Import> &imports, const QString &qualifier,
+ QTypeRevision version, quint16 precedence, QQmlImports::ImportFlags flags,
+ QList<QQmlError> *errors)
{
- const QQmlTypeLoaderQmldirContent qmldir = typeLoader()->qmldirContent(qmldirUri);
- const QList<QQmlDirParser::Import> implicitImports
- = QQmlMetaType::moduleImports(currentImport->uri, currentImport->version)
- + qmldir.imports();
- for (const auto &implicitImport : implicitImports) {
- if (implicitImport.flags & QQmlDirParser::Import::Optional)
+ for (const auto &import : imports) {
+ if (import.flags & QQmlDirParser::Import::Optional)
continue;
auto dependencyImport = std::make_shared<PendingImport>();
- dependencyImport->uri = implicitImport.module;
- dependencyImport->qualifier = currentImport->qualifier;
- dependencyImport->version = (implicitImport.flags & QQmlDirParser::Import::Auto)
- ? currentImport->version : implicitImport.version;
- if (!addImport(dependencyImport, QQmlImports::ImportLowPrecedence, errors)) {
+ dependencyImport->uri = import.module;
+ dependencyImport->qualifier = qualifier;
+ dependencyImport->version = (import.flags & QQmlDirParser::Import::Auto)
+ ? version : import.version;
+ dependencyImport->flags = flags;
+ dependencyImport->precedence = precedence;
+
+ qCDebug(lcQmlImport)
+ << "loading dependent import" << dependencyImport->uri << "version"
+ << dependencyImport->version << "as" << dependencyImport->qualifier;
+
+ if (!addImport(dependencyImport, errors)) {
QQmlError error;
error.setDescription(
QString::fromLatin1(
- "Failed to load dependencies for module \"%1\" version %2.%3")
- .arg(currentImport->uri)
- .arg(currentImport->version.majorVersion())
- .arg(currentImport->version.minorVersion()));
+ "Failed to load dependent import \"%1\" version %2.%3")
+ .arg(dependencyImport->uri)
+ .arg(dependencyImport->version.majorVersion())
+ .arg(dependencyImport->version.minorVersion()));
errors->append(error);
return false;
}
@@ -771,40 +823,82 @@ bool QQmlTypeLoader::Blob::loadImportDependencies(PendingImportPtr currentImport
return true;
}
+bool QQmlTypeLoader::Blob::loadImportDependencies(
+ const QQmlTypeLoader::Blob::PendingImportPtr &currentImport, const QString &qmldirUri,
+ QQmlImports::ImportFlags flags, QList<QQmlError> *errors)
+{
+ QList<QQmlDirParser::Import> implicitImports
+ = QQmlMetaType::moduleImports(currentImport->uri, currentImport->version);
+ if (!qmldirUri.isEmpty())
+ implicitImports += typeLoader()->qmldirContent(qmldirUri).imports();
+
+ // Prevent overflow from one category of import into the other.
+ switch (currentImport->precedence) {
+ case QQmlImportInstance::Implicit - 1:
+ case QQmlImportInstance::Lowest: {
+ QQmlError error;
+ error.setDescription(
+ QString::fromLatin1("Too many dependent imports for %1 %2.%3")
+ .arg(currentImport->uri)
+ .arg(currentImport->version.majorVersion())
+ .arg(currentImport->version.minorVersion()));
+ errors->append(error);
+ return false;
+ }
+ default:
+ break;
+ }
+
+ if (!loadDependentImports(
+ implicitImports, currentImport->qualifier, currentImport->version,
+ currentImport->precedence + 1, flags, errors)) {
+ QQmlError error;
+ error.setDescription(
+ QString::fromLatin1(
+ "Failed to load dependencies for module \"%1\" version %2.%3")
+ .arg(currentImport->uri)
+ .arg(currentImport->version.majorVersion())
+ .arg(currentImport->version.minorVersion()));
+ errors->append(error);
+ return false;
+ }
+
+ return true;
+}
+
bool QQmlTypeLoader::Blob::isDebugging() const
{
return typeLoader()->engine()->handle()->debugger() != nullptr;
}
-bool QQmlTypeLoader::Blob::diskCacheEnabled() const
+bool QQmlTypeLoader::Blob::readCacheFile() const
{
- return typeLoader()->engine()->handle()->diskCacheEnabled();
+ return typeLoader()->engine()->handle()->diskCacheOptions()
+ & QV4::ExecutionEngine::DiskCache::QmlcRead;
}
-bool QQmlTypeLoader::Blob::qmldirDataAvailable(const QQmlRefPointer<QQmlQmldirData> &data, QList<QQmlError> *errors)
+bool QQmlTypeLoader::Blob::writeCacheFile() const
{
- PendingImportPtr import = data->import(this);
- data->setImport(this, nullptr);
-
- int priority = data->priority(this);
- data->setPriority(this, 0);
-
- if (import) {
- // Do we need to resolve this import?
- const bool resolve = (import->priority == 0) || (import->priority > priority);
-
- if (resolve) {
- // This is the (current) best resolution for this import
- if (!updateQmldir(data, import, errors)) {
- return false;
- }
+ return typeLoader()->engine()->handle()->diskCacheOptions()
+ & QV4::ExecutionEngine::DiskCache::QmlcWrite;
+}
- import->priority = priority;
- return true;
- }
- }
+QQmlMetaType::CacheMode QQmlTypeLoader::Blob::aotCacheMode() const
+{
+ const QV4::ExecutionEngine::DiskCacheOptions options
+ = typeLoader()->engine()->handle()->diskCacheOptions();
+ if (!(options & QV4::ExecutionEngine::DiskCache::Aot))
+ return QQmlMetaType::RejectAll;
+ if (options & QV4::ExecutionEngine::DiskCache::AotByteCode)
+ return QQmlMetaType::AcceptUntyped;
+ return QQmlMetaType::RequireFullyTyped;
+}
- return true;
+bool QQmlTypeLoader::Blob::qmldirDataAvailable(const QQmlRefPointer<QQmlQmldirData> &data, QList<QQmlError> *errors)
+{
+ return data->processImports(this, [&](PendingImportPtr import) {
+ return updateQmldir(data, import, errors);
+ });
}
/*!
@@ -870,8 +964,9 @@ QQmlRefPointer<QQmlTypeData> QQmlTypeLoader::getType(const QUrl &unNormalizedUrl
m_typeCache.insert(url, typeData);
QQmlMetaType::CachedUnitLookupError error = QQmlMetaType::CachedUnitLookupError::NoError;
- if (const QQmlPrivate::CachedQmlUnit *cachedUnit = typeData->diskCacheEnabled()
- ? QQmlMetaType::findCachedCompilationUnit(typeData->url(), &error)
+ const QQmlMetaType::CacheMode cacheMode = typeData->aotCacheMode();
+ if (const QQmlPrivate::CachedQmlUnit *cachedUnit = (cacheMode != QQmlMetaType::RejectAll)
+ ? QQmlMetaType::findCachedCompilationUnit(typeData->url(), cacheMode, &error)
: nullptr) {
QQmlTypeLoader::loadWithCachedUnit(typeData, cachedUnit, mode);
} else {
@@ -882,16 +977,16 @@ QQmlRefPointer<QQmlTypeData> QQmlTypeLoader::getType(const QUrl &unNormalizedUrl
// this was started Asynchronous, but we need to force Synchronous
// completion now (if at all possible with this type of URL).
+#if QT_CONFIG(thread)
if (!m_thread->isThisThread()) {
// this only works when called directly from the UI thread, but not
// when recursively called on the QML thread via resolveTypes()
while (!typeData->isCompleteOrError()) {
- unlock();
m_thread->waitForNextMessage();
- lock();
}
}
+#endif
}
return typeData;
@@ -911,6 +1006,26 @@ QQmlRefPointer<QQmlTypeData> QQmlTypeLoader::getType(const QByteArray &data, con
return QQmlRefPointer<QQmlTypeData>(typeData, QQmlRefPointer<QQmlTypeData>::Adopt);
}
+void QQmlTypeLoader::injectScript(const QUrl &relativeUrl, const QV4::Value &value)
+{
+ LockHolder<QQmlTypeLoader> holder(this);
+
+ QQmlScriptBlob *blob = new QQmlScriptBlob(relativeUrl, this);
+ blob->initializeFromNative(value);
+ blob->m_isDone = true;
+ blob->m_data.setStatus(QQmlDataBlob::Complete);
+ m_scriptCache.insert(relativeUrl, blob);
+}
+
+QQmlRefPointer<QQmlScriptBlob> QQmlTypeLoader::injectedScript(const QUrl &relativeUrl)
+{
+ LockHolder<QQmlTypeLoader> holder(this);
+ const auto it = m_scriptCache.constFind(relativeUrl);
+ return (it != m_scriptCache.constEnd() && (*it)->isNative())
+ ? *it
+ : QQmlRefPointer<QQmlScriptBlob>();
+}
+
/*!
Return a QQmlScriptBlob for \a url. The QQmlScriptData may be cached.
*/
@@ -931,8 +1046,9 @@ QQmlRefPointer<QQmlScriptBlob> QQmlTypeLoader::getScript(const QUrl &unNormalize
m_scriptCache.insert(url, scriptBlob);
QQmlMetaType::CachedUnitLookupError error = QQmlMetaType::CachedUnitLookupError::NoError;
- if (const QQmlPrivate::CachedQmlUnit *cachedUnit = scriptBlob->diskCacheEnabled()
- ? QQmlMetaType::findCachedCompilationUnit(scriptBlob->url(), &error)
+ const QQmlMetaType::CacheMode cacheMode = scriptBlob->aotCacheMode();
+ if (const QQmlPrivate::CachedQmlUnit *cachedUnit = (cacheMode != QQmlMetaType::RejectAll)
+ ? QQmlMetaType::findCachedCompilationUnit(scriptBlob->url(), cacheMode, &error)
: nullptr) {
QQmlTypeLoader::loadWithCachedUnit(scriptBlob, cachedUnit);
} else {
@@ -982,19 +1098,19 @@ QString QQmlTypeLoader::absoluteFilePath(const QString &path)
// qrc resource
QFileInfo fileInfo(path);
return fileInfo.isFile() ? fileInfo.absoluteFilePath() : QString();
- } else if (path.count() > 3 && path.at(3) == QLatin1Char(':') &&
+ } else if (path.size() > 3 && path.at(3) == QLatin1Char(':') &&
path.startsWith(QLatin1String("qrc"), Qt::CaseInsensitive)) {
// qrc resource url
QFileInfo fileInfo(QQmlFile::urlToLocalFileOrQrc(path));
return fileInfo.isFile() ? fileInfo.absoluteFilePath() : QString();
}
#if defined(Q_OS_ANDROID)
- else if (path.count() > 7 && path.at(6) == QLatin1Char(':') && path.at(7) == QLatin1Char('/') &&
+ else if (path.size() > 7 && path.at(6) == QLatin1Char(':') && path.at(7) == QLatin1Char('/') &&
path.startsWith(QLatin1String("assets"), Qt::CaseInsensitive)) {
// assets resource url
QFileInfo fileInfo(QQmlFile::urlToLocalFileOrQrc(path));
return fileInfo.isFile() ? fileInfo.absoluteFilePath() : QString();
- } else if (path.count() > 8 && path.at(7) == QLatin1Char(':') && path.at(8) == QLatin1Char('/') &&
+ } else if (path.size() > 8 && path.at(7) == QLatin1Char(':') && path.at(8) == QLatin1Char('/') &&
path.startsWith(QLatin1String("content"), Qt::CaseInsensitive)) {
// content url
QFileInfo fileInfo(QQmlFile::urlToLocalFileOrQrc(path));
@@ -1016,7 +1132,7 @@ QString QQmlTypeLoader::absoluteFilePath(const QString &path)
return QString();
QString absoluteFilePath;
- QString fileName(path.mid(lastSlash+1, path.length()-lastSlash-1));
+ QString fileName(path.mid(lastSlash+1, path.size()-lastSlash-1));
bool *value = fileSet->object(fileName);
if (value) {
@@ -1029,7 +1145,7 @@ QString QQmlTypeLoader::absoluteFilePath(const QString &path)
absoluteFilePath = path;
}
- if (absoluteFilePath.length() > 2 && absoluteFilePath.at(0) != QLatin1Char('/') && absoluteFilePath.at(1) != QLatin1Char(':'))
+ if (absoluteFilePath.size() > 2 && absoluteFilePath.at(0) != QLatin1Char('/') && absoluteFilePath.at(1) != QLatin1Char(':'))
absoluteFilePath = QFileInfo(absoluteFilePath).absoluteFilePath();
return absoluteFilePath;
@@ -1071,20 +1187,20 @@ bool QQmlTypeLoader::fileExists(const QString &path, const QString &file)
return addToCache(QFileInfo(path + file));
}
- if (path.count() > 3 && path.at(3) == QLatin1Char(':')
+ if (path.size() > 3 && path.at(3) == QLatin1Char(':')
&& path.startsWith(QLatin1String("qrc"), Qt::CaseInsensitive)) {
// qrc resource url
return addToCache(QFileInfo(QQmlFile::urlToLocalFileOrQrc(path + file)));
}
#if defined(Q_OS_ANDROID)
- if (path.count() > 7 && path.at(6) == QLatin1Char(':') && path.at(7) == QLatin1Char('/')
+ if (path.size() > 7 && path.at(6) == QLatin1Char(':') && path.at(7) == QLatin1Char('/')
&& path.startsWith(QLatin1String("assets"), Qt::CaseInsensitive)) {
// assets resource url
return addToCache(QFileInfo(QQmlFile::urlToLocalFileOrQrc(path + file)));
}
- if (path.count() > 8 && path.at(7) == QLatin1Char(':') && path.at(8) == QLatin1Char('/')
+ if (path.size() > 8 && path.at(7) == QLatin1Char(':') && path.at(8) == QLatin1Char('/')
&& path.startsWith(QLatin1String("content"), Qt::CaseInsensitive)) {
// content url
return addToCache(QFileInfo(QQmlFile::urlToLocalFileOrQrc(path + file)));
@@ -1115,7 +1231,7 @@ bool QQmlTypeLoader::directoryExists(const QString &path)
return fileInfo.exists() && fileInfo.isDir();
}
- int length = path.length();
+ int length = path.size();
if (path.endsWith(QLatin1Char('/')))
--length;
QString dirPath(path.left(length));
@@ -1152,7 +1268,7 @@ const QQmlTypeLoaderQmldirContent QQmlTypeLoader::qmldirContent(const QString &f
// Yet, this heuristic is the best we can do until we pass more structured information here,
// for example a QUrl also for local files.
QUrl url(filePathIn);
- if (url.scheme().length() < 2) {
+ if (url.scheme().size() < 2) {
filePath = filePathIn;
} else {
filePath = QQmlFile::urlToLocalFileOrQrc(url);
@@ -1212,6 +1328,11 @@ and qmldir information.
*/
void QQmlTypeLoader::clearCache()
{
+ // Pending messages typically hold references to the blobs they want to be delivered to.
+ // We don't want them anymore.
+ if (m_thread)
+ m_thread->discardMessages();
+
for (TypeCache::Iterator iter = m_typeCache.begin(), end = m_typeCache.end(); iter != end; ++iter)
(*iter)->release();
for (ScriptCache::Iterator iter = m_scriptCache.begin(), end = m_scriptCache.end(); iter != end; ++iter)
@@ -1227,7 +1348,7 @@ void QQmlTypeLoader::clearCache()
m_qmldirCache.clear();
m_importDirCache.clear();
m_importQmlDirCache.clear();
- QQmlMetaType::freeUnusedTypesAndCaches();
+ m_checksumCache.clear();
}
void QQmlTypeLoader::updateTypeCacheTrimThreshold()
@@ -1249,15 +1370,29 @@ void QQmlTypeLoader::trimCache()
// typeData->m_compiledData may be set early on in the proccess of loading a file, so
// it's important to check the general loading status of the typeData before making any
// other decisions.
- if (typeData->count() == 1 && (typeData->isError() || typeData->isComplete())
- && (!typeData->m_compiledData || typeData->m_compiledData->count() == 1)) {
- // There are no live objects of this type
- iter.value()->release();
- iter = m_typeCache.erase(iter);
- deletedOneType = true;
- } else {
+ if (typeData->count() != 1 || (!typeData->isError() && !typeData->isComplete())) {
++iter;
+ continue;
+ }
+
+ const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &compilationUnit
+ = typeData->m_compiledData;
+ if (compilationUnit) {
+ if (compilationUnit->count()
+ > QQmlMetaType::countInternalCompositeTypeSelfReferences(
+ compilationUnit) + 1) {
+ ++iter;
+ continue;
+ }
+
+ QQmlMetaType::unregisterInternalCompositeType(compilationUnit);
+ Q_ASSERT(compilationUnit->count() == 1);
}
+
+ // There are no live objects of this type
+ iter.value()->release();
+ iter = m_typeCache.erase(iter);
+ deletedOneType = true;
}
if (!deletedOneType)
diff --git a/src/qml/qml/qqmltypeloader_p.h b/src/qml/qml/qqmltypeloader_p.h
index eb6e549911..e9c4559527 100644
--- a/src/qml/qml/qqmltypeloader_p.h
+++ b/src/qml/qml/qqmltypeloader_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLTYPELOADER_P_H
#define QQMLTYPELOADER_P_H
@@ -54,6 +18,7 @@
#include <private/qqmldatablob_p.h>
#include <private/qqmlimport_p.h>
#include <private/qqmlmetatype_p.h>
+#include <private/qv4compileddata_p.h>
#include <QtQml/qtqmlglobal.h>
#include <QtQml/qqmlerror.h>
@@ -74,64 +39,82 @@ class QQmlProfiler;
class QQmlTypeLoaderThread;
class QQmlEngine;
-class Q_QML_PRIVATE_EXPORT QQmlTypeLoader
+class Q_QML_EXPORT QQmlTypeLoader
{
Q_DECLARE_TR_FUNCTIONS(QQmlTypeLoader)
public:
+ using ChecksumCache = QHash<quintptr, QByteArray>;
enum Mode { PreferSynchronous, Asynchronous, Synchronous };
- class Q_QML_PRIVATE_EXPORT Blob : public QQmlDataBlob
+ class Q_QML_EXPORT Blob : public QQmlDataBlob
{
public:
Blob(const QUrl &url, QQmlDataBlob::Type type, QQmlTypeLoader *loader);
~Blob() override;
- const QQmlImports &imports() const { return m_importCache; }
+ const QQmlImports *imports() const { return m_importCache.data(); }
void setCachedUnitStatus(QQmlMetaType::CachedUnitLookupError status) { m_cachedUnitStatus = status; }
struct PendingImport
{
- QV4::CompiledData::Import::ImportType type = QV4::CompiledData::Import::ImportType::ImportLibrary;
-
QString uri;
QString qualifier;
- QTypeRevision version;
-
+ QV4::CompiledData::Import::ImportType type
+ = QV4::CompiledData::Import::ImportType::ImportLibrary;
QV4::CompiledData::Location location;
+ QQmlImports::ImportFlags flags;
+ quint8 precedence = 0;
int priority = 0;
+ QTypeRevision version;
+
PendingImport() = default;
- PendingImport(Blob *blob, const QV4::CompiledData::Import *import);
+ PendingImport(Blob *blob, const QV4::CompiledData::Import *import,
+ QQmlImports::ImportFlags flags);
};
using PendingImportPtr = std::shared_ptr<PendingImport>;
+ void importQmldirScripts(const PendingImportPtr &import, const QQmlTypeLoaderQmldirContent &qmldir, const QUrl &qmldirUrl);
+
protected:
- bool addImport(const QV4::CompiledData::Import *import, uint flags,
+ bool addImport(const QV4::CompiledData::Import *import, QQmlImports::ImportFlags,
QList<QQmlError> *errors);
- bool addImport(PendingImportPtr import, uint flags, QList<QQmlError> *errors);
+ bool addImport(PendingImportPtr import, QList<QQmlError> *errors);
bool fetchQmldir(const QUrl &url, PendingImportPtr import, int priority, QList<QQmlError> *errors);
- bool updateQmldir(const QQmlRefPointer<QQmlQmldirData> &data, PendingImportPtr import, QList<QQmlError> *errors);
+ bool updateQmldir(const QQmlRefPointer<QQmlQmldirData> &data, const PendingImportPtr &import, QList<QQmlError> *errors);
private:
+ bool addScriptImport(const PendingImportPtr &import);
+ bool addFileImport(const PendingImportPtr &import, QList<QQmlError> *errors);
+ bool addLibraryImport(const PendingImportPtr &import, QList<QQmlError> *errors);
+
virtual bool qmldirDataAvailable(const QQmlRefPointer<QQmlQmldirData> &, QList<QQmlError> *);
virtual void scriptImported(const QQmlRefPointer<QQmlScriptBlob> &, const QV4::CompiledData::Location &, const QString &, const QString &) {}
void dependencyComplete(QQmlDataBlob *) override;
- bool loadImportDependencies(PendingImportPtr currentImport, const QString &qmldirUri, QList<QQmlError> *errors);
+ bool loadImportDependencies(
+ const PendingImportPtr &currentImport, const QString &qmldirUri,
+ QQmlImports::ImportFlags flags, QList<QQmlError> *errors);
protected:
+ bool loadDependentImports(
+ const QList<QQmlDirParser::Import> &imports, const QString &qualifier,
+ QTypeRevision version, quint16 precedence, QQmlImports::ImportFlags flags,
+ QList<QQmlError> *errors);
virtual QString stringAt(int) const { return QString(); }
bool isDebugging() const;
- bool diskCacheEnabled() const;
+ bool readCacheFile() const;
+ bool writeCacheFile() const;
+ QQmlMetaType::CacheMode aotCacheMode() const;
- QQmlImports m_importCache;
+ QQmlRefPointer<QQmlImports> m_importCache;
QVector<PendingImportPtr> m_unresolvedImports;
QVector<QQmlRefPointer<QQmlQmldirData>> m_qmldirs;
QQmlMetaType::CachedUnitLookupError m_cachedUnitStatus = QQmlMetaType::CachedUnitLookupError::NoError;
@@ -140,13 +123,35 @@ public:
QQmlTypeLoader(QQmlEngine *);
~QQmlTypeLoader();
+ template<
+ typename Engine,
+ typename EnginePrivate = QQmlEnginePrivate,
+ typename = std::enable_if_t<std::is_same_v<Engine, QQmlEngine>>>
+ static QQmlTypeLoader *get(Engine *engine)
+ {
+ return get(EnginePrivate::get(engine));
+ }
+
+ template<
+ typename Engine,
+ typename = std::enable_if_t<std::is_same_v<Engine, QQmlEnginePrivate>>>
+ static QQmlTypeLoader *get(Engine *engine)
+ {
+ return &engine->typeLoader;
+ }
+
QQmlImportDatabase *importDatabase() const;
+ ChecksumCache *checksumCache() { return &m_checksumCache; }
+ const ChecksumCache *checksumCache() const { return &m_checksumCache; }
static QUrl normalize(const QUrl &unNormalizedUrl);
QQmlRefPointer<QQmlTypeData> getType(const QUrl &unNormalizedUrl, Mode mode = PreferSynchronous);
QQmlRefPointer<QQmlTypeData> getType(const QByteArray &, const QUrl &url, Mode mode = PreferSynchronous);
+ void injectScript(const QUrl &relativeUrl, const QV4::Value &value);
+ QQmlRefPointer<QQmlScriptBlob> injectedScript(const QUrl &relativeUrl);
+
QQmlRefPointer<QQmlScriptBlob> getScript(const QUrl &unNormalizedUrl);
QQmlRefPointer<QQmlQmldirData> getQmldir(const QUrl &);
@@ -193,36 +198,20 @@ private:
void shutdownThread();
- void loadThread(QQmlDataBlob *);
- void loadWithStaticDataThread(QQmlDataBlob *, const QByteArray &);
- void loadWithCachedUnitThread(QQmlDataBlob *blob, const QQmlPrivate::CachedQmlUnit *unit);
+ void loadThread(const QQmlDataBlob::Ptr &);
+ void loadWithStaticDataThread(const QQmlDataBlob::Ptr &, const QByteArray &);
+ void loadWithCachedUnitThread(const QQmlDataBlob::Ptr &blob, const QQmlPrivate::CachedQmlUnit *unit);
#if QT_CONFIG(qml_network)
void networkReplyFinished(QNetworkReply *);
void networkReplyProgress(QNetworkReply *, qint64, qint64);
- typedef QHash<QNetworkReply *, QQmlDataBlob *> NetworkReplies;
+ typedef QHash<QNetworkReply *, QQmlDataBlob::Ptr> NetworkReplies;
#endif
- void setData(QQmlDataBlob *, const QByteArray &);
- void setData(QQmlDataBlob *, const QString &fileName);
- void setData(QQmlDataBlob *, const QQmlDataBlob::SourceCodeData &);
- void setCachedUnit(QQmlDataBlob *blob, const QQmlPrivate::CachedQmlUnit *unit);
-
- template<typename T>
- struct TypedCallback
- {
- TypedCallback(T *object, void (T::*func)(QQmlTypeData *)) : o(object), mf(func) {}
-
- static void redirect(void *arg, QQmlTypeData *type)
- {
- TypedCallback<T> *self = reinterpret_cast<TypedCallback<T> *>(arg);
- ((self->o)->*(self->mf))(type);
- }
-
- private:
- T *o;
- void (T::*mf)(QQmlTypeData *);
- };
+ void setData(const QQmlDataBlob::Ptr &, const QByteArray &);
+ void setData(const QQmlDataBlob::Ptr &, const QString &fileName);
+ void setData(const QQmlDataBlob::Ptr &, const QQmlDataBlob::SourceCodeData &);
+ void setCachedUnit(const QQmlDataBlob::Ptr &blob, const QQmlPrivate::CachedQmlUnit *unit);
typedef QHash<QUrl, QQmlTypeData *> TypeCache;
typedef QHash<QUrl, QQmlScriptBlob *> ScriptCache;
@@ -247,6 +236,7 @@ private:
QmldirCache m_qmldirCache;
ImportDirCache m_importDirCache;
ImportQmlDirCache m_importQmlDirCache;
+ ChecksumCache m_checksumCache;
template<typename Loader>
void doLoad(const Loader &loader, QQmlDataBlob *blob, Mode mode);
diff --git a/src/qml/qml/qqmltypeloadernetworkreplyproxy.cpp b/src/qml/qml/qqmltypeloadernetworkreplyproxy.cpp
index af97643163..cea7ae6650 100644
--- a/src/qml/qml/qqmltypeloadernetworkreplyproxy.cpp
+++ b/src/qml/qml/qqmltypeloadernetworkreplyproxy.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 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$
-**
-****************************************************************************/
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <private/qqmltypeloadernetworkreplyproxy_p.h>
#include <private/qqmltypeloader_p.h>
@@ -72,3 +36,5 @@ void QQmlTypeLoaderNetworkReplyProxy::manualFinished(QNetworkReply *reply)
}
QT_END_NAMESPACE
+
+#include "moc_qqmltypeloadernetworkreplyproxy_p.cpp"
diff --git a/src/qml/qml/qqmltypeloadernetworkreplyproxy_p.h b/src/qml/qml/qqmltypeloadernetworkreplyproxy_p.h
index ed87a2b508..47e59b4bba 100644
--- a/src/qml/qml/qqmltypeloadernetworkreplyproxy_p.h
+++ b/src/qml/qml/qqmltypeloadernetworkreplyproxy_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 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$
-**
-****************************************************************************/
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLTYPELOADERNETWORKREPLYPROXY_P_H
#define QQMLTYPELOADERNETWORKREPLYPROXY_P_H
@@ -53,6 +17,7 @@
#include <QtQml/qtqmlglobal.h>
#include <QtCore/qobject.h>
+#include <QtCore/private/qglobal_p.h>
QT_REQUIRE_CONFIG(qml_network);
@@ -72,7 +37,7 @@ class QQmlTypeLoaderNetworkReplyProxy : public QObject
public:
QQmlTypeLoaderNetworkReplyProxy(QQmlTypeLoader *l);
-public slots:
+public Q_SLOTS:
void finished();
void downloadProgress(qint64, qint64);
void manualFinished(QNetworkReply*);
diff --git a/src/qml/qml/qqmltypeloaderqmldircontent.cpp b/src/qml/qml/qqmltypeloaderqmldircontent.cpp
index 6365d0900c..5744cf2bb7 100644
--- a/src/qml/qml/qqmltypeloaderqmldircontent.cpp
+++ b/src/qml/qml/qqmltypeloaderqmldircontent.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 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$
-**
-****************************************************************************/
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <private/qqmltypeloaderqmldircontent_p.h>
#include <private/qqmlsourcecoordinate_p.h>
@@ -43,10 +7,9 @@
QT_BEGIN_NAMESPACE
-QList<QQmlError> QQmlTypeLoaderQmldirContent::errors(const QString &uri) const
+QList<QQmlError> QQmlTypeLoaderQmldirContent::errors(const QString &uri, const QUrl &url) const
{
QList<QQmlError> errors;
- const QUrl url(uri);
const auto parseErrors = m_parser.errors(uri);
for (const auto &parseError : parseErrors) {
QQmlError error;
@@ -65,6 +28,7 @@ void QQmlTypeLoaderQmldirContent::setContent(const QString &location, const QStr
m_hasContent = true;
m_location = location;
m_parser.parse(content);
+ m_parser.disambiguateFileSelectors();
}
void QQmlTypeLoaderQmldirContent::setError(const QQmlError &error)
diff --git a/src/qml/qml/qqmltypeloaderqmldircontent_p.h b/src/qml/qml/qqmltypeloaderqmldircontent_p.h
index 55cd846925..421eb16da4 100644
--- a/src/qml/qml/qqmltypeloaderqmldircontent_p.h
+++ b/src/qml/qml/qqmltypeloaderqmldircontent_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 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$
-**
-****************************************************************************/
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLTYPELOADERQMLDIRCONTENT_P_H
#define QQMLTYPELOADERQMLDIRCONTENT_P_H
@@ -71,7 +35,7 @@ public:
bool hasContent() const { return m_hasContent; }
bool hasError() const { return m_parser.hasError(); }
- QList<QQmlError> errors(const QString &uri) const;
+ QList<QQmlError> errors(const QString &uri, const QUrl &url) const;
QString typeNamespace() const { return m_parser.typeNamespace(); }
@@ -83,7 +47,15 @@ public:
QString qmldirLocation() const { return m_location; }
QString preferredPath() const { return m_parser.preferredPath(); }
+ bool hasRedirection() const
+ {
+ const QString preferred = preferredPath();
+ return !preferred.isEmpty()
+ && preferred != QStringView(m_location).chopped(strlen("qmldir"));
+ }
+
bool designerSupported() const { return m_parser.designerSupported(); }
+ bool hasTypeInfo() const { return !m_parser.typeInfos().isEmpty(); }
private:
QQmlDirParser m_parser;
diff --git a/src/qml/qml/qqmltypeloaderthread.cpp b/src/qml/qml/qqmltypeloaderthread.cpp
index bb7a6aacb2..18d1dbe7ce 100644
--- a/src/qml/qml/qqmltypeloaderthread.cpp
+++ b/src/qml/qml/qqmltypeloaderthread.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 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$
-**
-****************************************************************************/
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <private/qqmlengine_p.h>
#include <private/qqmlextensionplugin_p.h>
@@ -49,9 +13,6 @@ QT_BEGIN_NAMESPACE
QQmlTypeLoaderThread::QQmlTypeLoaderThread(QQmlTypeLoader *loader)
: m_loader(loader)
-#if QT_CONFIG(qml_network)
- , m_networkAccessManager(nullptr), m_networkReplyProxy(nullptr)
-#endif // qml_network
{
// Do that after initializing all the members.
startup();
@@ -63,7 +24,9 @@ QNetworkAccessManager *QQmlTypeLoaderThread::networkAccessManager() const
Q_ASSERT(isThisThread());
if (!m_networkAccessManager) {
m_networkAccessManager = QQmlEnginePrivate::get(m_loader->engine())->createNetworkAccessManager(nullptr);
+ QObject::connect(thread(), &QThread::finished, m_networkAccessManager, &QObject::deleteLater);
m_networkReplyProxy = new QQmlTypeLoaderNetworkReplyProxy(m_loader);
+ QObject::connect(thread(), &QThread::finished, m_networkReplyProxy, &QObject::deleteLater);
}
return m_networkAccessManager;
@@ -77,62 +40,44 @@ QQmlTypeLoaderNetworkReplyProxy *QQmlTypeLoaderThread::networkReplyProxy() const
}
#endif // qml_network
-void QQmlTypeLoaderThread::load(QQmlDataBlob *b)
+void QQmlTypeLoaderThread::load(const QQmlDataBlob::Ptr &b)
{
- b->addref();
callMethodInThread(&This::loadThread, b);
}
-void QQmlTypeLoaderThread::loadAsync(QQmlDataBlob *b)
+void QQmlTypeLoaderThread::loadAsync(const QQmlDataBlob::Ptr &b)
{
- b->addref();
postMethodToThread(&This::loadThread, b);
}
-void QQmlTypeLoaderThread::loadWithStaticData(QQmlDataBlob *b, const QByteArray &d)
+void QQmlTypeLoaderThread::loadWithStaticData(const QQmlDataBlob::Ptr &b, const QByteArray &d)
{
- b->addref();
callMethodInThread(&This::loadWithStaticDataThread, b, d);
}
-void QQmlTypeLoaderThread::loadWithStaticDataAsync(QQmlDataBlob *b, const QByteArray &d)
+void QQmlTypeLoaderThread::loadWithStaticDataAsync(const QQmlDataBlob::Ptr &b, const QByteArray &d)
{
- b->addref();
postMethodToThread(&This::loadWithStaticDataThread, b, d);
}
-void QQmlTypeLoaderThread::loadWithCachedUnit(QQmlDataBlob *b, const QQmlPrivate::CachedQmlUnit *unit)
+void QQmlTypeLoaderThread::loadWithCachedUnit(const QQmlDataBlob::Ptr &b, const QQmlPrivate::CachedQmlUnit *unit)
{
- b->addref();
callMethodInThread(&This::loadWithCachedUnitThread, b, unit);
}
-void QQmlTypeLoaderThread::loadWithCachedUnitAsync(QQmlDataBlob *b, const QQmlPrivate::CachedQmlUnit *unit)
+void QQmlTypeLoaderThread::loadWithCachedUnitAsync(const QQmlDataBlob::Ptr &b, const QQmlPrivate::CachedQmlUnit *unit)
{
- b->addref();
postMethodToThread(&This::loadWithCachedUnitThread, b, unit);
}
-void QQmlTypeLoaderThread::callCompleted(QQmlDataBlob *b)
+void QQmlTypeLoaderThread::callCompleted(const QQmlDataBlob::Ptr &b)
{
- b->addref();
-#if !QT_CONFIG(thread)
- if (!isThisThread())
- postMethodToThread(&This::callCompletedMain, b);
-#else
postMethodToMain(&This::callCompletedMain, b);
-#endif
}
-void QQmlTypeLoaderThread::callDownloadProgressChanged(QQmlDataBlob *b, qreal p)
+void QQmlTypeLoaderThread::callDownloadProgressChanged(const QQmlDataBlob::Ptr &b, qreal p)
{
- b->addref();
-#if !QT_CONFIG(thread)
- if (!isThisThread())
- postMethodToThread(&This::callDownloadProgressChangedMain, b, p);
-#else
postMethodToMain(&This::callDownloadProgressChangedMain, b, p);
-#endif
}
void QQmlTypeLoaderThread::initializeEngine(QQmlExtensionInterface *iface,
@@ -147,51 +92,36 @@ void QQmlTypeLoaderThread::initializeEngine(QQmlEngineExtensionInterface *iface,
callMethodInMain(&This::initializeEngineExtensionMain, iface, uri);
}
-void QQmlTypeLoaderThread::shutdownThread()
-{
-#if QT_CONFIG(qml_network)
- delete m_networkAccessManager;
- m_networkAccessManager = nullptr;
- delete m_networkReplyProxy;
- m_networkReplyProxy = nullptr;
-#endif // qml_network
-}
-
-void QQmlTypeLoaderThread::loadThread(QQmlDataBlob *b)
+void QQmlTypeLoaderThread::loadThread(const QQmlDataBlob::Ptr &b)
{
m_loader->loadThread(b);
- b->release();
}
-void QQmlTypeLoaderThread::loadWithStaticDataThread(QQmlDataBlob *b, const QByteArray &d)
+void QQmlTypeLoaderThread::loadWithStaticDataThread(const QQmlDataBlob::Ptr &b, const QByteArray &d)
{
m_loader->loadWithStaticDataThread(b, d);
- b->release();
}
-void QQmlTypeLoaderThread::loadWithCachedUnitThread(QQmlDataBlob *b, const QQmlPrivate::CachedQmlUnit *unit)
+void QQmlTypeLoaderThread::loadWithCachedUnitThread(const QQmlDataBlob::Ptr &b, const QQmlPrivate::CachedQmlUnit *unit)
{
m_loader->loadWithCachedUnitThread(b, unit);
- b->release();
}
-void QQmlTypeLoaderThread::callCompletedMain(QQmlDataBlob *b)
+void QQmlTypeLoaderThread::callCompletedMain(const QQmlDataBlob::Ptr &b)
{
#ifdef DATABLOB_DEBUG
qWarning("QQmlTypeLoaderThread: %s completed() callback", qPrintable(b->urlString()));
#endif
b->completed();
- b->release();
}
-void QQmlTypeLoaderThread::callDownloadProgressChangedMain(QQmlDataBlob *b, qreal p)
+void QQmlTypeLoaderThread::callDownloadProgressChangedMain(const QQmlDataBlob::Ptr &b, qreal p)
{
#ifdef DATABLOB_DEBUG
qWarning("QQmlTypeLoaderThread: %s downloadProgressChanged(%f) callback",
qPrintable(b->urlString()), p);
#endif
b->downloadProgressChanged(p);
- b->release();
}
void QQmlTypeLoaderThread::initializeExtensionMain(QQmlExtensionInterface *iface,
diff --git a/src/qml/qml/qqmltypeloaderthread_p.h b/src/qml/qml/qqmltypeloaderthread_p.h
index 045d838528..4f65fc0cbd 100644
--- a/src/qml/qml/qqmltypeloaderthread_p.h
+++ b/src/qml/qml/qqmltypeloaderthread_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLTYPELOADERTHREAD_P_H
#define QQMLTYPELOADERTHREAD_P_H
@@ -53,6 +17,7 @@
#include <private/qqmlthread_p.h>
#include <private/qv4compileddata_p.h>
+#include <private/qqmldatablob_p.h>
#include <QtQml/qtqmlglobal.h>
@@ -63,11 +28,14 @@
QT_BEGIN_NAMESPACE
-class QQmlDataBlob;
class QQmlTypeLoader;
class QQmlEngineExtensionInterface;
class QQmlExtensionInterface;
+namespace QQmlPrivate {
+struct CachedQmlUnit;
+}
+
class QQmlTypeLoaderThread : public QQmlThread
{
typedef QQmlTypeLoaderThread This;
@@ -78,33 +46,30 @@ public:
QNetworkAccessManager *networkAccessManager() const;
QQmlTypeLoaderNetworkReplyProxy *networkReplyProxy() const;
#endif // qml_network
- void load(QQmlDataBlob *b);
- void loadAsync(QQmlDataBlob *b);
- void loadWithStaticData(QQmlDataBlob *b, const QByteArray &);
- void loadWithStaticDataAsync(QQmlDataBlob *b, const QByteArray &);
- void loadWithCachedUnit(QQmlDataBlob *b, const QQmlPrivate::CachedQmlUnit *unit);
- void loadWithCachedUnitAsync(QQmlDataBlob *b, const QQmlPrivate::CachedQmlUnit *unit);
- void callCompleted(QQmlDataBlob *b);
- void callDownloadProgressChanged(QQmlDataBlob *b, qreal p);
+ void load(const QQmlDataBlob::Ptr &b);
+ void loadAsync(const QQmlDataBlob::Ptr &b);
+ void loadWithStaticData(const QQmlDataBlob::Ptr &b, const QByteArray &);
+ void loadWithStaticDataAsync(const QQmlDataBlob::Ptr &b, const QByteArray &);
+ void loadWithCachedUnit(const QQmlDataBlob::Ptr &b, const QQmlPrivate::CachedQmlUnit *unit);
+ void loadWithCachedUnitAsync(const QQmlDataBlob::Ptr &b, const QQmlPrivate::CachedQmlUnit *unit);
+ void callCompleted(const QQmlDataBlob::Ptr &b);
+ void callDownloadProgressChanged(const QQmlDataBlob::Ptr &b, qreal p);
void initializeEngine(QQmlExtensionInterface *, const char *);
void initializeEngine(QQmlEngineExtensionInterface *, const char *);
-protected:
- void shutdownThread() override;
-
private:
- void loadThread(QQmlDataBlob *b);
- void loadWithStaticDataThread(QQmlDataBlob *b, const QByteArray &);
- void loadWithCachedUnitThread(QQmlDataBlob *b, const QQmlPrivate::CachedQmlUnit *unit);
- void callCompletedMain(QQmlDataBlob *b);
- void callDownloadProgressChangedMain(QQmlDataBlob *b, qreal p);
+ void loadThread(const QQmlDataBlob::Ptr &b);
+ void loadWithStaticDataThread(const QQmlDataBlob::Ptr &b, const QByteArray &);
+ void loadWithCachedUnitThread(const QQmlDataBlob::Ptr &b, const QQmlPrivate::CachedQmlUnit *unit);
+ void callCompletedMain(const QQmlDataBlob::Ptr &b);
+ void callDownloadProgressChangedMain(const QQmlDataBlob::Ptr &b, qreal p);
void initializeExtensionMain(QQmlExtensionInterface *iface, const char *uri);
void initializeEngineExtensionMain(QQmlEngineExtensionInterface *iface, const char *uri);
QQmlTypeLoader *m_loader;
#if QT_CONFIG(qml_network)
- mutable QNetworkAccessManager *m_networkAccessManager;
- mutable QQmlTypeLoaderNetworkReplyProxy *m_networkReplyProxy;
+ mutable QNetworkAccessManager *m_networkAccessManager = nullptr;
+ mutable QQmlTypeLoaderNetworkReplyProxy *m_networkReplyProxy = nullptr;
#endif // qml_network
};
diff --git a/src/qml/qml/qqmltypemodule.cpp b/src/qml/qml/qqmltypemodule.cpp
index 5120728031..b188b7fb90 100644
--- a/src/qml/qml/qqmltypemodule.cpp
+++ b/src/qml/qml/qqmltypemodule.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 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$
-**
-****************************************************************************/
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qqmltypemodule_p.h"
@@ -66,7 +30,7 @@ void QQmlTypeModule::add(QQmlTypePrivate *type)
addMinorVersion(type->version.minorVersion());
QList<QQmlTypePrivate *> &list = m_typeHash[type->elementName];
- for (int ii = 0; ii < list.count(); ++ii) {
+ for (int ii = 0; ii < list.size(); ++ii) {
QQmlTypePrivate *in_list = list.at(ii);
Q_ASSERT(in_list);
if (in_list->version.minorVersion() < type->version.minorVersion()) {
@@ -87,25 +51,10 @@ void QQmlTypeModule::remove(const QQmlTypePrivate *type)
QQmlMetaType::removeQQmlTypePrivate(elementIt.value(), type);
}
-QQmlType QQmlTypeModule::type(const QHashedStringRef &name, QTypeRevision version) const
+QQmlType QQmlTypeModule::findType(const QList<QQmlTypePrivate *> *types, QTypeRevision version)
{
- QMutexLocker lock(&m_mutex);
- QList<QQmlTypePrivate *> *types = m_typeHash.value(name);
- if (types) {
- for (int ii = 0; ii < types->count(); ++ii)
- if (types->at(ii)->version.minorVersion() <= version.minorVersion())
- return QQmlType(types->at(ii));
- }
-
- return QQmlType();
-}
-
-QQmlType QQmlTypeModule::type(const QV4::String *name, QTypeRevision version) const
-{
- QMutexLocker lock(&m_mutex);
- QList<QQmlTypePrivate *> *types = m_typeHash.value(name);
if (types) {
- for (int ii = 0; ii < types->count(); ++ii)
+ for (int ii = 0; ii < types->size(); ++ii)
if (types->at(ii)->version.minorVersion() <= version.minorVersion())
return QQmlType(types->at(ii));
}
diff --git a/src/qml/qml/qqmltypemodule_p.h b/src/qml/qml/qqmltypemodule_p.h
index 0ba6245cbb..717b07ec60 100644
--- a/src/qml/qml/qqmltypemodule_p.h
+++ b/src/qml/qml/qqmltypemodule_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 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$
-**
-****************************************************************************/
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLTYPEMODULE_P_H
#define QQMLTYPEMODULE_P_H
@@ -53,6 +17,7 @@
#include <QtQml/qtqmlglobal.h>
#include <QtQml/private/qstringhash_p.h>
+#include <QtQml/private/qqmltype_p.h>
#include <QtCore/qmutex.h>
#include <QtCore/qstring.h>
#include <QtCore/qversionnumber.h>
@@ -72,6 +37,12 @@ struct String;
class QQmlTypeModule
{
public:
+ enum class LockLevel {
+ Open = 0,
+ Weak = 1,
+ Strong = 2
+ };
+
QQmlTypeModule() = default;
QQmlTypeModule(const QString &uri, quint8 majorVersion)
: m_module(uri), m_majorVersion(majorVersion)
@@ -80,8 +51,17 @@ public:
void add(QQmlTypePrivate *);
void remove(const QQmlTypePrivate *type);
- bool isLocked() const { return m_locked.loadRelaxed() != 0; }
- void lock() { m_locked.storeRelaxed(1); }
+ LockLevel lockLevel() const { return LockLevel(m_lockLevel.loadRelaxed()); }
+ bool setLockLevel(LockLevel mode)
+ {
+ while (true) {
+ const int currentLock = m_lockLevel.loadAcquire();
+ if (currentLock > int(mode))
+ return false;
+ if (currentLock == int(mode) || m_lockLevel.testAndSetRelease(currentLock, int(mode)))
+ return true;
+ }
+ }
QString module() const
{
@@ -99,12 +79,24 @@ public:
quint8 minimumMinorVersion() const { return m_minMinorVersion.loadRelaxed(); }
quint8 maximumMinorVersion() const { return m_maxMinorVersion.loadRelaxed(); }
- QQmlType type(const QHashedStringRef &, QTypeRevision version) const;
- QQmlType type(const QV4::String *, QTypeRevision version) const;
+ QQmlType type(const QHashedStringRef &name, QTypeRevision version) const
+ {
+ QMutexLocker lock(&m_mutex);
+ return findType(m_typeHash.value(name), version);
+ }
+
+ QQmlType type(const QV4::String *name, QTypeRevision version) const
+ {
+ QMutexLocker lock(&m_mutex);
+ return findType(m_typeHash.value(name), version);
+ }
void walkCompositeSingletons(const std::function<void(const QQmlType &)> &callback) const;
private:
+ static Q_QML_EXPORT QQmlType findType(
+ const QList<QQmlTypePrivate *> *types, QTypeRevision version);
+
const QString m_module;
const quint8 m_majorVersion = 0;
@@ -114,8 +106,8 @@ private:
// Can only ever increase
QAtomicInt m_maxMinorVersion = 0;
- // Bool. Can only be set to 1 once.
- QAtomicInt m_locked = 0;
+ // LockLevel. Can only be increased.
+ QAtomicInt m_lockLevel = int(LockLevel::Open);
using TypeHash = QStringHash<QList<QQmlTypePrivate *>>;
TypeHash m_typeHash;
diff --git a/src/qml/qml/qqmltypemoduleversion.cpp b/src/qml/qml/qqmltypemoduleversion.cpp
index 932ff7f503..072cf8a1cd 100644
--- a/src/qml/qml/qqmltypemoduleversion.cpp
+++ b/src/qml/qml/qqmltypemoduleversion.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 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$
-**
-****************************************************************************/
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qqmltypemoduleversion_p.h"
diff --git a/src/qml/qml/qqmltypemoduleversion_p.h b/src/qml/qml/qqmltypemoduleversion_p.h
index c5379b2158..8c9b6c68b2 100644
--- a/src/qml/qml/qqmltypemoduleversion_p.h
+++ b/src/qml/qml/qqmltypemoduleversion_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 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$
-**
-****************************************************************************/
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLTYPEMODULEVERSION_P_H
#define QQMLTYPEMODULEVERSION_P_H
diff --git a/src/qml/qml/qqmltypenamecache.cpp b/src/qml/qml/qqmltypenamecache.cpp
index 45333668e3..7d3c81cfd7 100644
--- a/src/qml/qml/qqmltypenamecache.cpp
+++ b/src/qml/qml/qqmltypenamecache.cpp
@@ -1,60 +1,13 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qqmltypenamecache_p.h"
-#include "qqmlengine_p.h"
-
QT_BEGIN_NAMESPACE
-QQmlTypeNameCache::QQmlTypeNameCache(const QQmlImports &importCache)
- : m_imports(importCache)
-{
-}
-
-QQmlTypeNameCache::~QQmlTypeNameCache()
-{
-}
-
void QQmlTypeNameCache::add(const QHashedString &name, const QUrl &url, const QHashedString &nameSpace)
{
- if (nameSpace.length() != 0) {
+ if (nameSpace.size() != 0) {
QQmlImportRef *i = m_namedImports.value(nameSpace);
Q_ASSERT(i != nullptr);
i->compositeSingletons.insert(name, url);
@@ -73,7 +26,7 @@ void QQmlTypeNameCache::add(const QHashedString &name, int importedScriptIndex,
import.scriptIndex = importedScriptIndex;
import.m_qualifier = name;
- if (nameSpace.length() != 0) {
+ if (nameSpace.size() != 0) {
QQmlImportRef *i = m_namedImports.value(nameSpace);
Q_ASSERT(i != nullptr);
m_namespacedImports[i].insert(name, import);
@@ -86,119 +39,5 @@ void QQmlTypeNameCache::add(const QHashedString &name, int importedScriptIndex,
m_namedImports.insert(name, import);
}
-QQmlTypeNameCache::Result QQmlTypeNameCache::query(const QHashedStringRef &name) const
-{
- Result result = query(m_namedImports, name);
-
- if (!result.isValid())
- result = typeSearch(m_anonymousImports, name);
-
- if (!result.isValid())
- result = query(m_anonymousCompositeSingletons, name);
-
- if (!result.isValid()) {
- // Look up anonymous types from the imports of this document
- QQmlImportNamespace *typeNamespace = nullptr;
- QList<QQmlError> errors;
- QQmlType t;
- bool typeFound = m_imports.resolveType(name, &t, nullptr, &typeNamespace, &errors);
- if (typeFound) {
- return Result(t);
- }
-
- }
-
- return result;
-}
-
-QQmlTypeNameCache::Result QQmlTypeNameCache::query(const QHashedStringRef &name,
- const QQmlImportRef *importNamespace) const
-{
- Q_ASSERT(importNamespace && importNamespace->scriptIndex == -1);
-
- Result result = typeSearch(importNamespace->modules, name);
-
- if (!result.isValid())
- result = query(importNamespace->compositeSingletons, name);
-
- if (!result.isValid()) {
- // Look up types from the imports of this document
- // ### it would be nice if QQmlImports allowed us to resolve a namespace
- // first, and then types on it.
- QString qualifiedTypeName = importNamespace->m_qualifier + QLatin1Char('.') + name.toString();
- QQmlImportNamespace *typeNamespace = nullptr;
- QList<QQmlError> errors;
- QQmlType t;
- bool typeFound = m_imports.resolveType(qualifiedTypeName, &t, nullptr, &typeNamespace, &errors);
- if (typeFound) {
- return Result(t);
- }
- }
-
- return result;
-}
-
-QQmlTypeNameCache::Result QQmlTypeNameCache::query(const QV4::String *name, QQmlImport::RecursionRestriction recursionRestriction) const
-{
- Result result = query(m_namedImports, name);
-
- if (!result.isValid())
- result = typeSearch(m_anonymousImports, name);
-
- if (!result.isValid())
- result = query(m_anonymousCompositeSingletons, name);
-
- if (!result.isValid()) {
- // Look up anonymous types from the imports of this document
- QString typeName = name->toQStringNoThrow();
- QQmlImportNamespace *typeNamespace = nullptr;
- QList<QQmlError> errors;
- QQmlType t;
- bool typeRecursionDetected = false;
- bool typeFound = m_imports.resolveType(typeName, &t, nullptr, &typeNamespace, &errors,
- QQmlType::AnyRegistrationType,
- recursionRestriction == QQmlImport::AllowRecursion ? &typeRecursionDetected : nullptr);
- if (typeFound) {
- return Result(t);
- }
-
- }
-
- return result;
-}
-
-QQmlTypeNameCache::Result QQmlTypeNameCache::query(const QV4::String *name, const QQmlImportRef *importNamespace) const
-{
- Q_ASSERT(importNamespace && importNamespace->scriptIndex == -1);
-
- QMap<const QQmlImportRef *, QStringHash<QQmlImportRef> >::const_iterator it = m_namespacedImports.constFind(importNamespace);
- if (it != m_namespacedImports.constEnd()) {
- Result r = query(*it, name);
- if (r.isValid())
- return r;
- }
-
- Result r = typeSearch(importNamespace->modules, name);
-
- if (!r.isValid())
- r = query(importNamespace->compositeSingletons, name);
-
- if (!r.isValid()) {
- // Look up types from the imports of this document
- // ### it would be nice if QQmlImports allowed us to resolve a namespace
- // first, and then types on it.
- QString qualifiedTypeName = importNamespace->m_qualifier + QLatin1Char('.') + name->toQStringNoThrow();
- QQmlImportNamespace *typeNamespace = nullptr;
- QList<QQmlError> errors;
- QQmlType t;
- bool typeFound = m_imports.resolveType(qualifiedTypeName, &t, nullptr, &typeNamespace, &errors);
- if (typeFound) {
- return Result(t);
- }
- }
-
- return r;
-}
-
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmltypenamecache_p.h b/src/qml/qml/qqmltypenamecache_p.h
index 974f99ecae..1ec0a65fa0 100644
--- a/src/qml/qml/qqmltypenamecache_p.h
+++ b/src/qml/qml/qqmltypenamecache_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLTYPENAMECACHE_P_H
#define QQMLTYPENAMECACHE_P_H
@@ -81,11 +45,11 @@ struct QQmlImportRef {
class QQmlType;
class QQmlEngine;
-class Q_QML_PRIVATE_EXPORT QQmlTypeNameCache : public QQmlRefCount
+class Q_QML_EXPORT QQmlTypeNameCache final : public QQmlRefCounted<QQmlTypeNameCache>
{
public:
- QQmlTypeNameCache(const QQmlImports &imports);
- ~QQmlTypeNameCache() override;
+ QQmlTypeNameCache(const QQmlRefPointer<QQmlImports> &imports) : m_imports(imports) {}
+ ~QQmlTypeNameCache() {}
inline bool isEmpty() const;
@@ -104,16 +68,133 @@ public:
const QQmlImportRef *importNamespace;
int scriptIndex;
};
- Result query(const QHashedStringRef &) const;
- Result query(const QHashedStringRef &, const QQmlImportRef *importNamespace) const;
- Result query(const QV4::String *, QQmlImport::RecursionRestriction recursionRestriction = QQmlImport::PreventRecursion) const;
- Result query(const QV4::String *, const QQmlImportRef *importNamespace) const;
+
+ enum class QueryNamespaced { No, Yes };
+
+ // Restrict the types allowed for key. We don't want QV4::ScopedString, for example.
+
+ template<QQmlImport::RecursionRestriction recursionRestriction = QQmlImport::PreventRecursion>
+ Result query(const QHashedStringRef &key, QQmlTypeLoader *typeLoader) const
+ {
+ return doQuery<const QHashedStringRef &, recursionRestriction>(key, typeLoader);
+ }
+
+ template<QueryNamespaced queryNamespaced = QueryNamespaced::Yes>
+ Result query(const QHashedStringRef &key, const QQmlImportRef *importNamespace,
+ QQmlTypeLoader *typeLoader) const
+ {
+ return doQuery<const QHashedStringRef &, queryNamespaced>(key, importNamespace, typeLoader);
+ }
+
+ template<QQmlImport::RecursionRestriction recursionRestriction = QQmlImport::PreventRecursion>
+ Result query(const QV4::String *key, QQmlTypeLoader *typeLoader) const
+ {
+ return doQuery<const QV4::String *, recursionRestriction>(key, typeLoader);
+ }
+
+ template<QueryNamespaced queryNamespaced = QueryNamespaced::Yes>
+ Result query(const QV4::String *key, const QQmlImportRef *importNamespace,
+ QQmlTypeLoader *typeLoader) const
+ {
+ return doQuery<const QV4::String *, queryNamespaced>(key, importNamespace, typeLoader);
+ }
private:
friend class QQmlImports;
+ static QHashedStringRef toHashedStringRef(const QHashedStringRef &key) { return key; }
+ static QHashedStringRef toHashedStringRef(const QV4::String *key)
+ {
+ const QV4::Heap::String *heapString = key->d();
+
+ // toQString() would also do simplifyString(). Therefore, we can be sure that this
+ // is safe. Any other operation on the string data cannot keep references on the
+ // non-simplified pieces.
+ if (heapString->subtype >= QV4::Heap::String::StringType_Complex)
+ heapString->simplifyString();
+
+ // This is safe because the string data is backed by the QV4::String we got as
+ // parameter. The contract about passing V4 values as parameters is that you have to
+ // scope them first, so that they don't get gc'd while the callee is working on them.
+ const QStringPrivate &text = heapString->text();
+ return QHashedStringRef(QStringView(text.ptr, text.size));
+ }
+
+ static QString toQString(const QHashedStringRef &key) { return key.toString(); }
+ static QString toQString(const QV4::String *key) { return key->toQStringNoThrow(); }
+
+ template<typename Key, QQmlImport::RecursionRestriction recursionRestriction>
+ Result doQuery(Key name, QQmlTypeLoader *typeLoader) const
+ {
+ Result result = doQuery(m_namedImports, name);
+
+ if (!result.isValid())
+ result = typeSearch(m_anonymousImports, name);
+
+ if (!result.isValid())
+ result = doQuery(m_anonymousCompositeSingletons, name);
+
+ if (!result.isValid()) {
+ // Look up anonymous types from the imports of this document
+ // ### it would be nice if QQmlImports allowed us to resolve a namespace
+ // first, and then types on it.
+ QQmlImportNamespace *typeNamespace = nullptr;
+ QList<QQmlError> errors;
+ QQmlType t;
+ bool typeRecursionDetected = false;
+ const bool typeFound = m_imports->resolveType(
+ typeLoader, toHashedStringRef(name), &t, nullptr, &typeNamespace, &errors,
+ QQmlType::AnyRegistrationType,
+ recursionRestriction == QQmlImport::AllowRecursion
+ ? &typeRecursionDetected
+ : nullptr);
+ if (typeFound)
+ return Result(t);
+
+ }
+
+ return result;
+ }
+
+ template<typename Key, QueryNamespaced queryNamespaced>
+ Result doQuery(Key name, const QQmlImportRef *importNamespace, QQmlTypeLoader *typeLoader) const
+ {
+ Q_ASSERT(importNamespace && importNamespace->scriptIndex == -1);
+
+ if constexpr (queryNamespaced == QueryNamespaced::Yes) {
+ QMap<const QQmlImportRef *, QStringHash<QQmlImportRef> >::const_iterator it
+ = m_namespacedImports.constFind(importNamespace);
+ if (it != m_namespacedImports.constEnd()) {
+ Result r = doQuery(*it, name);
+ if (r.isValid())
+ return r;
+ }
+ }
+
+ Result result = typeSearch(importNamespace->modules, name);
+
+ if (!result.isValid())
+ result = doQuery(importNamespace->compositeSingletons, name);
+
+ if (!result.isValid()) {
+ // Look up types from the imports of this document
+ // ### it would be nice if QQmlImports allowed us to resolve a namespace
+ // first, and then types on it.
+ const QString qualifiedTypeName = importNamespace->m_qualifier + u'.' + toQString(name);
+ QQmlImportNamespace *typeNamespace = nullptr;
+ QList<QQmlError> errors;
+ QQmlType t;
+ bool typeFound = m_imports->resolveType(
+ typeLoader, qualifiedTypeName, &t, nullptr, &typeNamespace, &errors);
+ if (typeFound)
+ return Result(t);
+ }
+
+ return result;
+ }
+
template<typename Key>
- Result query(const QStringHash<QQmlImportRef> &imports, Key key) const
+ Result doQuery(const QStringHash<QQmlImportRef> &imports, Key key) const
{
QQmlImportRef *i = imports.value(key);
if (i) {
@@ -129,7 +210,7 @@ private:
}
template<typename Key>
- Result query(const QStringHash<QUrl> &urls, Key key) const
+ Result doQuery(const QStringHash<QUrl> &urls, Key key) const
{
QUrl *url = urls.value(key);
if (url) {
@@ -157,7 +238,7 @@ private:
QMap<const QQmlImportRef *, QStringHash<QQmlImportRef> > m_namespacedImports;
QVector<QQmlTypeModuleVersion> m_anonymousImports;
QStringHash<QUrl> m_anonymousCompositeSingletons;
- QQmlImports m_imports;
+ QQmlRefPointer<QQmlImports> m_imports;
};
QQmlTypeNameCache::Result::Result()
diff --git a/src/qml/qml/qqmltypenotavailable.cpp b/src/qml/qml/qqmltypenotavailable.cpp
deleted file mode 100644
index 0e95d6062c..0000000000
--- a/src/qml/qml/qqmltypenotavailable.cpp
+++ /dev/null
@@ -1,51 +0,0 @@
-/****************************************************************************
-**
-** 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 "qqmltypenotavailable_p.h"
-
-QT_BEGIN_NAMESPACE
-
-int qmlRegisterTypeNotAvailable(const char *uri, int versionMajor, int versionMinor, const char *qmlName, const QString& message)
-{
- return qmlRegisterUncreatableType<QQmlTypeNotAvailable>(uri,versionMajor,versionMinor,qmlName,message);
-}
-
-QT_END_NAMESPACE
-
-#include "moc_qqmltypenotavailable_p.cpp"
diff --git a/src/qml/qml/qqmltypenotavailable_p.h b/src/qml/qml/qqmltypenotavailable_p.h
deleted file mode 100644
index dbd37ace2a..0000000000
--- a/src/qml/qml/qqmltypenotavailable_p.h
+++ /dev/null
@@ -1,69 +0,0 @@
-/****************************************************************************
-**
-** 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 QQMLTYPENOTAVAILABLE_H
-#define QQMLTYPENOTAVAILABLE_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 <qqml.h>
-
-QT_BEGIN_NAMESPACE
-
-class QQmlTypeNotAvailable : public QObject {
- Q_OBJECT
- QML_NAMED_ELEMENT(TypeNotAvailable)
- QML_ADDED_IN_VERSION(2, 15)
- QML_UNCREATABLE("Type not available.")
-};
-
-QT_END_NAMESPACE
-
-QML_DECLARE_TYPE(QQmlTypeNotAvailable)
-
-#endif // QQMLTYPENOTAVAILABLE_H
diff --git a/src/qml/qml/qqmltypewrapper.cpp b/src/qml/qml/qqmltypewrapper.cpp
index 495822251f..0d8786a9df 100644
--- a/src/qml/qml/qqmltypewrapper.cpp
+++ b/src/qml/qml/qqmltypewrapper.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qqmltypewrapper_p.h"
@@ -43,6 +7,7 @@
#include <private/qqmlcontext_p.h>
#include <private/qqmlmetaobject_p.h>
#include <private/qqmltypedata_p.h>
+#include <private/qqmlvaluetypewrapper_p.h>
#include <private/qjsvalue_p.h>
#include <private/qv4functionobject_p.h>
@@ -58,15 +23,32 @@ using namespace QV4;
DEFINE_OBJECT_VTABLE(QQmlTypeWrapper);
DEFINE_OBJECT_VTABLE(QQmlScopedEnumWrapper);
-void Heap::QQmlTypeWrapper::init()
+
+void Heap::QQmlTypeWrapper::init(TypeNameMode m, QObject *o, const QQmlTypePrivate *type)
+{
+ Q_ASSERT(type);
+ Object::init();
+ mode = m;
+ object.init(o);
+ typePrivate = type;
+ QQmlType::refHandle(typePrivate);
+}
+
+void Heap::QQmlTypeWrapper::init(
+ TypeNameMode m, QObject *o, QQmlTypeNameCache *type, const QQmlImportRef *import)
{
+ Q_ASSERT(type);
Object::init();
- mode = IncludeEnums;
- object.init();
+ mode = m;
+ object.init(o);
+ typeNamespace = type;
+ typeNamespace->addref();
+ importNamespace = import;
}
void Heap::QQmlTypeWrapper::destroy()
{
+ Q_ASSERT(typePrivate || typeNamespace);
QQmlType::derefHandle(typePrivate);
typePrivate = nullptr;
if (typeNamespace)
@@ -85,6 +67,50 @@ bool QQmlTypeWrapper::isSingleton() const
return d()->type().isSingleton();
}
+const QMetaObject *QQmlTypeWrapper::metaObject() const
+{
+ const QQmlType type = d()->type();
+ if (!type.isValid())
+ return nullptr;
+
+ if (type.isSingleton()) {
+ auto metaObjectCandidate = type.metaObject();
+ // if the candidate is the same as te baseMetaObject, we know that
+ // we don't have an extended singleton; in that case the
+ // actual instance might be subclass of type instead of type itself
+ // so we need to query the actual object for it's meta-object
+ if (metaObjectCandidate == type.baseMetaObject()) {
+ QQmlEnginePrivate *qmlEngine = QQmlEnginePrivate::get(engine()->qmlEngine());
+ auto object = qmlEngine->singletonInstance<QObject *>(type);
+ if (object)
+ return object->metaObject();
+ }
+ /* if we instead have an extended singleton, the dynamic proxy
+ meta-object must alreday be set up correctly
+ ### TODO: it isn't, as QQmlTypePrivate::init has no way to
+ query the object
+ */
+ return metaObjectCandidate;
+ }
+
+ return type.attachedPropertiesType(QQmlEnginePrivate::get(engine()->qmlEngine()));
+}
+
+QObject *QQmlTypeWrapper::object() const
+{
+ const QQmlType type = d()->type();
+ if (!type.isValid())
+ return nullptr;
+
+ QQmlEnginePrivate *qmlEngine = QQmlEnginePrivate::get(engine()->qmlEngine());
+ if (type.isSingleton())
+ return qmlEngine->singletonInstance<QObject *>(type);
+
+ return qmlAttachedPropertiesObject(
+ d()->object,
+ type.attachedPropertiesFunction(qmlEngine));
+}
+
QObject* QQmlTypeWrapper::singletonObject() const
{
if (!isSingleton())
@@ -96,11 +122,14 @@ QObject* QQmlTypeWrapper::singletonObject() const
QVariant QQmlTypeWrapper::toVariant() const
{
- if (!isSingleton())
- return QVariant::fromValue<QObject *>(d()->object);
-
QQmlEnginePrivate *e = QQmlEnginePrivate::get(engine()->qmlEngine());
const QQmlType type = d()->type();
+
+ if (!isSingleton()) {
+ return QVariant::fromValue(qmlAttachedPropertiesObject(
+ d()->object, type.attachedPropertiesFunction(e)));
+ }
+
if (type.isQJSValueSingleton())
return QVariant::fromValue<QJSValue>(e->singletonInstance<QJSValue>(type));
@@ -115,47 +144,31 @@ ReturnedValue QQmlTypeWrapper::create(QV4::ExecutionEngine *engine, QObject *o,
Q_ASSERT(t.isValid());
Scope scope(engine);
- Scoped<QQmlTypeWrapper> w(scope, engine->memoryManager->allocate<QQmlTypeWrapper>());
- w->d()->mode = mode; w->d()->object = o;
- w->d()->typePrivate = t.priv();
- QQmlType::refHandle(w->d()->typePrivate);
+ Scoped<QQmlTypeWrapper> w(scope, engine->memoryManager->allocate<QQmlTypeWrapper>(
+ mode, o, t.priv()));
return w.asReturnedValue();
}
// Returns a type wrapper for importNamespace (of t) on o. This allows nested resolution of a type in a
// namespace.
-ReturnedValue QQmlTypeWrapper::create(QV4::ExecutionEngine *engine, QObject *o, const QQmlRefPointer<QQmlTypeNameCache> &t, const QQmlImportRef *importNamespace,
- Heap::QQmlTypeWrapper::TypeNameMode mode)
+ReturnedValue QQmlTypeWrapper::create(
+ QV4::ExecutionEngine *engine, QObject *o, const QQmlRefPointer<QQmlTypeNameCache> &t,
+ const QQmlImportRef *importNamespace, Heap::QQmlTypeWrapper::TypeNameMode mode)
{
Q_ASSERT(t);
Q_ASSERT(importNamespace);
Scope scope(engine);
- Scoped<QQmlTypeWrapper> w(scope, engine->memoryManager->allocate<QQmlTypeWrapper>());
- w->d()->mode = mode; w->d()->object = o; w->d()->typeNamespace = t.data(); w->d()->importNamespace = importNamespace;
- t->addref();
+ Scoped<QQmlTypeWrapper> w(scope, engine->memoryManager->allocate<QQmlTypeWrapper>(
+ mode, o, t.data(), importNamespace));
return w.asReturnedValue();
}
-static int enumForSingleton(QV4::ExecutionEngine *v4, String *name, QObject *qobjectSingleton,
- const QQmlType &type, bool *ok)
+static int enumForSingleton(QV4::ExecutionEngine *v4, String *name, const QQmlType &type, bool *ok)
{
Q_ASSERT(ok != nullptr);
- int value = type.enumValue(QQmlEnginePrivate::get(v4->qmlEngine()), name, ok);
- if (*ok)
- return value;
-
- // ### Optimize
- QByteArray enumName = name->toQString().toUtf8();
- const QMetaObject *metaObject = qobjectSingleton->metaObject();
- for (int ii = metaObject->enumeratorCount() - 1; ii >= 0; --ii) {
- QMetaEnum e = metaObject->enumerator(ii);
- value = e.keyToValue(enumName.constData(), ok);
- if (*ok)
- return value;
- }
- *ok = false;
- return -1;
+ const int value = type.enumValue(QQmlEnginePrivate::get(v4->qmlEngine()), name, ok);
+ return *ok ? value : -1;
}
ReturnedValue QQmlTypeWrapper::virtualGet(const Managed *m, PropertyKey id, const Value *receiver, bool *hasProperty)
@@ -166,7 +179,7 @@ ReturnedValue QQmlTypeWrapper::virtualGet(const Managed *m, PropertyKey id, cons
if (!id.isString())
return Object::virtualGet(m, id, receiver, hasProperty);
- QV4::ExecutionEngine *v4 = static_cast<const QQmlTypeWrapper *>(m)->engine();
+ QV4::ExecutionEngine *v4 = m->engine();
QV4::Scope scope(v4);
ScopedString name(scope, id.asStringOrSymbol());
@@ -180,23 +193,24 @@ ReturnedValue QQmlTypeWrapper::virtualGet(const Managed *m, PropertyKey id, cons
QObject *object = w->d()->object;
QQmlType type = w->d()->type();
+ QQmlEnginePrivate *enginePrivate = QQmlEnginePrivate::get(v4->qmlEngine());
if (type.isValid()) {
// singleton types are handled differently to other types.
if (type.isSingleton()) {
- QQmlEnginePrivate *e = QQmlEnginePrivate::get(v4->qmlEngine());
+
QJSValue scriptSingleton;
if (type.isQObjectSingleton() || type.isCompositeSingleton()) {
- if (QObject *qobjectSingleton = e->singletonInstance<QObject*>(type)) {
+ if (QObject *qobjectSingleton = enginePrivate->singletonInstance<QObject*>(type)) {
// check for enum value
const bool includeEnums = w->d()->mode == Heap::QQmlTypeWrapper::IncludeEnums;
if (includeEnums && name->startsWithUpper()) {
bool ok = false;
- int value = enumForSingleton(v4, name, qobjectSingleton, type, &ok);
+ int value = enumForSingleton(v4, name, type, &ok);
if (ok)
return QV4::Value::fromInt32(value).asReturnedValue();
- value = type.scopedEnumIndex(QQmlEnginePrivate::get(v4->qmlEngine()), name, &ok);
+ value = type.scopedEnumIndex(enginePrivate, name, &ok);
if (ok) {
Scoped<QQmlScopedEnumWrapper> enumWrapper(scope, v4->memoryManager->allocate<QQmlScopedEnumWrapper>());
enumWrapper->d()->typePrivate = type.priv();
@@ -208,14 +222,16 @@ ReturnedValue QQmlTypeWrapper::virtualGet(const Managed *m, PropertyKey id, cons
// check for property.
bool ok;
- const ReturnedValue result = QV4::QObjectWrapper::getQmlProperty(v4, context, qobjectSingleton, name, QV4::QObjectWrapper::IgnoreRevision, &ok);
+ const ReturnedValue result = QV4::QObjectWrapper::getQmlProperty(
+ v4, context, w->d(), qobjectSingleton, name,
+ QV4::QObjectWrapper::AttachMethods, &ok);
if (hasProperty)
*hasProperty = ok;
return result;
}
} else if (type.isQJSValueSingleton()) {
- QJSValue scriptSingleton = e->singletonInstance<QJSValue>(type);
+ QJSValue scriptSingleton = enginePrivate->singletonInstance<QJSValue>(type);
if (!scriptSingleton.isUndefined()) {
// NOTE: if used in a binding, changes will not trigger re-evaluation since non-NOTIFYable.
QV4::ScopedObject o(scope, QJSValuePrivate::asReturnedValue(&scriptSingleton));
@@ -230,11 +246,11 @@ ReturnedValue QQmlTypeWrapper::virtualGet(const Managed *m, PropertyKey id, cons
if (name->startsWithUpper()) {
bool ok = false;
- int value = type.enumValue(QQmlEnginePrivate::get(v4->qmlEngine()), name, &ok);
+ int value = type.enumValue(enginePrivate, name, &ok);
if (ok)
return QV4::Value::fromInt32(value).asReturnedValue();
- value = type.scopedEnumIndex(QQmlEnginePrivate::get(v4->qmlEngine()), name, &ok);
+ value = type.scopedEnumIndex(enginePrivate, name, &ok);
if (ok) {
Scoped<QQmlScopedEnumWrapper> enumWrapper(scope, v4->memoryManager->allocate<QQmlScopedEnumWrapper>());
enumWrapper->d()->typePrivate = type.priv();
@@ -250,7 +266,9 @@ ReturnedValue QQmlTypeWrapper::virtualGet(const Managed *m, PropertyKey id, cons
object,
type.attachedPropertiesFunction(QQmlEnginePrivate::get(v4->qmlEngine())));
if (ao)
- return QV4::QObjectWrapper::getQmlProperty(v4, context, ao, name, QV4::QObjectWrapper::IgnoreRevision, hasProperty);
+ return QV4::QObjectWrapper::getQmlProperty(
+ v4, context, w->d(), ao, name, QV4::QObjectWrapper::AttachMethods,
+ hasProperty);
// Fall through to base implementation
}
@@ -262,7 +280,8 @@ ReturnedValue QQmlTypeWrapper::virtualGet(const Managed *m, PropertyKey id, cons
} else if (w->d()->typeNamespace) {
Q_ASSERT(w->d()->importNamespace);
- QQmlTypeNameCache::Result r = w->d()->typeNamespace->query(name, w->d()->importNamespace);
+ QQmlTypeNameCache::Result r = w->d()->typeNamespace->query(
+ name, w->d()->importNamespace, QQmlTypeLoader::get(enginePrivate));
if (r.isValid()) {
if (r.type.isValid()) {
@@ -302,7 +321,7 @@ bool QQmlTypeWrapper::virtualPut(Managed *m, PropertyKey id, const Value &value,
Q_ASSERT(m->as<QQmlTypeWrapper>());
QQmlTypeWrapper *w = static_cast<QQmlTypeWrapper *>(m);
QV4::Scope scope(w);
- if (scope.engine->hasException)
+ if (scope.hasException())
return false;
ScopedString name(scope, id.asStringOrSymbol());
@@ -315,13 +334,16 @@ bool QQmlTypeWrapper::virtualPut(Managed *m, PropertyKey id, const Value &value,
QObject *ao = qmlAttachedPropertiesObject(
object, type.attachedPropertiesFunction(QQmlEnginePrivate::get(e)));
if (ao)
- return QV4::QObjectWrapper::setQmlProperty(scope.engine, context, ao, name, QV4::QObjectWrapper::IgnoreRevision, value);
+ return QV4::QObjectWrapper::setQmlProperty(
+ scope.engine, context, ao, name, QV4::QObjectWrapper::NoFlag, value);
return false;
} else if (type.isSingleton()) {
QQmlEnginePrivate *e = QQmlEnginePrivate::get(scope.engine->qmlEngine());
if (type.isQObjectSingleton() || type.isCompositeSingleton()) {
if (QObject *qobjectSingleton = e->singletonInstance<QObject*>(type))
- return QV4::QObjectWrapper::setQmlProperty(scope.engine, context, qobjectSingleton, name, QV4::QObjectWrapper::IgnoreRevision, value);
+ return QV4::QObjectWrapper::setQmlProperty(
+ scope.engine, context, qobjectSingleton, name,
+ QV4::QObjectWrapper::NoFlag, value);
} else {
QJSValue scriptSingleton = e->singletonInstance<QJSValue>(type);
@@ -367,20 +389,11 @@ bool QQmlTypeWrapper::virtualIsEqualTo(Managed *a, Managed *b)
return false;
}
-ReturnedValue QQmlTypeWrapper::virtualInstanceOf(const Object *typeObject, const Value &var)
+static ReturnedValue instanceOfQObject(const QV4::QQmlTypeWrapper *typeWrapper, const QObjectWrapper *objectWrapper)
{
- Q_ASSERT(typeObject->as<QV4::QQmlTypeWrapper>());
- const QV4::QQmlTypeWrapper *typeWrapper = static_cast<const QV4::QQmlTypeWrapper *>(typeObject);
- QV4::ExecutionEngine *engine = typeObject->internalClass()->engine;
- QQmlEnginePrivate *qenginepriv = QQmlEnginePrivate::get(engine->qmlEngine());
-
- // can only compare a QObject* against a QML type
- const QObjectWrapper *wrapper = var.as<QObjectWrapper>();
- if (!wrapper)
- return QV4::Encode(false);
-
+ QV4::ExecutionEngine *engine = typeWrapper->internalClass()->engine;
// in case the wrapper outlived the QObject*
- const QObject *wrapperObject = wrapper->object();
+ const QObject *wrapperObject = objectWrapper->object();
if (!wrapperObject)
return engine->throwTypeError();
@@ -390,16 +403,21 @@ ReturnedValue QQmlTypeWrapper::virtualInstanceOf(const Object *typeObject, const
// we're a composite type; a composite type cannot be equal to a
// non-composite object instance (Rectangle{} is never an instance of
// CustomRectangle)
- QQmlData *theirDData = QQmlData::get(wrapperObject, /*create=*/false);
+ QQmlData *theirDData = QQmlData::get(wrapperObject);
Q_ASSERT(theirDData); // must exist, otherwise how do we have a QObjectWrapper for it?!
if (!theirDData->compilationUnit)
return Encode(false);
+ QQmlEnginePrivate *qenginepriv = QQmlEnginePrivate::get(engine->qmlEngine());
QQmlRefPointer<QQmlTypeData> td = qenginepriv->typeLoader.getType(typeWrapper->d()->type().sourceUrl());
- ExecutableCompilationUnit *cu = td->compilationUnit();
- myQmlType = qenginepriv->metaObjectForType(cu->typeIds.id.id());
+ if (CompiledData::CompilationUnit *cu = td->compilationUnit())
+ myQmlType = QQmlMetaType::metaObjectForType(cu->metaType());
+ else
+ return Encode(false); // It seems myQmlType has some errors, so we could not compile it.
} else {
- myQmlType = qenginepriv->metaObjectForType(myTypeId.id());
+ myQmlType = QQmlMetaType::metaObjectForType(myTypeId);
+ if (myQmlType.isNull())
+ return Encode(false);
}
const QMetaObject *theirType = wrapperObject->metaObject();
@@ -407,6 +425,29 @@ ReturnedValue QQmlTypeWrapper::virtualInstanceOf(const Object *typeObject, const
return QV4::Encode(QQmlMetaObject::canConvert(theirType, myQmlType));
}
+ReturnedValue QQmlTypeWrapper::virtualInstanceOf(const Object *typeObject, const Value &var)
+{
+ Q_ASSERT(typeObject->as<QV4::QQmlTypeWrapper>());
+ const QV4::QQmlTypeWrapper *typeWrapper = static_cast<const QV4::QQmlTypeWrapper *>(typeObject);
+
+ if (const QObjectWrapper *objectWrapper = var.as<QObjectWrapper>())
+ return instanceOfQObject(typeWrapper, objectWrapper);
+
+ const QQmlType type = typeWrapper->d()->type();
+ if (type.isValueType()) {
+ if (const QQmlValueTypeWrapper *valueWrapper = var.as<QQmlValueTypeWrapper>()) {
+ return QV4::Encode(QQmlMetaObject::canConvert(valueWrapper->metaObject(),
+ type.metaObjectForValueType()));
+ }
+
+ // We want "foo as valuetype" to return undefined if it doesn't match.
+ return Encode::undefined();
+ }
+
+ // If the target type is an object type we want null.
+ return Encode(false);
+}
+
ReturnedValue QQmlTypeWrapper::virtualResolveLookupGetter(const Object *object, ExecutionEngine *engine, Lookup *lookup)
{
// Keep this code in sync with ::virtualGet
@@ -432,15 +473,19 @@ ReturnedValue QQmlTypeWrapper::virtualResolveLookupGetter(const Object *object,
if (!includeEnums || !name->startsWithUpper()) {
QQmlData *ddata = QQmlData::get(qobjectSingleton, false);
if (ddata && ddata->propertyCache) {
- QQmlPropertyData *property = ddata->propertyCache->property(name.getPointer(), qobjectSingleton, qmlContext);
+ const QQmlPropertyData *property = ddata->propertyCache->property(name.getPointer(), qobjectSingleton, qmlContext);
if (property) {
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 = QQmlTypeWrapper::lookupSingletonProperty;
+ if (qualifiesForMethodLookup(property)) {
+ QV4::Heap::QObjectMethod *method = nullptr;
+ setupQObjectMethodLookup(
+ lookup, ddata, property, val->objectValue(), method);
+ lookup->getter = QQmlTypeWrapper::lookupSingletonMethod;
+ } else {
+ setupQObjectLookup(
+ lookup, ddata, property, val->objectValue(), This);
+ lookup->getter = QQmlTypeWrapper::lookupSingletonProperty;
+ }
return lookup->getter(lookup, engine, *object);
}
// Fall through to base implementation
@@ -458,7 +503,7 @@ ReturnedValue QQmlTypeWrapper::virtualResolveLookupGetter(const Object *object,
bool ok = false;
int value = type.enumValue(QQmlEnginePrivate::get(engine->qmlEngine()), name, &ok);
if (ok) {
- lookup->qmlEnumValueLookup.ic = This->internalClass();
+ lookup->qmlEnumValueLookup.ic.set(engine, This->internalClass());
lookup->qmlEnumValueLookup.encodedEnumValue
= QV4::Value::fromInt32(value).asReturnedValue();
lookup->getter = QQmlTypeWrapper::lookupEnumValue;
@@ -473,9 +518,9 @@ ReturnedValue QQmlTypeWrapper::virtualResolveLookupGetter(const Object *object,
QQmlType::refHandle(enumWrapper->d()->typePrivate);
enumWrapper->d()->scopeEnumIndex = value;
- lookup->qmlScopedEnumWrapperLookup.ic = This->internalClass();
- lookup->qmlScopedEnumWrapperLookup.qmlScopedEnumWrapper
- = static_cast<Heap::Object*>(enumWrapper->heapObject());
+ lookup->qmlScopedEnumWrapperLookup.ic.set(engine, This->internalClass());
+ lookup->qmlScopedEnumWrapperLookup.qmlScopedEnumWrapper.set(engine,
+ static_cast<Heap::Object*>(enumWrapper->heapObject()));
lookup->getter = QQmlTypeWrapper::lookupScopedEnum;
return enumWrapper.asReturnedValue();
}
@@ -491,6 +536,30 @@ bool QQmlTypeWrapper::virtualResolveLookupSetter(Object *object, ExecutionEngine
return Object::virtualResolveLookupSetter(object, engine, lookup, value);
}
+OwnPropertyKeyIterator *QQmlTypeWrapper::virtualOwnPropertyKeys(const Object *m, Value *target)
+{
+ QV4::Scope scope(m->engine());
+ QV4::Scoped<QQmlTypeWrapper> typeWrapper(scope, m);
+ Q_ASSERT(typeWrapper);
+ if (QObject *object = typeWrapper->object()) {
+ QV4::Scoped<QV4::QObjectWrapper> objectWrapper(scope, QV4::QObjectWrapper::wrap(typeWrapper->engine(), object));
+ return QV4::QObjectWrapper::virtualOwnPropertyKeys(objectWrapper, target);
+ }
+
+ return Object::virtualOwnPropertyKeys(m, target);
+}
+
+int QQmlTypeWrapper::virtualMetacall(Object *object, QMetaObject::Call call, int index, void **a)
+{
+ QQmlTypeWrapper *wrapper = object->as<QQmlTypeWrapper>();
+ Q_ASSERT(wrapper);
+
+ if (QObject *qObject = wrapper->object())
+ return QMetaObject::metacall(qObject, call, index, a);
+
+ return 0;
+}
+
ReturnedValue QQmlTypeWrapper::lookupSingletonProperty(Lookup *l, ExecutionEngine *engine, const Value &object)
{
const auto revertLookup = [l, engine, &object]() {
@@ -503,6 +572,16 @@ ReturnedValue QQmlTypeWrapper::lookupSingletonProperty(Lookup *l, ExecutionEngin
// 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());
+
+ // The qmlTypeIc check is not strictly necessary.
+ // If we have different ways to get to the same QObject type
+ // we can use the same lookup to get its properties, no matter
+ // how we've found the object. Most of the few times this check
+ // fails, we will, of course have different object types. So
+ // this check provides an early exit for the error case.
+ //
+ // So, if we ever need more bits in qobjectLookup, qmlTypeIc is the
+ // member to be replaced.
if (!o || o->internalClass != l->qobjectLookup.qmlTypeIc)
return revertLookup();
@@ -521,7 +600,42 @@ ReturnedValue QQmlTypeWrapper::lookupSingletonProperty(Lookup *l, ExecutionEngin
Scope scope(engine);
ScopedValue obj(scope, QV4::QObjectWrapper::wrap(engine, qobjectSingleton));
- return QObjectWrapper::lookupGetterImpl(l, engine, obj, /*useOriginalProperty*/ true, revertLookup);
+ const QObjectWrapper::Flags flags = l->forCall
+ ? QObjectWrapper::AllowOverride
+ : (QObjectWrapper::AttachMethods | QObjectWrapper::AllowOverride);
+ return QObjectWrapper::lookupPropertyGetterImpl(l, engine, obj, flags, revertLookup);
+}
+
+ReturnedValue QQmlTypeWrapper::lookupSingletonMethod(Lookup *l, ExecutionEngine *engine, const Value &object)
+{
+ const auto revertLookup = [l, engine, &object]() {
+ l->qobjectMethodLookup.propertyCache->release();
+ l->qobjectMethodLookup.propertyCache = nullptr;
+ l->getter = Lookup::getterGeneric;
+ return Lookup::getterGeneric(l, engine, object);
+ };
+
+ // We cannot safely cast here as we don't explicitly check the IC. Therefore as().
+ const QQmlTypeWrapper *This = object.as<QQmlTypeWrapper>();
+ if (!This)
+ return revertLookup();
+
+ QQmlType type = This->d()->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::lookupMethodGetterImpl(
+ l, engine, obj, l->forCall ? QObjectWrapper::NoFlag : QObjectWrapper::AttachMethods,
+ revertLookup);
}
ReturnedValue QQmlTypeWrapper::lookupEnumValue(Lookup *l, ExecutionEngine *engine, const Value &base)
@@ -539,12 +653,12 @@ ReturnedValue QQmlTypeWrapper::lookupScopedEnum(Lookup *l, ExecutionEngine *engi
{
Scope scope(engine);
Scoped<QQmlScopedEnumWrapper> enumWrapper(scope, static_cast<Heap::QQmlScopedEnumWrapper *>(
- l->qmlScopedEnumWrapperLookup.qmlScopedEnumWrapper));
+ l->qmlScopedEnumWrapperLookup.qmlScopedEnumWrapper.get()));
auto *o = static_cast<Heap::Object *>(base.heapObject());
if (!o || o->internalClass != l->qmlScopedEnumWrapperLookup.ic) {
QQmlType::derefHandle(enumWrapper->d()->typePrivate);
- l->qmlScopedEnumWrapperLookup.qmlScopedEnumWrapper = nullptr;
+ l->qmlScopedEnumWrapperLookup.qmlScopedEnumWrapper.clear();
l->getter = Lookup::getterGeneric;
return Lookup::getterGeneric(l, engine, base);
}
diff --git a/src/qml/qml/qqmltypewrapper_p.h b/src/qml/qml/qqmltypewrapper_p.h
index 595e362a41..717efaf20e 100644
--- a/src/qml/qml/qqmltypewrapper_p.h
+++ b/src/qml/qml/qqmltypewrapper_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QV8TYPEWRAPPER_P_H
#define QV8TYPEWRAPPER_P_H
@@ -74,7 +38,9 @@ struct QQmlTypeWrapper : Object {
ExcludeEnums
};
- void init();
+ void init(TypeNameMode m, QObject *o, const QQmlTypePrivate *type);
+ void init(TypeNameMode m, QObject *o, QQmlTypeNameCache *type, const QQmlImportRef *import);
+
void destroy();
TypeNameMode mode;
QV4QPointer<QObject> object;
@@ -102,6 +68,8 @@ struct Q_QML_EXPORT QQmlTypeWrapper : Object
V4_NEEDS_DESTROY
bool isSingleton() const;
+ const QMetaObject *metaObject() const;
+ QObject *object() const;
QObject *singletonObject() const;
QVariant toVariant() const;
@@ -113,8 +81,11 @@ 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 OwnPropertyKeyIterator *virtualOwnPropertyKeys(const Object *m, Value *target);
+ static int virtualMetacall(Object *object, QMetaObject::Call call, int index, void **a);
static ReturnedValue lookupSingletonProperty(Lookup *l, ExecutionEngine *engine, const Value &base);
+ static ReturnedValue lookupSingletonMethod(Lookup *l, ExecutionEngine *engine, const Value &base);
static ReturnedValue lookupEnumValue(Lookup *l, ExecutionEngine *engine, const Value &base);
static ReturnedValue lookupScopedEnum(Lookup *l, ExecutionEngine *engine, const Value &base);
diff --git a/src/qml/qml/qqmlvaluetype.cpp b/src/qml/qml/qqmlvaluetype.cpp
index e1f56d0d59..4088d6e6c4 100644
--- a/src/qml/qml/qqmlvaluetype.cpp
+++ b/src/qml/qml/qqmlvaluetype.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qqmlvaluetype_p.h"
@@ -47,17 +11,9 @@
QT_BEGIN_NAMESPACE
-QQmlValueType::QQmlValueType(int typeId, const QMetaObject *gadgetMetaObject)
- : metaType(typeId)
-{
- QMetaObjectBuilder builder(gadgetMetaObject);
- dynamicMetaObject = builder.toMetaObject();
- *static_cast<QMetaObject*>(this) = *dynamicMetaObject;
-}
-
QQmlValueType::~QQmlValueType()
{
- ::free(dynamicMetaObject);
+ ::free(m_dynamicMetaObject);
}
QQmlGadgetPtrWrapper *QQmlGadgetPtrWrapper::instance(QQmlEngine *engine, QMetaType type)
@@ -87,33 +43,43 @@ void QQmlGadgetPtrWrapper::read(QObject *obj, int idx)
QMetaObject::metacall(obj, QMetaObject::ReadProperty, idx, a);
}
-void QQmlGadgetPtrWrapper::write(QObject *obj, int idx, QQmlPropertyData::WriteFlags flags)
+void QQmlGadgetPtrWrapper::write(
+ QObject *obj, int idx, QQmlPropertyData::WriteFlags flags, int internalIndex) const
{
Q_ASSERT(m_gadgetPtr);
int status = -1;
- void *a[] = { m_gadgetPtr, nullptr, &status, &flags };
+ void *a[] = { m_gadgetPtr, nullptr, &status, &flags, &internalIndex };
QMetaObject::metacall(obj, QMetaObject::WriteProperty, idx, a);
}
-QVariant QQmlGadgetPtrWrapper::value()
+QVariant QQmlGadgetPtrWrapper::value() const
{
Q_ASSERT(m_gadgetPtr);
- return QVariant(QMetaType(metaTypeId()), m_gadgetPtr);
+
+ const QMetaType m = metaType();
+ return m == QMetaType::fromType<QVariant>()
+ ? *static_cast<const QVariant *>(m_gadgetPtr)
+ : QVariant(m, m_gadgetPtr);
}
void QQmlGadgetPtrWrapper::setValue(const QVariant &value)
{
Q_ASSERT(m_gadgetPtr);
- Q_ASSERT(metaTypeId() == value.userType());
- const QQmlValueType *type = valueType();
- type->destruct(m_gadgetPtr);
- type->construct(m_gadgetPtr, value.constData());
+
+ const QMetaType m = metaType();
+ m.destruct(m_gadgetPtr);
+ if (m == QMetaType::fromType<QVariant>()) {
+ m.construct(m_gadgetPtr, &value);
+ } else {
+ Q_ASSERT(m == value.metaType());
+ m.construct(m_gadgetPtr, value.constData());
+ }
}
int QQmlGadgetPtrWrapper::metaCall(QMetaObject::Call type, int id, void **argv)
{
Q_ASSERT(m_gadgetPtr);
- const QMetaObject *metaObject = valueType();
+ const QMetaObject *metaObject = valueType()->staticMetaObject();
QQmlMetaObject::resolveGadgetMethodOrPropertyIndex(type, &metaObject, &id);
metaObject->d.static_metacall(static_cast<QObject *>(m_gadgetPtr), type, id, argv);
return id;
@@ -125,9 +91,18 @@ const QQmlValueType *QQmlGadgetPtrWrapper::valueType() const
return static_cast<const QQmlValueType *>(d->metaObject);
}
-QAbstractDynamicMetaObject *QQmlValueType::toDynamicMetaObject(QObject *)
+QMetaObject *QQmlValueType::toDynamicMetaObject(QObject *)
{
- return this;
+ if (!m_dynamicMetaObject) {
+ QMetaObjectBuilder builder(m_staticMetaObject);
+
+ // Do not set PropertyAccessInStaticMetaCall here. QQmlGadgetPtrWrapper likes to
+ // to intercept the metacalls since it needs to use its gadgetPtr.
+ // For QQmlValueType::metaObject() we use the base type that has the flag.
+
+ m_dynamicMetaObject = builder.toMetaObject();
+ }
+ return m_dynamicMetaObject;
}
void QQmlValueType::objectDestroyed(QObject *)
@@ -419,7 +394,7 @@ void QQmlEasingValueType::setBezierCurve(const QVariantList &customCurveVariant)
if (customCurveVariant.isEmpty())
return;
- if ((customCurveVariant.count() % 6) != 0)
+ if ((customCurveVariant.size() % 6) != 0)
return;
auto convert = [](const QVariant &v, qreal &r) {
@@ -448,16 +423,6 @@ void QQmlEasingValueType::setBezierCurve(const QVariantList &customCurveVariant)
v = newEasingCurve;
}
-QObject *QQmlPropertyValueType::object() const
-{
- return v.object();
-}
-
-QString QQmlPropertyValueType::name() const
-{
- return v.name();
-}
-
QVariantList QQmlEasingValueType::bezierCurve() const
{
QVariantList rv;
diff --git a/src/qml/qml/qqmlvaluetype_p.h b/src/qml/qml/qqmlvaluetype_p.h
index 632405f315..8815c914ce 100644
--- a/src/qml/qml/qqmlvaluetype_p.h
+++ b/src/qml/qml/qqmlvaluetype_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLVALUETYPE_P_H
#define QQMLVALUETYPE_P_H
@@ -51,12 +15,11 @@
// We mean it.
//
-#include "qqml.h"
-#include "qqmlproperty.h"
-#include "qqmlproperty_p.h"
+#include <QtQml/private/qqmlproperty_p.h>
#include <private/qqmlnullablevalue_p.h>
#include <private/qmetatype_p.h>
+#include <private/qv4referenceobject_p.h>
#include <QtCore/qobject.h>
#include <QtCore/qrect.h>
@@ -67,57 +30,80 @@
QT_BEGIN_NAMESPACE
-class Q_QML_PRIVATE_EXPORT QQmlValueType : public QAbstractDynamicMetaObject
+class Q_QML_EXPORT QQmlValueType : public QDynamicMetaObjectData
{
public:
- QQmlValueType() : metaType(QMetaType::UnknownType) {}
- QQmlValueType(int userType, const QMetaObject *metaObject);
+ QQmlValueType() = default;
+ QQmlValueType(QMetaType type, const QMetaObject *staticMetaObject)
+ : m_metaType(type), m_staticMetaObject(staticMetaObject)
+ {}
~QQmlValueType();
- void *create() const { return metaType.create(); }
- void destroy(void *gadgetPtr) const { metaType.destroy(gadgetPtr); }
+ void *create() const { return m_metaType.create(); }
+ void destroy(void *gadgetPtr) const { m_metaType.destroy(gadgetPtr); }
- void construct(void *gadgetPtr, const void *copy) const { metaType.construct(gadgetPtr, copy); }
- void destruct(void *gadgetPtr) const { metaType.destruct(gadgetPtr); }
+ void construct(void *gadgetPtr, const void *copy) const { m_metaType.construct(gadgetPtr, copy); }
+ void destruct(void *gadgetPtr) const { m_metaType.destruct(gadgetPtr); }
- int metaTypeId() const { return metaType.id(); }
+ QMetaType metaType() const { return m_metaType; }
+ const QMetaObject *staticMetaObject() const { return m_staticMetaObject; }
// ---- dynamic meta object data interface
- QAbstractDynamicMetaObject *toDynamicMetaObject(QObject *) override;
+ QMetaObject *toDynamicMetaObject(QObject *) override;
void objectDestroyed(QObject *) override;
int metaCall(QObject *obj, QMetaObject::Call type, int _id, void **argv) override;
// ----
-public:
- QMetaType metaType;
- QMetaObject *dynamicMetaObject = nullptr;
+private:
+ QMetaType m_metaType;
+ const QMetaObject *m_staticMetaObject = nullptr;
+ QMetaObject *m_dynamicMetaObject = nullptr;
};
-class Q_QML_PRIVATE_EXPORT QQmlGadgetPtrWrapper : public QObject
+class Q_QML_EXPORT QQmlGadgetPtrWrapper : public QObject
{
Q_OBJECT
public:
static QQmlGadgetPtrWrapper *instance(QQmlEngine *engine, QMetaType type);
- QQmlGadgetPtrWrapper(QQmlValueType *valueType, QObject *parent);
+ QQmlGadgetPtrWrapper(QQmlValueType *valueType, QObject *parent = nullptr);
~QQmlGadgetPtrWrapper();
void read(QObject *obj, int idx);
- void write(QObject *obj, int idx, QQmlPropertyData::WriteFlags flags);
- QVariant value();
+ void write(QObject *obj, int idx, QQmlPropertyData::WriteFlags flags,
+ int internalIndex = QV4::ReferenceObject::AllProperties) const;
+ QVariant value() const;
void setValue(const QVariant &value);
- int metaTypeId() const { return valueType()->metaTypeId(); }
+ QMetaType metaType() const { return valueType()->metaType(); }
int metaCall(QMetaObject::Call type, int id, void **argv);
- QMetaProperty property(int index) { return valueType()->property(index); }
+
+ QMetaProperty property(int index) const
+ {
+ return valueType()->staticMetaObject()->property(index);
+ }
+
+ QVariant readOnGadget(const QMetaProperty &property) const
+ {
+ return property.readOnGadget(m_gadgetPtr);
+ }
+
+ void writeOnGadget(const QMetaProperty &property, const QVariant &value)
+ {
+ property.writeOnGadget(m_gadgetPtr, value);
+ }
+
+ void writeOnGadget(const QMetaProperty &property, QVariant &&value)
+ {
+ property.writeOnGadget(m_gadgetPtr, std::move(value));
+ }
private:
const QQmlValueType *valueType() const;
-
void *m_gadgetPtr = nullptr;
};
-struct Q_QML_PRIVATE_EXPORT QQmlPointFValueType
+struct Q_QML_EXPORT QQmlPointFValueType
{
QPointF v;
Q_PROPERTY(qreal x READ x WRITE setX FINAL)
@@ -127,16 +113,21 @@ struct Q_QML_PRIVATE_EXPORT QQmlPointFValueType
QML_FOREIGN(QPointF)
QML_ADDED_IN_VERSION(2, 0)
QML_EXTENDED(QQmlPointFValueType)
+ QML_STRUCTURED_VALUE
public:
+ QQmlPointFValueType() = default;
+ Q_INVOKABLE QQmlPointFValueType(const QPoint &point) : v(point) {}
Q_INVOKABLE QString toString() const;
qreal x() const;
qreal y() const;
void setX(qreal);
void setY(qreal);
+
+ operator QPointF() const { return v; }
};
-struct Q_QML_PRIVATE_EXPORT QQmlPointValueType
+struct Q_QML_EXPORT QQmlPointValueType
{
QPoint v;
Q_PROPERTY(int x READ x WRITE setX FINAL)
@@ -146,16 +137,21 @@ struct Q_QML_PRIVATE_EXPORT QQmlPointValueType
QML_FOREIGN(QPoint)
QML_ADDED_IN_VERSION(2, 0)
QML_EXTENDED(QQmlPointValueType)
+ QML_STRUCTURED_VALUE
public:
+ QQmlPointValueType() = default;
+ Q_INVOKABLE QQmlPointValueType(const QPointF &point) : v(point.toPoint()) {}
Q_INVOKABLE QString toString() const;
int x() const;
int y() const;
void setX(int);
void setY(int);
+
+ operator QPoint() const { return v; }
};
-struct Q_QML_PRIVATE_EXPORT QQmlSizeFValueType
+struct Q_QML_EXPORT QQmlSizeFValueType
{
QSizeF v;
Q_PROPERTY(qreal width READ width WRITE setWidth FINAL)
@@ -165,16 +161,21 @@ struct Q_QML_PRIVATE_EXPORT QQmlSizeFValueType
QML_FOREIGN(QSizeF)
QML_ADDED_IN_VERSION(2, 0)
QML_EXTENDED(QQmlSizeFValueType)
+ QML_STRUCTURED_VALUE
public:
+ QQmlSizeFValueType() = default;
+ Q_INVOKABLE QQmlSizeFValueType(const QSize &size) : v(size) {}
Q_INVOKABLE QString toString() const;
qreal width() const;
qreal height() const;
void setWidth(qreal);
void setHeight(qreal);
+
+ operator QSizeF() const { return v; }
};
-struct Q_QML_PRIVATE_EXPORT QQmlSizeValueType
+struct Q_QML_EXPORT QQmlSizeValueType
{
QSize v;
Q_PROPERTY(int width READ width WRITE setWidth FINAL)
@@ -184,16 +185,21 @@ struct Q_QML_PRIVATE_EXPORT QQmlSizeValueType
QML_FOREIGN(QSize)
QML_ADDED_IN_VERSION(2, 0)
QML_EXTENDED(QQmlSizeValueType)
+ QML_STRUCTURED_VALUE
public:
+ QQmlSizeValueType() = default;
+ Q_INVOKABLE QQmlSizeValueType(const QSizeF &size) : v(size.toSize()) {}
Q_INVOKABLE QString toString() const;
int width() const;
int height() const;
void setWidth(int);
void setHeight(int);
+
+ operator QSize() const { return v; }
};
-struct Q_QML_PRIVATE_EXPORT QQmlRectFValueType
+struct Q_QML_EXPORT QQmlRectFValueType
{
QRectF v;
Q_PROPERTY(qreal x READ x WRITE setX FINAL)
@@ -209,8 +215,11 @@ struct Q_QML_PRIVATE_EXPORT QQmlRectFValueType
QML_FOREIGN(QRectF)
QML_ADDED_IN_VERSION(2, 0)
QML_EXTENDED(QQmlRectFValueType)
+ QML_STRUCTURED_VALUE
public:
+ QQmlRectFValueType() = default;
+ Q_INVOKABLE QQmlRectFValueType(const QRect &rect) : v(rect) {}
Q_INVOKABLE QString toString() const;
qreal x() const;
qreal y() const;
@@ -226,9 +235,11 @@ public:
qreal right() const;
qreal top() const;
qreal bottom() const;
+
+ operator QRectF() const { return v; }
};
-struct Q_QML_PRIVATE_EXPORT QQmlRectValueType
+struct Q_QML_EXPORT QQmlRectValueType
{
QRect v;
Q_PROPERTY(int x READ x WRITE setX FINAL)
@@ -244,8 +255,11 @@ struct Q_QML_PRIVATE_EXPORT QQmlRectValueType
QML_FOREIGN(QRect)
QML_ADDED_IN_VERSION(2, 0)
QML_EXTENDED(QQmlRectValueType)
+ QML_STRUCTURED_VALUE
public:
+ QQmlRectValueType() = default;
+ Q_INVOKABLE QQmlRectValueType(const QRectF &rect) : v(rect.toRect()) {}
Q_INVOKABLE QString toString() const;
int x() const;
int y() const;
@@ -261,12 +275,14 @@ public:
int right() const;
int top() const;
int bottom() const;
+
+ operator QRect() const { return v; }
};
#if QT_CONFIG(easingcurve)
namespace QQmlEasingEnums
{
-Q_NAMESPACE
+Q_NAMESPACE_EXPORT(Q_QML_EXPORT)
QML_NAMED_ELEMENT(Easing)
QML_ADDED_IN_VERSION(2, 0)
@@ -301,7 +317,7 @@ enum Type {
Q_ENUM_NS(Type)
};
-struct Q_QML_PRIVATE_EXPORT QQmlEasingValueType
+struct Q_QML_EXPORT QQmlEasingValueType
{
QEasingCurve v;
Q_GADGET
@@ -309,6 +325,7 @@ struct Q_QML_PRIVATE_EXPORT QQmlEasingValueType
QML_FOREIGN(QEasingCurve)
QML_ADDED_IN_VERSION(2, 0)
QML_EXTENDED(QQmlEasingValueType)
+ QML_STRUCTURED_VALUE
Q_PROPERTY(QQmlEasingEnums::Type type READ type WRITE setType FINAL)
Q_PROPERTY(qreal amplitude READ amplitude WRITE setAmplitude FINAL)
@@ -327,23 +344,17 @@ public:
void setPeriod(qreal);
void setBezierCurve(const QVariantList &);
QVariantList bezierCurve() const;
+
+ operator QEasingCurve() const { return v; }
};
#endif
-struct Q_QML_PRIVATE_EXPORT QQmlPropertyValueType
+struct QQmlV4ExecutionEnginePtrForeign
{
- QQmlProperty v;
- Q_PROPERTY(QObject *object READ object CONSTANT FINAL)
- Q_PROPERTY(QString name READ name CONSTANT FINAL)
Q_GADGET
QML_ANONYMOUS
- QML_FOREIGN(QQmlProperty)
- QML_ADDED_IN_VERSION(2, 15)
- QML_EXTENDED(QQmlPropertyValueType)
-
-public:
- QObject *object() const;
- QString name() const;
+ QML_FOREIGN(QQmlV4ExecutionEnginePtr)
+ QML_EXTENDED(QQmlV4ExecutionEnginePtrForeign)
};
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlvaluetypeproxybinding.cpp b/src/qml/qml/qqmlvaluetypeproxybinding.cpp
index d5cff26444..a1cf9f802b 100644
--- a/src/qml/qml/qqmlvaluetypeproxybinding.cpp
+++ b/src/qml/qml/qqmlvaluetypeproxybinding.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qqmlvaluetypeproxybinding_p.h"
@@ -67,11 +31,6 @@ void QQmlValueTypeProxyBinding::setEnabled(bool e, QQmlPropertyData::WriteFlags
}
}
-bool QQmlValueTypeProxyBinding::isValueTypeProxy() const
-{
- return true;
-}
-
QQmlAbstractBinding *QQmlValueTypeProxyBinding::subBindings() const
{
return m_bindings.data();
diff --git a/src/qml/qml/qqmlvaluetypeproxybinding_p.h b/src/qml/qml/qqmlvaluetypeproxybinding_p.h
index 35b54c339b..79cb935e94 100644
--- a/src/qml/qml/qqmlvaluetypeproxybinding_p.h
+++ b/src/qml/qml/qqmlvaluetypeproxybinding_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLVALUETYPEPROXYBINDING_P_H
#define QQMLVALUETYPEPROXYBINDING_P_H
@@ -65,7 +29,7 @@ public:
void removeBindings(quint32 mask);
void setEnabled(bool, QQmlPropertyData::WriteFlags) override;
- bool isValueTypeProxy() const override;
+ Kind kind() const final { return QQmlAbstractBinding::ValueTypeProxy; }
protected:
~QQmlValueTypeProxyBinding();
diff --git a/src/qml/qml/qqmlvaluetypewrapper.cpp b/src/qml/qml/qqmlvaluetypewrapper.cpp
index 1b3034d5d9..7075d0f5f6 100644
--- a/src/qml/qml/qqmlvaluetypewrapper.cpp
+++ b/src/qml/qml/qqmlvaluetypewrapper.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qqmlvaluetypewrapper_p.h"
@@ -53,11 +17,23 @@
#include <private/qv4qobjectwrapper_p.h>
#include <private/qv4identifiertable_p.h>
#include <private/qv4lookup_p.h>
+#include <private/qv4sequenceobject_p.h>
+#include <private/qv4arraybuffer_p.h>
+#include <private/qv4dateobject_p.h>
+#include <private/qv4jsonobject_p.h>
+#if QT_CONFIG(regularexpression)
+#include <private/qv4regexpobject_p.h>
+#endif
+#if QT_CONFIG(qml_locale)
+#include <private/qqmllocale_p.h>
+#endif
#include <QtCore/qloggingcategory.h>
+#include <QtCore/qdatetime.h>
#include <QtCore/QLine>
#include <QtCore/QLineF>
#include <QtCore/QSize>
#include <QtCore/QSizeF>
+#include <QtCore/QTimeZone>
QT_BEGIN_NAMESPACE
@@ -66,112 +42,95 @@ Q_DECLARE_LOGGING_CATEGORY(lcBindingRemoval)
DEFINE_OBJECT_VTABLE(QV4::QQmlValueTypeWrapper);
namespace QV4 {
-namespace Heap {
-struct QQmlValueTypeReference : QQmlValueTypeWrapper
+Heap::QQmlValueTypeWrapper *Heap::QQmlValueTypeWrapper::detached() const
{
- void init() {
- QQmlValueTypeWrapper::init();
- object.init();
- }
- void destroy() {
- object.destroy();
- QQmlValueTypeWrapper::destroy();
- }
- QV4QPointer<QObject> object;
- int property;
-};
-
-}
-
-struct QQmlValueTypeReference : public QQmlValueTypeWrapper
-{
- V4_OBJECT2(QQmlValueTypeReference, QQmlValueTypeWrapper)
- V4_NEEDS_DESTROY
-
- bool readReferenceValue() const;
-};
-
+ return internalClass->engine->memoryManager->allocate<QV4::QQmlValueTypeWrapper>(
+ m_gadgetPtr, QMetaType(m_metaType), m_metaObject, nullptr, -1, NoFlag);
}
-DEFINE_OBJECT_VTABLE(QV4::QQmlValueTypeReference);
-
-using namespace QV4;
-
void Heap::QQmlValueTypeWrapper::destroy()
{
if (m_gadgetPtr) {
- m_valueType->metaType.destruct(m_gadgetPtr);
+ metaType().destruct(m_gadgetPtr);
::operator delete(m_gadgetPtr);
}
- Object::destroy();
-}
-
-void Heap::QQmlValueTypeWrapper::setValue(const QVariant &value) const
-{
- Q_ASSERT(valueType()->metaType.id() == value.userType());
- if (auto *gadget = gadgetPtr())
- valueType()->metaType.destruct(gadget);
- if (!gadgetPtr())
- setGadgetPtr(::operator new(valueType()->metaType.sizeOf()));
- valueType()->metaType.construct(gadgetPtr(), value.constData());
+ ReferenceObject::destroy();
}
QVariant Heap::QQmlValueTypeWrapper::toVariant() const
{
Q_ASSERT(gadgetPtr());
- return QVariant(valueType()->metaType, gadgetPtr());
+ return QVariant(metaType(), gadgetPtr());
}
-
-bool QQmlValueTypeReference::readReferenceValue() const
+bool Heap::QQmlValueTypeWrapper::setVariant(const QVariant &variant)
{
- if (!d()->object)
- return false;
- // A reference resource may be either a "true" reference (eg, to a QVector3D property)
- // or a "variant" reference (eg, to a QVariant property which happens to contain a value-type).
- QMetaProperty writebackProperty = d()->object->metaObject()->property(d()->property);
- if (writebackProperty.userType() == QMetaType::QVariant) {
- // variant-containing-value-type reference
- QVariant variantReferenceValue;
-
- void *a[] = { &variantReferenceValue, nullptr };
- QMetaObject::metacall(d()->object, QMetaObject::ReadProperty, d()->property, a);
-
- const QMetaType variantReferenceType = variantReferenceValue.metaType();
- if (variantReferenceType != type()) {
- // This is a stale VariantReference. That is, the variant has been
- // overwritten with a different type in the meantime.
- // We need to modify this reference to the updated value type, if
- // possible, or return false if it is not a value type.
- if (QQmlMetaType::isValueType(variantReferenceType)) {
- const QMetaObject *mo = QQmlMetaType::metaObjectForMetaType(variantReferenceType);
- if (d()->gadgetPtr()) {
- d()->valueType()->metaType.destruct(d()->gadgetPtr());
- ::operator delete(d()->gadgetPtr());
- }
- d()->setGadgetPtr(nullptr);
- d()->setMetaObject(mo);
- d()->setValueType(QQmlMetaType::valueType(variantReferenceType));
- if (!mo)
- return false;
- } else {
- return false;
+ Q_ASSERT(isVariant());
+
+ const QMetaType variantReferenceType = variant.metaType();
+ if (variantReferenceType != metaType()) {
+ // This is a stale VariantReference. That is, the variant has been
+ // overwritten with a different type in the meantime.
+ // We need to modify this reference to the updated value type, if
+ // possible, or return false if it is not a value type.
+ if (QQmlMetaType::isValueType(variantReferenceType)) {
+ const QMetaObject *mo = QQmlMetaType::metaObjectForValueType(variantReferenceType);
+ if (gadgetPtr()) {
+ metaType().destruct(gadgetPtr());
+ ::operator delete(gadgetPtr());
}
+ setGadgetPtr(nullptr);
+ setMetaObject(mo);
+ setMetaType(variantReferenceType);
+ if (!mo)
+ return false;
+ } else {
+ return false;
}
- d()->setValue(variantReferenceValue);
- } else {
- if (!d()->gadgetPtr()) {
- d()->setGadgetPtr(::operator new(d()->valueType()->metaType.sizeOf()));
- d()->valueType()->metaType.construct(d()->gadgetPtr(), nullptr);
- }
- // value-type reference
- void *args[] = { d()->gadgetPtr(), nullptr };
- QMetaObject::metacall(d()->object, QMetaObject::ReadProperty, d()->property, args);
}
+
+ setData(variant.constData());
return true;
}
+void *Heap::QQmlValueTypeWrapper::storagePointer()
+{
+ if (!gadgetPtr()) {
+ setGadgetPtr(::operator new(metaType().sizeOf()));
+ metaType().construct(gadgetPtr(), nullptr);
+ }
+ return gadgetPtr();
+}
+
+bool Heap::QQmlValueTypeWrapper::readReference()
+{
+ // If locations are enforced we only read once
+ return enforcesLocation() || QV4::ReferenceObject::readReference(this);
+}
+
+bool Heap::QQmlValueTypeWrapper::writeBack(int propertyIndex)
+{
+ return isAttachedToProperty() && QV4::ReferenceObject::writeBack(this, propertyIndex);
+}
+
+ReturnedValue QQmlValueTypeWrapper::create(
+ ExecutionEngine *engine, Heap::QQmlValueTypeWrapper *cloneFrom, Heap::Object *object)
+{
+ QV4::Scope scope(engine);
+ initProto(engine);
+
+ // Either we're enforcing the location, then we have to read right away.
+ // Or we don't then we lazy-load. In neither case we pass any data.
+ Scoped<QQmlValueTypeWrapper> r(scope, engine->memoryManager->allocate<QQmlValueTypeWrapper>(
+ nullptr, cloneFrom->metaType(), cloneFrom->metaObject(),
+ object, cloneFrom->property(), cloneFrom->flags()));
+ r->d()->setLocation(cloneFrom->function(), cloneFrom->statementIndex());
+ if (cloneFrom->enforcesLocation())
+ QV4::ReferenceObject::readReference(r->d());
+ return r->asReturnedValue();
+}
+
void QQmlValueTypeWrapper::initProto(ExecutionEngine *v4)
{
if (v4->valueTypeWrapperPrototype()->d_unchecked())
@@ -183,59 +142,103 @@ void QQmlValueTypeWrapper::initProto(ExecutionEngine *v4)
v4->jsObjects[QV4::ExecutionEngine::ValueTypeProto] = o->d();
}
-ReturnedValue QQmlValueTypeWrapper::create(ExecutionEngine *engine, QObject *object, int property, const QMetaObject *metaObject, QMetaType type)
+int QQmlValueTypeWrapper::virtualMetacall(
+ Object *object, QMetaObject::Call call, int index, void **a)
+{
+ QQmlValueTypeWrapper *wrapper = object->as<QQmlValueTypeWrapper>();
+ Q_ASSERT(wrapper);
+
+ switch (call) {
+ case QMetaObject::InvokeMetaMethod:
+ case QMetaObject::ReadProperty:
+ case QMetaObject::BindableProperty:
+ case QMetaObject::CustomCall:
+ if (wrapper->d()->object())
+ wrapper->d()->readReference();
+ break;
+ default:
+ break;
+ }
+
+ const QMetaObject *mo = wrapper->d()->metaObject();
+ if (!mo->d.static_metacall)
+ return 0;
+
+ mo->d.static_metacall(static_cast<QObject *>(wrapper->d()->gadgetPtr()), call, index, a);
+
+ switch (call) {
+ case QMetaObject::ReadProperty:
+ break;
+ case QMetaObject::WriteProperty:
+ case QMetaObject::ResetProperty:
+ if (wrapper->d()->object())
+ wrapper->d()->writeBack(index);
+ break;
+ case QMetaObject::InvokeMetaMethod:
+ case QMetaObject::CustomCall:
+ if (wrapper->d()->object())
+ wrapper->d()->writeBack();
+ break;
+ default:
+ break;
+ }
+
+ return -1;
+}
+
+ReturnedValue QQmlValueTypeWrapper::create(
+ ExecutionEngine *engine, const void *data, const QMetaObject *metaObject, QMetaType type,
+ Heap::Object *object, int property, Heap::ReferenceObject::Flags flags)
{
Scope scope(engine);
initProto(engine);
- Scoped<QQmlValueTypeReference> r(scope, engine->memoryManager->allocate<QQmlValueTypeReference>());
- r->d()->object = object;
- r->d()->property = property;
- r->d()->setMetaObject(metaObject);
- auto valueType = QQmlMetaType::valueType(type);
- if (!valueType) {
+ if (!type.isValid()) {
return engine->throwTypeError(QLatin1String("Type %1 is not a value type")
.arg(QString::fromUtf8(type.name())));
}
- r->d()->setValueType(valueType);
- r->d()->setGadgetPtr(nullptr);
+
+ // If data is given explicitly, we assume it has just been read from the property
+ Scoped<QQmlValueTypeWrapper> r(scope, engine->memoryManager->allocate<QQmlValueTypeWrapper>(
+ data, type, metaObject, object, property, flags));
+ if (CppStackFrame *frame = engine->currentStackFrame)
+ r->d()->setLocation(frame->v4Function, frame->statementNumber());
+ if (!data && r->d()->enforcesLocation())
+ QV4::ReferenceObject::readReference(r->d());
return r->asReturnedValue();
}
-ReturnedValue QQmlValueTypeWrapper::create(ExecutionEngine *engine, const QVariant &value, const QMetaObject *metaObject, QMetaType type)
+ReturnedValue QQmlValueTypeWrapper::create(
+ ExecutionEngine *engine, const void *data, const QMetaObject *metaObject, QMetaType type)
{
Scope scope(engine);
initProto(engine);
- Scoped<QQmlValueTypeWrapper> r(scope, engine->memoryManager->allocate<QQmlValueTypeWrapper>());
- r->d()->setMetaObject(metaObject);
- auto valueType = QQmlMetaType::valueType(type);
- if (!valueType) {
+ if (!type.isValid()) {
return engine->throwTypeError(QLatin1String("Type %1 is not a value type")
.arg(QString::fromUtf8(type.name())));
}
- r->d()->setValueType(valueType);
- r->d()->setGadgetPtr(nullptr);
- r->d()->setValue(value);
+
+ Scoped<QQmlValueTypeWrapper> r(
+ scope, engine->memoryManager->allocate<QQmlValueTypeWrapper>(
+ data, type, metaObject, nullptr, -1, Heap::ReferenceObject::NoFlag));
return r->asReturnedValue();
}
QVariant QQmlValueTypeWrapper::toVariant() const
{
- if (const QQmlValueTypeReference *ref = as<const QQmlValueTypeReference>())
- if (!ref->readReferenceValue())
- return QVariant();
+ if (d()->isReference() && !readReferenceValue())
+ return QVariant();
return d()->toVariant();
}
bool QQmlValueTypeWrapper::toGadget(void *data) const
{
- if (const QQmlValueTypeReference *ref = as<const QQmlValueTypeReference>())
- if (!ref->readReferenceValue())
- return false;
- const int typeId = d()->valueType()->metaType.id();
- QMetaType(typeId).destruct(data);
- QMetaType(typeId).construct(data, d()->gadgetPtr());
+ if (d()->isReference() && !readReferenceValue())
+ return false;
+ const QMetaType type = d()->metaType();
+ type.destruct(data);
+ type.construct(data, d()->gadgetPtr());
return true;
}
@@ -253,6 +256,48 @@ bool QQmlValueTypeWrapper::virtualIsEqualTo(Managed *m, Managed *other)
return false;
}
+bool QQmlValueTypeWrapper::virtualHasProperty(const Managed *m, PropertyKey id)
+{
+ if (!id.isString())
+ return Object::virtualHasProperty(m, id);
+ Q_ASSERT(m && m->as<QQmlValueTypeWrapper>());
+ auto wrapper = static_cast<const QQmlValueTypeWrapper *>(m);
+ if (auto mo = wrapper->d()->metaObject())
+ if (mo->indexOfProperty(id.toQString().toUtf8()) != -1)
+ return true;
+
+ /* we don't want to fallback to QObject::virtualHasProperty
+ as that would end up calling getOwnProperty which is wasteful,
+ as it calls our own virtualGetOwnProperty.
+ As we know that our own properties are only those found on the meta-object,
+ we can instead skip the call, and simply check whether the property exists
+ on the prototype.
+ */
+ Scope scope(m->engine());
+ ScopedObject o(scope, m);
+ o = o->getPrototypeOf();
+ if (o)
+ return o->hasProperty(id);
+
+ return false;
+}
+
+static Heap::ReferenceObject::Flags referenceFlags(const QMetaObject *metaObject, int index)
+{
+ return metaObject->property(index).isWritable()
+ ? (Heap::ReferenceObject::CanWriteBack | Heap::ReferenceObject::EnforcesLocation)
+ : Heap::ReferenceObject::EnforcesLocation;
+}
+
+static void doStaticReadCall(
+ const QMetaObject *metaObject, Heap::QQmlValueTypeWrapper *valueTypeWrapper,
+ int index, void **args)
+{
+ metaObject->d.static_metacall(
+ reinterpret_cast<QObject*>(
+ valueTypeWrapper->gadgetPtr()), QMetaObject::ReadProperty, index, args);
+}
+
static ReturnedValue getGadgetProperty(ExecutionEngine *engine,
Heap::QQmlValueTypeWrapper *valueTypeWrapper,
QMetaType metaType, quint16 coreIndex, bool isFunction, bool isEnum)
@@ -261,35 +306,114 @@ static ReturnedValue getGadgetProperty(ExecutionEngine *engine,
// calling a Q_INVOKABLE function of a value type
return QV4::QObjectMethod::create(engine->rootContext(), valueTypeWrapper, coreIndex);
}
+
+ const QMetaObject *metaObject = valueTypeWrapper->metaObject();
+ int index = coreIndex;
+
+ const auto wrapChar16 = [engine](char16_t c) {
+ return engine->newString(QChar(c));
+ };
+ const auto wrapQObject = [engine](QObject *object) {
+ return QObjectWrapper::wrap(engine, object);
+ };
+ const auto wrapJsonValue = [engine](const QJsonValue &value) {
+ return JsonObject::fromJsonValue(engine, value);
+ };
+ const auto wrapJsonObject = [engine](const QJsonObject &object) {
+ return JsonObject::fromJsonObject(engine, object);
+ };
+ const auto wrapJsonArray = [engine](const QJsonArray &array) {
+ return JsonObject::fromJsonArray(engine, array);
+ };
+
+ const auto wrapQDateTime = [&](const QDateTime &dateTime) {
+ return engine->newDateObject(
+ dateTime, valueTypeWrapper, index, referenceFlags(metaObject, index));
+ };
+ const auto wrapQDate = [&](QDate date) {
+ return engine->newDateObject(
+ date, valueTypeWrapper, index, referenceFlags(metaObject, index));
+ };
+ const auto wrapQTime = [&](QTime time) {
+ return engine->newDateObject(
+ time, valueTypeWrapper, index, referenceFlags(metaObject, index));
+ };
+
#define VALUE_TYPE_LOAD(metatype, cpptype, constructor) \
- if (metaTypeId == metatype) { \
+ case metatype: { \
cpptype v; \
void *args[] = { &v, nullptr }; \
- metaObject->d.static_metacall(reinterpret_cast<QObject*>(valueTypeWrapper->gadgetPtr()), \
- QMetaObject::ReadProperty, index, args); \
+ doStaticReadCall(metaObject, valueTypeWrapper, index, args); \
return QV4::Encode(constructor(v)); \
}
- const QMetaObject *metaObject = valueTypeWrapper->metaObject();
- int index = coreIndex;
- QQmlMetaObject::resolveGadgetMethodOrPropertyIndex(QMetaObject::ReadProperty, &metaObject, &index);
- // These four types are the most common used by the value type wrappers
- int metaTypeId = metaType.id();
+
+ QQmlMetaObject::resolveGadgetMethodOrPropertyIndex(
+ QMetaObject::ReadProperty, &metaObject, &index);
+
+ const int metaTypeId = isEnum
+ ? metaType.underlyingType().id()
+ : (metaType.flags() & QMetaType::PointerToQObject)
+ ? QMetaType::QObjectStar
+ : metaType.id();
+
+ switch (metaTypeId) {
+ case QMetaType::UnknownType:
+ case QMetaType::Void:
+ return Encode::undefined();
+ case QMetaType::Nullptr:
+ case QMetaType::VoidStar:
+ return Encode::null();
+ VALUE_TYPE_LOAD(QMetaType::Bool, bool, bool);
+ VALUE_TYPE_LOAD(QMetaType::Int, int, int);
+ VALUE_TYPE_LOAD(QMetaType::UInt, uint, uint);
+ VALUE_TYPE_LOAD(QMetaType::Long, long, double);
+ VALUE_TYPE_LOAD(QMetaType::ULong, ulong, double);
+ VALUE_TYPE_LOAD(QMetaType::LongLong, qlonglong, double);
+ VALUE_TYPE_LOAD(QMetaType::ULongLong, qulonglong, double);
VALUE_TYPE_LOAD(QMetaType::Double, double, double);
- VALUE_TYPE_LOAD(QMetaType::Float, float, float);
- VALUE_TYPE_LOAD(QMetaType::Int || isEnum, int, int);
VALUE_TYPE_LOAD(QMetaType::QString, QString, engine->newString);
- VALUE_TYPE_LOAD(QMetaType::Bool, bool, bool);
- QVariant v;
- void *args[] = { nullptr, nullptr };
- if (metaType == QMetaType::fromType<QVariant>()) {
- args[0] = &v;
- } else {
- v = QVariant(metaType, static_cast<void *>(nullptr));
- args[0] = v.data();
+ VALUE_TYPE_LOAD(QMetaType::QByteArray, QByteArray, engine->newArrayBuffer);
+ VALUE_TYPE_LOAD(QMetaType::Float, float, float);
+ VALUE_TYPE_LOAD(QMetaType::Short, short, int);
+ VALUE_TYPE_LOAD(QMetaType::UShort, unsigned short, int);
+ VALUE_TYPE_LOAD(QMetaType::Char, char, int);
+ VALUE_TYPE_LOAD(QMetaType::UChar, unsigned char, int);
+ VALUE_TYPE_LOAD(QMetaType::SChar, signed char, int);
+ VALUE_TYPE_LOAD(QMetaType::QChar, QChar, engine->newString);
+ VALUE_TYPE_LOAD(QMetaType::Char16, char16_t, wrapChar16);
+ VALUE_TYPE_LOAD(QMetaType::QDateTime, QDateTime, wrapQDateTime);
+ VALUE_TYPE_LOAD(QMetaType::QDate, QDate, wrapQDate);
+ VALUE_TYPE_LOAD(QMetaType::QTime, QTime, wrapQTime);
+#if QT_CONFIG(regularexpression)
+ VALUE_TYPE_LOAD(QMetaType::QRegularExpression, QRegularExpression, engine->newRegExpObject);
+#endif
+ VALUE_TYPE_LOAD(QMetaType::QObjectStar, QObject*, wrapQObject);
+ VALUE_TYPE_LOAD(QMetaType::QJsonValue, QJsonValue, wrapJsonValue);
+ VALUE_TYPE_LOAD(QMetaType::QJsonObject, QJsonObject, wrapJsonObject);
+ VALUE_TYPE_LOAD(QMetaType::QJsonArray, QJsonArray, wrapJsonArray);
+ case QMetaType::QPixmap:
+ case QMetaType::QImage: {
+ QVariant v(metaType);
+ void *args[] = { v.data(), nullptr };
+ doStaticReadCall(metaObject, valueTypeWrapper, index, args);
+ return Encode(engine->newVariantObject(metaType, v.data()));
+ }
+ case QMetaType::QVariant: {
+ QVariant v;
+ void *args[] = { &v, nullptr };
+ doStaticReadCall(metaObject, valueTypeWrapper, index, args);
+ return engine->fromVariant(
+ v, valueTypeWrapper, index,
+ referenceFlags(metaObject, index) | Heap::ReferenceObject::IsVariant);
}
- metaObject->d.static_metacall(reinterpret_cast<QObject*>(valueTypeWrapper->gadgetPtr()), QMetaObject::ReadProperty,
- index, args);
- return engine->fromVariant(v);
+ default:
+ break;
+ }
+
+ QVariant v(metaType);
+ void *args[] = { v.data(), nullptr };
+ doStaticReadCall(metaObject, valueTypeWrapper, index, args);
+ return engine->fromVariant(v, valueTypeWrapper, index, referenceFlags(metaObject, index));
#undef VALUE_TYPE_LOAD
}
@@ -297,10 +421,26 @@ PropertyAttributes QQmlValueTypeWrapper::virtualGetOwnProperty(const Managed *m,
{
if (id.isString()) {
const QQmlValueTypeWrapper *r = static_cast<const QQmlValueTypeWrapper *>(m);
- QQmlPropertyData result = r->dataForPropertyKey(id);
- if (p && result.isValid())
- p->value = getGadgetProperty(r->engine(), r->d(), result.propType(), result.coreIndex(), result.isFunction(), result.isEnum());
- return result.isValid() ? Attr_Data : Attr_Invalid;
+ Q_ASSERT(r);
+
+ const QQmlPropertyData result = r->dataForPropertyKey(id);
+ if (!result.isValid())
+ return Attr_Invalid; // Property doesn't exist. Object shouldn't meddle with it.
+
+ if (!p)
+ return Attr_Data; // Property exists, but we're not interested in the value
+
+ if (!r->d()->isReference() || r->readReferenceValue()) {
+ // Property exists, and we can retrieve it
+ p->value = getGadgetProperty(
+ r->engine(), r->d(), result.propType(), result.coreIndex(),
+ result.isFunction(), result.isEnum());
+ } else {
+ // Property exists, but we can't retrieve it. Make it undefined.
+ p->value = Encode::undefined();
+ }
+
+ return Attr_Data;
}
return QV4::Object::virtualGetOwnProperty(m, id, p);
@@ -317,10 +457,8 @@ struct QQmlValueTypeWrapperOwnPropertyKeyIterator : ObjectOwnPropertyKeyIterator
PropertyKey QQmlValueTypeWrapperOwnPropertyKeyIterator::next(const Object *o, Property *pd, PropertyAttributes *attrs) {
const QQmlValueTypeWrapper *that = static_cast<const QQmlValueTypeWrapper *>(o);
- if (const QQmlValueTypeReference *ref = that->as<QQmlValueTypeReference>()) {
- if (!ref->readReferenceValue())
- return PropertyKey::invalid();
- }
+ if (that->d()->isReference() && !that->readReferenceValue())
+ return PropertyKey::invalid();
const QMetaObject *mo = that->d()->metaObject();
// We don't return methods, ie. they are not visible when iterating
@@ -352,9 +490,8 @@ OwnPropertyKeyIterator *QQmlValueTypeWrapper::virtualOwnPropertyKeys(const Objec
bool QQmlValueTypeWrapper::isEqual(const QVariant& value) const
{
- if (const QQmlValueTypeReference *ref = as<const QQmlValueTypeReference>())
- if (!ref->readReferenceValue())
- return false;
+ if (d()->isReference() && !readReferenceValue())
+ return false;
int id1 = value.metaType().id();
QVariant v = d()->toVariant();
int id2 = v.metaType().id();
@@ -402,26 +539,26 @@ bool QQmlValueTypeWrapper::isEqual(const QVariant& value) const
int QQmlValueTypeWrapper::typeId() const
{
- return d()->valueType()->metaType.id();
+ return d()->metaType().id();
}
QMetaType QQmlValueTypeWrapper::type() const
{
- return d()->valueType()->metaType;
+ return d()->metaType();
}
bool QQmlValueTypeWrapper::write(QObject *target, int propertyIndex) const
{
bool destructGadgetOnExit = false;
Q_ALLOCA_DECLARE(void, gadget);
- if (const QQmlValueTypeReference *ref = as<const QQmlValueTypeReference>()) {
+ if (d()->isReference()) {
if (!d()->gadgetPtr()) {
- Q_ALLOCA_ASSIGN(void, gadget, d()->valueType()->metaType.sizeOf());
+ Q_ALLOCA_ASSIGN(void, gadget, d()->metaType().sizeOf());
d()->setGadgetPtr(gadget);
- d()->valueType()->metaType.construct(d()->gadgetPtr(), nullptr);
+ d()->metaType().construct(d()->gadgetPtr(), nullptr);
destructGadgetOnExit = true;
}
- if (!ref->readReferenceValue())
+ if (!readReferenceValue())
return false;
}
@@ -431,7 +568,7 @@ bool QQmlValueTypeWrapper::write(QObject *target, int propertyIndex) const
QMetaObject::metacall(target, QMetaObject::WriteProperty, propertyIndex, a);
if (destructGadgetOnExit) {
- d()->valueType()->metaType.destruct(d()->gadgetPtr());
+ d()->metaType().destruct(d()->gadgetPtr());
d()->setGadgetPtr(nullptr);
}
return true;
@@ -464,14 +601,13 @@ ReturnedValue QQmlValueTypeWrapper::method_toString(const FunctionObject *b, con
if (!w)
return b->engine()->throwTypeError();
- if (const QQmlValueTypeReference *ref = w->as<QQmlValueTypeReference>())
- if (!ref->readReferenceValue())
- RETURN_UNDEFINED();
+ if (w->d()->isReference() && !w->readReferenceValue())
+ RETURN_UNDEFINED();
QString result;
- if (!QMetaType::convert(w->d()->valueType()->metaType, w->d()->gadgetPtr(),
+ if (!QMetaType::convert(w->d()->metaType(), w->d()->gadgetPtr(),
QMetaType(QMetaType::QString), &result)) {
- result = QString::fromUtf8(w->d()->valueType()->metaType.name()) + QLatin1Char('(');
+ result = QString::fromUtf8(w->d()->metaType().name()) + QLatin1Char('(');
const QMetaObject *mo = w->d()->metaObject();
const int propCount = mo->propertyCount();
for (int i = 0; i < propCount; ++i) {
@@ -501,16 +637,14 @@ ReturnedValue QQmlValueTypeWrapper::virtualResolveLookupGetter(const Object *obj
ScopedString name(scope, id.asStringOrSymbol());
// Note: readReferenceValue() can change the reference->type.
- if (const QQmlValueTypeReference *reference = r->as<QQmlValueTypeReference>()) {
- if (!reference->readReferenceValue())
- return Value::undefinedValue().asReturnedValue();
- }
+ if (r->d()->isReference() && !r->readReferenceValue())
+ return Value::undefinedValue().asReturnedValue();
QQmlPropertyData result = r->dataForPropertyKey(id);
if (!result.isValid())
return QV4::Object::virtualResolveLookupGetter(object, engine, lookup);
- lookup->qgadgetLookup.ic = r->internalClass();
+ lookup->qgadgetLookup.ic.set(engine, r->internalClass());
// & 1 to tell the gc that this is not heap allocated; see markObjects in qv4lookup_p.h
lookup->qgadgetLookup.metaObject = quintptr(r->d()->metaObject()) + 1;
lookup->qgadgetLookup.metaType = result.propType().iface();
@@ -540,13 +674,19 @@ ReturnedValue QQmlValueTypeWrapper::lookupGetter(Lookup *lookup, ExecutionEngine
if (valueTypeWrapper->metaObject() != reinterpret_cast<const QMetaObject *>(lookup->qgadgetLookup.metaObject - 1))
return revertLookup();
- if (lookup->qgadgetLookup.ic->vtable == QQmlValueTypeReference::staticVTable()) {
- Scope scope(engine);
- Scoped<QQmlValueTypeReference> referenceWrapper(scope, valueTypeWrapper);
- referenceWrapper->readReferenceValue();
- }
+ if (valueTypeWrapper->isReference() && !valueTypeWrapper->readReference())
+ return Encode::undefined();
+
+ return getGadgetProperty(
+ engine, valueTypeWrapper, QMetaType(lookup->qgadgetLookup.metaType),
+ lookup->qgadgetLookup.coreIndex, lookup->qgadgetLookup.isFunction,
+ lookup->qgadgetLookup.isEnum);
+}
- return getGadgetProperty(engine, valueTypeWrapper, QMetaType(lookup->qgadgetLookup.metaType), lookup->qgadgetLookup.coreIndex, lookup->qgadgetLookup.isFunction, lookup->qgadgetLookup.isEnum);
+bool QQmlValueTypeWrapper::lookupSetter(
+ Lookup *l, ExecutionEngine *engine, Value &object, const Value &value)
+{
+ return QV4::Lookup::setterFallback(l, engine, object, value);
}
bool QQmlValueTypeWrapper::virtualResolveLookupSetter(Object *object, ExecutionEngine *engine, Lookup *lookup,
@@ -566,10 +706,8 @@ ReturnedValue QQmlValueTypeWrapper::virtualGet(const Managed *m, PropertyKey id,
QV4::ExecutionEngine *v4 = r->engine();
// Note: readReferenceValue() can change the reference->type.
- if (const QQmlValueTypeReference *reference = r->as<QQmlValueTypeReference>()) {
- if (!reference->readReferenceValue())
- return Value::undefinedValue().asReturnedValue();
- }
+ if (r->d()->isReference() && !r->readReferenceValue())
+ return Value::undefinedValue().asReturnedValue();
QQmlPropertyData result = r->dataForPropertyKey(id);
if (!result.isValid())
@@ -593,17 +731,11 @@ bool QQmlValueTypeWrapper::virtualPut(Managed *m, PropertyKey id, const Value &v
return false;
Scoped<QQmlValueTypeWrapper> r(scope, static_cast<QQmlValueTypeWrapper *>(m));
- Scoped<QQmlValueTypeReference> reference(scope, m->d());
-
- QMetaType writeBackPropertyType;
-
- if (reference) {
- QMetaProperty writebackProperty = reference->d()->object->metaObject()->property(reference->d()->property);
-
- if (!writebackProperty.isWritable() || !reference->readReferenceValue())
+ Heap::Object *heapObject = nullptr;
+ if (r->d()->isReference()) {
+ heapObject = r->d()->object();
+ if (!r->readReferenceValue() || !r->d()->canWriteBack())
return false;
-
- writeBackPropertyType = writebackProperty.metaType();
}
const QMetaObject *metaObject = r->d()->metaObject();
@@ -611,10 +743,18 @@ bool QQmlValueTypeWrapper::virtualPut(Managed *m, PropertyKey id, const Value &v
if (!pd.isValid())
return false;
- if (reference) {
+ if (heapObject) {
+ QObject *referenceObject = nullptr;
QV4::ScopedFunctionObject f(scope, value);
- const QV4QPointer<QObject> &referenceObject = reference->d()->object;
- const int referencePropertyIndex = reference->d()->property;
+ const int referencePropertyIndex = r->d()->property();
+ QV4::Scoped<QV4::QObjectWrapper> o(scope, heapObject);
+ if (o) {
+ referenceObject = o->object();
+ } else {
+ QV4::Scoped<QV4::QQmlTypeWrapper> t(scope, heapObject);
+ if (t)
+ referenceObject = t->object();
+ }
if (f) {
if (!f->isBinding()) {
@@ -625,6 +765,17 @@ bool QQmlValueTypeWrapper::virtualPut(Managed *m, PropertyKey id, const Value &v
return false;
}
+ if (!referenceObject) {
+ QString error = QStringLiteral("Cannot create binding on nested value type property");
+ ScopedString e(scope, v4->newString(error));
+ v4->throwError(e);
+ return false;
+ }
+
+ const QMetaProperty writebackProperty
+ = referenceObject->metaObject()->property(referencePropertyIndex);
+ const QMetaType writeBackPropertyType = writebackProperty.metaType();
+
QQmlRefPointer<QQmlContextData> context = v4->callingQmlContext();
QQmlPropertyData cacheData;
@@ -644,10 +795,10 @@ bool QQmlValueTypeWrapper::virtualPut(Managed *m, PropertyKey id, const Value &v
newBinding->setTarget(referenceObject, cacheData, &pd);
QQmlPropertyPrivate::setBinding(newBinding);
return true;
- } else {
+ } else if (referenceObject) {
if (Q_UNLIKELY(lcBindingRemoval().isInfoEnabled())) {
if (auto binding = QQmlPropertyPrivate::binding(referenceObject, QQmlPropertyIndex(referencePropertyIndex, pd.coreIndex()))) {
- Q_ASSERT(!binding->isValueTypeProxy());
+ Q_ASSERT(binding->kind() == QQmlAbstractBinding::QmlBinding);
const auto qmlBinding = static_cast<const QQmlBinding*>(binding);
const auto stackFrame = v4->currentStackFrame;
qCInfo(lcBindingRemoval,
@@ -664,34 +815,27 @@ bool QQmlValueTypeWrapper::virtualPut(Managed *m, PropertyKey id, const Value &v
QMetaProperty property = metaObject->property(pd.coreIndex());
Q_ASSERT(property.isValid());
+ if (value.isUndefined() && pd.isResettable()) {
+ property.resetOnGadget(reinterpret_cast<QObject *>(r->d()->gadgetPtr()));
+ if (heapObject)
+ r->d()->writeBack(pd.coreIndex());
+ return true;
+ }
- QVariant v = v4->toVariant(value, property.userType());
+ QVariant v = QV4::ExecutionEngine::toVariant(value, property.metaType());
if (property.isEnumType() && (QMetaType::Type)v.userType() == QMetaType::Double)
v = v.toInt();
void *gadget = r->d()->gadgetPtr();
- property.writeOnGadget(gadget, v);
-
-
- if (reference) {
- if (writeBackPropertyType == QMetaType::fromType<QVariant>()) {
- QVariant variantReferenceValue = r->d()->toVariant();
-
- int flags = 0;
- int status = -1;
- void *a[] = { &variantReferenceValue, nullptr, &status, &flags };
- QMetaObject::metacall(reference->d()->object, QMetaObject::WriteProperty, reference->d()->property, a);
+ property.writeOnGadget(gadget, std::move(v));
- } else {
- int flags = 0;
- int status = -1;
- void *a[] = { r->d()->gadgetPtr(), nullptr, &status, &flags };
- QMetaObject::metacall(reference->d()->object, QMetaObject::WriteProperty, reference->d()->property, a);
- }
- }
+ if (heapObject)
+ r->d()->writeBack(pd.coreIndex());
return true;
}
+} // namespace QV4
+
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlvaluetypewrapper_p.h b/src/qml/qml/qqmlvaluetypewrapper_p.h
index ffce64d54e..5b3894a07f 100644
--- a/src/qml/qml/qqmlvaluetypewrapper_p.h
+++ b/src/qml/qml/qqmlvaluetypewrapper_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLVALUETYPEWRAPPER_P_H
#define QQMLVALUETYPEWRAPPER_P_H
@@ -54,9 +18,15 @@
#include <QtCore/qglobal.h>
#include <private/qtqmlglobal_p.h>
-#include <private/qv4value_p.h>
-#include <private/qv4object_p.h>
+#include <private/qv4referenceobject_p.h>
#include <private/qqmlpropertycache_p.h>
+#include <private/qqmltype_p_p.h>
+#include <private/qqmltypewrapper_p.h>
+#include <private/qv4object_p.h>
+#include <private/qv4qobjectwrapper_p.h>
+#include <private/qv4sequenceobject_p.h>
+#include <private/qv4value_p.h>
+#include <private/qv4referenceobject_p.h>
QT_BEGIN_NAMESPACE
@@ -66,84 +36,126 @@ namespace QV4 {
namespace Heap {
-struct QQmlValueTypeWrapper : Object {
- void init() { Object::init(); }
- void destroy();
+#define QQmlValueTypeWrapperMembers(class, Member)
- void setValueType(QQmlValueType *valueType)
- {
- Q_ASSERT(valueType != nullptr);
- m_valueType = valueType;
- }
+DECLARE_HEAP_OBJECT(QQmlValueTypeWrapper, ReferenceObject) {
+ DECLARE_MARKOBJECTS(QQmlValueTypeWrapper);
- QQmlValueType *valueType() const
+ void init(
+ const void *data, QMetaType metaType, const QMetaObject *metaObject,
+ Object *object, int property, Flags flags)
{
- Q_ASSERT(m_valueType != nullptr);
- return m_valueType;
+ ReferenceObject::init(object, property, flags);
+ setMetaType(metaType);
+ setMetaObject(metaObject);
+ if (data)
+ setData(data);
}
- void setGadgetPtr(void *gadgetPtr) const
- {
- m_gadgetPtr = gadgetPtr;
- }
+ QQmlValueTypeWrapper *detached() const;
- void *gadgetPtr() const
- {
- return m_gadgetPtr;
- }
+ void destroy();
- void setMetaObject(const QMetaObject *metaObject)
+ QMetaType metaType() const
{
- m_metaObject = metaObject;
+ Q_ASSERT(m_metaType != nullptr);
+ return QMetaType(m_metaType);
}
- const QMetaObject *metaObject() const
+
+ void setGadgetPtr(void *gadgetPtr) { m_gadgetPtr = gadgetPtr; }
+ void *gadgetPtr() const { return m_gadgetPtr; }
+
+ const QMetaObject *metaObject() const { return m_metaObject; }
+
+ void setData(const void *data)
{
- return m_metaObject;
+ const QMetaType type = metaType();
+ void *gadget = gadgetPtr();
+ if (gadget) {
+ type.destruct(gadget);
+ } else {
+ gadget = ::operator new(type.sizeOf());
+ setGadgetPtr(gadget);
+ }
+ type.construct(gadget, data);
}
-
- void setValue(const QVariant &value) const;
QVariant toVariant() const;
+ void *storagePointer();
+ bool setVariant(const QVariant &variant);
+
+ bool readReference();
+ bool writeBack(int propertyIndex = QV4::ReferenceObject::AllProperties);
+
private:
- mutable void *m_gadgetPtr;
- QQmlValueType *m_valueType;
+ void setMetaObject(const QMetaObject *metaObject) { m_metaObject = metaObject; }
+ void setMetaType(QMetaType metaType)
+ {
+ Q_ASSERT(metaType.isValid());
+ m_metaType = metaType.iface();
+ }
+
+ void *m_gadgetPtr;
+ const QtPrivate::QMetaTypeInterface *m_metaType;
const QMetaObject *m_metaObject;
};
}
-struct Q_QML_EXPORT QQmlValueTypeWrapper : Object
+struct Q_QML_EXPORT QQmlValueTypeWrapper : public ReferenceObject
{
- V4_OBJECT2(QQmlValueTypeWrapper, Object)
+ V4_OBJECT2(QQmlValueTypeWrapper, ReferenceObject)
V4_PROTOTYPE(valueTypeWrapperPrototype)
V4_NEEDS_DESTROY
public:
- static ReturnedValue create(ExecutionEngine *engine, QObject *, int, const QMetaObject *metaObject, QMetaType type);
- static ReturnedValue create(ExecutionEngine *engine, const QVariant &, const QMetaObject *metaObject, QMetaType type);
+ static ReturnedValue create(
+ ExecutionEngine *engine, const void *data, const QMetaObject *metaObject,
+ QMetaType type, Heap::Object *object, int property, Heap::ReferenceObject::Flags flags);
+ static ReturnedValue create(
+ ExecutionEngine *engine, Heap::QQmlValueTypeWrapper *cloneFrom, Heap::Object *object);
+ static ReturnedValue create(
+ ExecutionEngine *engine, const void *, const QMetaObject *metaObject, QMetaType type);
QVariant toVariant() const;
+
+ template<typename ValueType>
+ ValueType *cast()
+ {
+ if (QMetaType::fromType<ValueType>() != d()->metaType())
+ return nullptr;
+ if (d()->isReference() && !readReferenceValue())
+ return nullptr;
+ return static_cast<ValueType *>(d()->gadgetPtr());
+ }
+
bool toGadget(void *data) const;
bool isEqual(const QVariant& value) const;
int typeId() const;
QMetaType type() const;
bool write(QObject *target, int propertyIndex) const;
+ bool readReferenceValue() const { return d()->readReference(); }
+ const QMetaObject *metaObject() const { return d()->metaObject(); }
QQmlPropertyData dataForPropertyKey(PropertyKey id) const;
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);
static bool virtualIsEqualTo(Managed *m, Managed *other);
+ static bool virtualHasProperty(const Managed *m, PropertyKey id);
static PropertyAttributes virtualGetOwnProperty(const Managed *m, PropertyKey id, Property *p);
static OwnPropertyKeyIterator *virtualOwnPropertyKeys(const Object *m, Value *target);
static ReturnedValue method_toString(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
static ReturnedValue virtualResolveLookupGetter(const Object *object, ExecutionEngine *engine, Lookup *lookup);
static bool virtualResolveLookupSetter(Object *object, ExecutionEngine *engine, Lookup *lookup, const Value &value);
static ReturnedValue lookupGetter(Lookup *lookup, ExecutionEngine *engine, const Value &object);
+ static bool lookupSetter(QV4::Lookup *l, QV4::ExecutionEngine *engine,
+ QV4::Value &object, const QV4::Value &value);
static void initProto(ExecutionEngine *v4);
+ static int virtualMetacall(Object *object, QMetaObject::Call call, int index, void **a);
};
}
diff --git a/src/qml/qml/qqmlvme.cpp b/src/qml/qml/qqmlvme.cpp
index cf073dc768..3b9bf80940 100644
--- a/src/qml/qml/qqmlvme.cpp
+++ b/src/qml/qml/qqmlvme.cpp
@@ -1,67 +1,12 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qqmlvme_p.h"
-#include "qqmlboundsignal_p.h"
-#include "qqmlstringconverters_p.h"
#include <private/qmetaobjectbuilder_p.h>
-#include "qqmldata_p.h"
-#include "qqml.h"
-#include "qqmlinfo.h"
-#include "qqmlcustomparser_p.h"
#include "qqmlengine.h"
-#include "qqmlcontext.h"
-#include "qqmlcomponent.h"
-#include "qqmlcomponentattached_p.h"
-#include "qqmlbinding_p.h"
-#include "qqmlengine_p.h"
-#include "qqmlcomponent_p.h"
-#include "qqmlvmemetaobject_p.h"
-#include "qqmlcontext_p.h"
-#include "qqmlglobal_p.h"
#include <private/qfinitestack_p.h>
-#include "qqmlscriptstring.h"
-#include "qqmlscriptstring_p.h"
-#include "qqmlpropertyvalueinterceptor_p.h"
-#include "qqmlvaluetypeproxybinding_p.h"
-#include "qqmlexpression_p.h"
+#include <QtQml/private/qqmlcomponent_p.h>
#include <QStack>
#include <QPointF>
@@ -107,9 +52,9 @@ void QQmlVMEGuard::guard(QQmlObjectCreator *creator)
{
clear();
- QFiniteStack<QPointer<QObject> > &objects = creator->allCreatedObjects();
+ QFiniteStack<QQmlGuard<QObject> > &objects = creator->allCreatedObjects();
m_objectCount = objects.count();
- m_objects = new QPointer<QObject>[m_objectCount];
+ m_objects = new QQmlGuard<QObject>[m_objectCount];
for (int ii = 0; ii < m_objectCount; ++ii)
m_objects[ii] = objects[ii];
diff --git a/src/qml/qml/qqmlvme_p.h b/src/qml/qml/qqmlvme_p.h
index 78631ecdf8..b8dfc28050 100644
--- a/src/qml/qml/qqmlvme_p.h
+++ b/src/qml/qml/qqmlvme_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLVME_P_H
#define QQMLVME_P_H
@@ -51,12 +15,12 @@
// We mean it.
//
-#include "qqmlerror.h"
#include <private/qrecursionwatcher_p.h>
#include <QtCore/QStack>
#include <QtCore/QString>
#include <QtCore/qelapsedtimer.h>
+#include <QtCore/qdeadlinetimer.h>
#include <QtCore/qcoreapplication.h>
#include <QtCore/qtypeinfo.h>
@@ -72,20 +36,19 @@ class QObject;
class QQmlInstantiationInterrupt {
public:
inline QQmlInstantiationInterrupt();
- inline QQmlInstantiationInterrupt(std::atomic<bool> *runWhile, qint64 nsecs = 0);
- inline QQmlInstantiationInterrupt(qint64 nsecs);
+ inline QQmlInstantiationInterrupt(std::atomic<bool> *runWhile,
+ QDeadlineTimer deadline = QDeadlineTimer::Forever);
+ inline QQmlInstantiationInterrupt(QDeadlineTimer deadline);
- inline void reset();
inline bool shouldInterrupt() const;
private:
enum Mode { None, Time, Flag };
Mode mode;
- QElapsedTimer timer;
- qint64 nsecs = 0;
+ QDeadlineTimer deadline;
std::atomic<bool> *runWhile = nullptr;
};
-class Q_QML_PRIVATE_EXPORT QQmlVME
+class Q_QML_EXPORT QQmlVME
{
public:
static void enableComponentComplete();
@@ -116,7 +79,7 @@ public:
private:
int m_objectCount;
- QPointer<QObject> *m_objects;
+ QQmlGuard<QObject> *m_objects;
int m_contextCount;
QQmlGuardedContextData *m_contexts;
};
@@ -126,34 +89,27 @@ QQmlInstantiationInterrupt::QQmlInstantiationInterrupt()
{
}
-QQmlInstantiationInterrupt::QQmlInstantiationInterrupt(std::atomic<bool> *runWhile, qint64 nsecs)
- : mode(Flag), nsecs(nsecs), runWhile(runWhile)
+QQmlInstantiationInterrupt::QQmlInstantiationInterrupt(std::atomic<bool> *runWhile, QDeadlineTimer deadline)
+ : mode(Flag), deadline(deadline), runWhile(runWhile)
{
}
-QQmlInstantiationInterrupt::QQmlInstantiationInterrupt(qint64 nsecs)
- : mode(Time), nsecs(nsecs)
+QQmlInstantiationInterrupt::QQmlInstantiationInterrupt(QDeadlineTimer deadline)
+ : mode(Time), deadline(deadline)
{
}
-void QQmlInstantiationInterrupt::reset()
-{
- if (mode == Time || nsecs)
- timer.start();
-}
-
bool QQmlInstantiationInterrupt::shouldInterrupt() const
{
switch (mode) {
case None:
return false;
case Time:
- return timer.nsecsElapsed() > nsecs;
+ return deadline.hasExpired();
case Flag:
- return !runWhile->load(std::memory_order_acquire) || (nsecs && timer.nsecsElapsed() > nsecs);
+ return !runWhile->load(std::memory_order_acquire) || deadline.hasExpired();
}
- Q_UNREACHABLE();
- return false;
+ Q_UNREACHABLE_RETURN(false);
}
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlvmemetaobject.cpp b/src/qml/qml/qqmlvmemetaobject.cpp
index 417ac6b3b7..5f3b6975ca 100644
--- a/src/qml/qml/qqmlvmemetaobject.cpp
+++ b/src/qml/qml/qqmlvmemetaobject.cpp
@@ -1,52 +1,10 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Copyright (C) 2016 BasysKom GmbH.
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// Copyright (C) 2016 BasysKom GmbH.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qqmlvmemetaobject_p.h"
-
-#include "qqml.h"
#include <private/qqmlrefcount_p.h>
-#include "qqmlexpression.h"
-#include "qqmlexpression_p.h"
-#include "qqmlcontext_p.h"
-#include "qqmlbinding_p.h"
#include "qqmlpropertyvalueinterceptor_p.h"
#include <qqmlinfo.h>
@@ -58,136 +16,162 @@
#include <private/qv4scopedvalue_p.h>
#include <private/qv4jscall_p.h>
#include <private/qv4qobjectwrapper_p.h>
+#include <private/qv4sequenceobject_p.h>
#include <private/qqmlpropertycachecreator_p.h>
#include <private/qqmlpropertycachemethodarguments_p.h>
+#include <private/qqmlvaluetypewrapper_p.h>
+
+#include <QtCore/qsequentialiterable.h>
#include <climits> // for CHAR_BIT
QT_BEGIN_NAMESPACE
-class ResolvedList
+QQmlVMEResolvedList::QQmlVMEResolvedList(QQmlListProperty<QObject> *prop)
{
- Q_DISABLE_COPY_MOVE(ResolvedList)
+ // see QQmlVMEMetaObject::metaCall for how this was constructed
+ auto encodedIndex = quintptr(prop->data);
+ constexpr quintptr usableBits = sizeof(quintptr) * CHAR_BIT;
+ quintptr inheritanceDepth = encodedIndex >> (usableBits / 2);
+ m_id = encodedIndex & ((quintptr(1) << (usableBits / 2)) - 1);
+
+ // walk up to the correct meta object if necessary
+ auto mo = static_cast<QQmlVMEMetaObject *>(QObjectPrivate::get(prop->object)->metaObject);
+ while (inheritanceDepth--)
+ mo = mo->parentVMEMetaObject();
+ m_metaObject = mo;
+ Q_ASSERT(m_metaObject);
+ Q_ASSERT(::strstr(m_metaObject->toDynamicMetaObject(prop->object)
+ ->property(m_metaObject->propOffset() + m_id)
+ .typeName(),
+ "QQmlListProperty"));
+ Q_ASSERT(m_metaObject->object == prop->object);
+
+ // readPropertyAsList() with checks transformed into Q_ASSERT
+ // and without allocation.
+ if (m_metaObject->propertyAndMethodStorage.isUndefined()
+ && m_metaObject->propertyAndMethodStorage.valueRef()) {
+ return;
+ }
-public:
- ResolvedList(QQmlListProperty<QObject> *prop)
- {
- // see QQmlVMEMetaObject::metaCall for how this was constructed
- auto encodedIndex = quintptr(prop->data);
- constexpr quintptr usableBits = sizeof(quintptr) * CHAR_BIT;
- quintptr inheritanceDepth = encodedIndex >> (usableBits / 2);
- m_id = encodedIndex & ((quintptr(1) << (usableBits / 2)) - 1);
-
- // walk up to the correct meta object if necessary
- auto mo = prop->object->metaObject();
- while (inheritanceDepth--)
- mo = mo->superClass();
- m_metaObject = static_cast<QQmlVMEMetaObject *>(const_cast<QMetaObject *>(mo));
- Q_ASSERT(m_metaObject);
- Q_ASSERT( ::strstr(m_metaObject->property(m_metaObject->propOffset() + m_id).typeName(), "QQmlListProperty") );
- Q_ASSERT(m_metaObject->object == prop->object);
-
- // readPropertyAsList() with checks transformed into Q_ASSERT
- // and without allocation.
- if (m_metaObject->propertyAndMethodStorage.isUndefined() &&
- m_metaObject->propertyAndMethodStorage.valueRef()) {
- return;
- }
+ if (auto *md = static_cast<QV4::MemberData *>(
+ m_metaObject->propertyAndMethodStorage.asManaged())) {
+ const QV4::Value *v = md->data() + m_id;
+ Q_ASSERT(v->as<QV4::Object>());
+ m_list = static_cast<QV4::Heap::Object *>(v->heapObject());
+ Q_ASSERT(m_list);
+ }
+}
- if (auto *md = static_cast<QV4::MemberData *>(
- m_metaObject->propertyAndMethodStorage.asManaged())) {
- const auto *v = (md->data() + m_id)->as<QV4::VariantObject>();
- Q_ASSERT(v);
- Q_ASSERT(v->d());
- QVariant &data = v->d()->data();
- Q_ASSERT(data.userType() == qMetaTypeId<QVector<QQmlGuard<QObject>>>());
- m_list = static_cast<QVector<QQmlGuard<QObject>> *>(data.data());
- Q_ASSERT(m_list);
- }
+void QQmlVMEResolvedList::append(QObject *o) const
+{
+ QV4::Scope scope(m_list->internalClass->engine);
+ QV4::Heap::ArrayData *arrayData = m_list->arrayData;
+
+ const uint length = arrayData->length();
+ if (Q_UNLIKELY(length == std::numeric_limits<uint>::max())) {
+ scope.engine->throwRangeError(QLatin1String("Too many elements."));
+ return;
}
- ~ResolvedList() = default;
+ QV4::ScopedObject object(scope, m_list);
+ QV4::ArrayData::realloc(object, QV4::Heap::ArrayData::Simple, length + 1, false);
+ arrayData->vtable()->put(
+ object, length, QV4::QObjectWrapper::wrap(scope.engine, o));
+}
- QQmlVMEMetaObject *metaObject() const { return m_metaObject; }
- QVector<QQmlGuard<QObject>> *list() const { return m_list; }
- quintptr id() const { return m_id; }
+QObject *QQmlVMEResolvedList::at(qsizetype i) const
+{
+ QV4::Scope scope(m_list->internalClass->engine);
+ QV4::Scoped<QV4::QObjectWrapper> result(scope, m_list->arrayData->get(i));
+ return result ? result->object() : nullptr;
+}
- void activateSignal() const
- {
- m_metaObject->activate(m_metaObject->object, int(m_id + m_metaObject->methodOffset()),
- nullptr);
- }
+void QQmlVMEResolvedList::replace(qsizetype i, QObject *o) const
+{
+ QV4::Scope scope(m_list->internalClass->engine);
+ QV4::ScopedObject object(scope, m_list);
+ m_list->arrayData->vtable()->put(object, i, QV4::QObjectWrapper::wrap(scope.engine, o));
+}
-private:
- QQmlVMEMetaObject *m_metaObject = nullptr;
- QVector<QQmlGuard<QObject>> *m_list = nullptr;
- quintptr m_id = 0;
-};
+QQmlVMEResolvedList::~QQmlVMEResolvedList() = default;
+
+void QQmlVMEResolvedList::activateSignal() const
+{
+ m_metaObject->activate(m_metaObject->object, int(m_id + m_metaObject->methodOffset()), nullptr);
+}
-static void list_append(QQmlListProperty<QObject> *prop, QObject *o)
+void QQmlVMEMetaObject::list_append(QQmlListProperty<QObject> *prop, QObject *o)
{
- const ResolvedList resolved(prop);
- resolved.list()->append(o);
+ const QQmlVMEResolvedList resolved(prop);
+ resolved.append(o);
resolved.activateSignal();
}
+void QQmlVMEMetaObject::list_append_nosignal(QQmlListProperty<QObject> *prop, QObject *o)
+{
+ QQmlVMEResolvedList(prop).append(o);
+}
+
static qsizetype list_count(QQmlListProperty<QObject> *prop)
{
- return ResolvedList(prop).list()->count();
+ return QQmlVMEResolvedList(prop).size();
}
static QObject *list_at(QQmlListProperty<QObject> *prop, qsizetype index)
{
- return ResolvedList(prop).list()->at(index);
+ return QQmlVMEResolvedList(prop).at(index);
}
-static void list_clear(QQmlListProperty<QObject> *prop)
+void QQmlVMEMetaObject::list_clear(QQmlListProperty<QObject> *prop)
{
- const ResolvedList resolved(prop);
- resolved.list()->clear();
+ const QQmlVMEResolvedList resolved(prop);
+ resolved.clear();
resolved.activateSignal();
}
+void QQmlVMEMetaObject::list_clear_nosignal(QQmlListProperty<QObject> *prop)
+{
+ QQmlVMEResolvedList(prop).clear();
+}
+
static void list_replace(QQmlListProperty<QObject> *prop, qsizetype index, QObject *o)
{
- const ResolvedList resolved(prop);
- resolved.list()->replace(index, o);
+ const QQmlVMEResolvedList resolved(prop);
+ resolved.replace(index, o);
resolved.activateSignal();
}
static void list_removeLast(QQmlListProperty<QObject> *prop)
{
- const ResolvedList resolved(prop);
- resolved.list()->removeLast();
+ const QQmlVMEResolvedList resolved(prop);
+ resolved.removeLast();
resolved.activateSignal();
}
QQmlVMEVariantQObjectPtr::QQmlVMEVariantQObjectPtr()
- : QQmlGuard<QObject>(nullptr), m_target(nullptr), m_index(-1)
-{
-}
-
-QQmlVMEVariantQObjectPtr::~QQmlVMEVariantQObjectPtr()
+ : QQmlGuard<QObject>(QQmlVMEVariantQObjectPtr::objectDestroyedImpl, nullptr), m_target(nullptr), m_index(-1)
{
}
-void QQmlVMEVariantQObjectPtr::objectDestroyed(QObject *)
+void QQmlVMEVariantQObjectPtr::objectDestroyedImpl(QQmlGuardImpl *guard)
{
- if (!m_target || QQmlData::wasDeleted(m_target->object))
+ auto This = static_cast<QQmlVMEVariantQObjectPtr *>(guard);
+ if (!This->m_target || QQmlData::wasDeleted(This->m_target->object))
return;
- if (m_index >= 0) {
- QV4::ExecutionEngine *v4 = m_target->propertyAndMethodStorage.engine();
+ if (This->m_index >= 0) {
+ QV4::ExecutionEngine *v4 = This->m_target->propertyAndMethodStorage.engine();
if (v4) {
QV4::Scope scope(v4);
- QV4::Scoped<QV4::MemberData> sp(scope, m_target->propertyAndMethodStorage.value());
+ QV4::Scoped<QV4::MemberData> sp(scope, This->m_target->propertyAndMethodStorage.value());
if (sp) {
- QV4::PropertyIndex index{ sp->d(), sp->d()->values.values + m_index };
+ QV4::PropertyIndex index{ sp->d(), sp->d()->values.values + This->m_index };
index.set(v4, QV4::Value::nullValue());
}
}
- m_target->activate(m_target->object, m_target->methodOffset() + m_index, nullptr);
+ This->m_target->activate(This->m_target->object, This->m_target->methodOffset() + This->m_index, nullptr);
}
}
@@ -236,21 +220,18 @@ void QQmlVMEMetaObjectEndpoint::tryConnect()
const QV4::CompiledData::Alias *aliasData = &metaObject->compiledObject->aliasTable()[aliasId];
if (!aliasData->isObjectAlias()) {
QQmlRefPointer<QQmlContextData> ctxt = metaObject->ctxt;
- QObject *target = ctxt->idValue(aliasData->targetObjectId);
+ QObject *target = ctxt->idValue(aliasData->targetObjectId());
if (!target)
return;
- QQmlData *targetDData = QQmlData::get(target, /*create*/false);
- if (!targetDData)
- return;
QQmlPropertyIndex encodedIndex = QQmlPropertyIndex::fromEncoded(aliasData->encodedMetaPropertyIndex);
int coreIndex = encodedIndex.coreIndex();
int valueTypeIndex = encodedIndex.valueTypeIndex();
- const QQmlPropertyData *pd = targetDData->propertyCache->property(coreIndex);
+ const QQmlPropertyData *pd = QQmlData::ensurePropertyCache(target)->property(coreIndex);
if (pd && valueTypeIndex != -1 && !QQmlMetaType::valueType(pd->propType())) {
// deep alias
- QQmlEnginePrivate *enginePriv = QQmlEnginePrivate::get(metaObject->compilationUnit->engine->qmlEngine());
- auto const *newPropertyCache = enginePriv->propertyCacheForType(pd->propType().id());
+ const QQmlPropertyCache::ConstPtr newPropertyCache
+ = QQmlMetaType::propertyCacheForType(pd->propType());
void *argv[1] = { &target };
QMetaObject::metacall(target, QMetaObject::ReadProperty, coreIndex, argv);
Q_ASSERT(newPropertyCache);
@@ -268,11 +249,9 @@ void QQmlVMEMetaObjectEndpoint::tryConnect()
}
-QQmlInterceptorMetaObject::QQmlInterceptorMetaObject(QObject *obj, const QQmlRefPointer<QQmlPropertyCache> &cache)
+QQmlInterceptorMetaObject::QQmlInterceptorMetaObject(QObject *obj, const QQmlPropertyCache::ConstPtr &cache)
: object(obj),
- cache(cache),
- interceptors(nullptr),
- hasAssignedMetaObjectData(false)
+ cache(cache)
{
QObjectPrivate *op = QObjectPrivate::get(obj);
@@ -295,6 +274,15 @@ QQmlInterceptorMetaObject::~QQmlInterceptorMetaObject()
void QQmlInterceptorMetaObject::registerInterceptor(QQmlPropertyIndex index, QQmlPropertyValueInterceptor *interceptor)
{
+ for (QQmlPropertyValueInterceptor *vi = interceptors; vi; vi = vi->m_next) {
+ if (Q_UNLIKELY(vi->m_propertyIndex.coreIndex() == index.coreIndex())) {
+ qWarning() << "Attempting to set another interceptor on "
+ << object->metaObject()->className() << "property"
+ << object->metaObject()->property(index.coreIndex()).name()
+ << "- unsupported";
+ }
+ }
+
interceptor->m_propertyIndex = index;
interceptor->m_next = interceptors;
interceptors = interceptor;
@@ -310,21 +298,29 @@ int QQmlInterceptorMetaObject::metaCall(QObject *o, QMetaObject::Call c, int id,
return object->qt_metacall(c, id, a);
}
-bool QQmlInterceptorMetaObject::intercept(QMetaObject::Call c, int id, void **a)
+bool QQmlInterceptorMetaObject::doIntercept(QMetaObject::Call c, int id, void **a)
{
- if (c == QMetaObject::WriteProperty && interceptors &&
- !(*reinterpret_cast<int*>(a[3]) & QQmlPropertyData::BypassInterceptor)) {
-
- for (QQmlPropertyValueInterceptor *vi = interceptors; vi; vi = vi->m_next) {
- if (vi->m_propertyIndex.coreIndex() != id)
- continue;
-
- const int valueIndex = vi->m_propertyIndex.valueTypeIndex();
- const QQmlData *data = QQmlData::get(object);
- const QMetaType metaType = data->propertyCache->property(id)->propType();
-
- if (metaType.isValid()) {
- if (valueIndex != -1) {
+ for (QQmlPropertyValueInterceptor *vi = interceptors; vi; vi = vi->m_next) {
+ if (vi->m_propertyIndex.coreIndex() != id)
+ continue;
+
+ const int valueIndex = vi->m_propertyIndex.valueTypeIndex();
+ const QQmlData *data = QQmlData::get(object);
+ const QMetaType metaType = data->propertyCache->property(id)->propType();
+
+ if (metaType.isValid()) {
+ if (valueIndex != -1 && c == QMetaObject::WriteProperty) {
+
+ // If we didn't intend to change the property this interceptor cares about,
+ // then don't bother intercepting it. There may be an animation running on
+ // the property. We shouldn't disturb it.
+ const int changedProperty
+ = (*static_cast<int *>(a[3]) & QQmlPropertyData::HasInternalIndex)
+ ? *static_cast<int *>(a[4])
+ : QV4::ReferenceObject::AllProperties;
+ if (changedProperty == QV4::ReferenceObject::AllProperties
+ || changedProperty == valueIndex) {
+ // TODO: handle intercepting bindable properties for value types?
QQmlGadgetPtrWrapper *valueType = QQmlGadgetPtrWrapper::instance(
data->context->engine(), metaType);
Q_ASSERT(valueType);
@@ -364,53 +360,61 @@ bool QQmlInterceptorMetaObject::intercept(QMetaObject::Call c, int id, void **a)
QVariant newValue(metaType, a[0]);
valueType->read(object, id);
- QVariant prevComponentValue = valueProp.read(valueType);
+ QVariant prevComponentValue = valueType->readOnGadget(valueProp);
valueType->setValue(newValue);
- QVariant newComponentValue = valueProp.read(valueType);
-
- // Don't apply the interceptor if the intercepted value has not changed
- bool updated = false;
- if (newComponentValue != prevComponentValue) {
- valueProp.write(valueType, prevComponentValue);
- valueType->write(object, id, QQmlPropertyData::DontRemoveBinding | QQmlPropertyData::BypassInterceptor);
+ QVariant newComponentValue = valueType->readOnGadget(valueProp);
- vi->write(newComponentValue);
- updated = true;
- }
+ // If the intercepted value seemingly has not changed, we still need to
+ // invoke the interceptor. There may be a pending animation that will
+ // change the value soon. Such an animation needs to be canceled if the
+ // current value is explicitly set.
+ // So, we cannot return here if prevComponentValue == newComponentValue.
+ valueType->writeOnGadget(valueProp, std::move(prevComponentValue));
+ valueType->write(object, id, QQmlPropertyData::DontRemoveBinding | QQmlPropertyData::BypassInterceptor);
- if (updated)
- return true;
- } else {
- vi->write(QVariant(metaType, a[0]));
+ vi->write(newComponentValue);
return true;
}
+ } else if (c == QMetaObject::WriteProperty) {
+ vi->write(QVariant(metaType, a[0]));
+ return true;
+ } else {
+ object->qt_metacall(c, id, a);
+ QUntypedBindable target = *reinterpret_cast<QUntypedBindable *>(a[0]);
+ return vi->bindable(reinterpret_cast<QUntypedBindable *>(a[0]), target);
}
}
}
+
return false;
}
-
-QAbstractDynamicMetaObject *QQmlInterceptorMetaObject::toDynamicMetaObject(QObject *o)
+static QMetaObject *stringCastMetaObject(QObject *o, const QMetaObject *top)
{
- if (!hasAssignedMetaObjectData) {
- *static_cast<QMetaObject *>(this) = *cache->createMetaObject();
+ for (const QMetaObject *mo = top; mo; mo = mo->superClass()) {
+ if (o->qt_metacast(mo->className()) != nullptr)
+ return const_cast<QMetaObject *>(mo);
+ }
+ return nullptr;
+}
- if (parent.isT1())
- this->d.superdata = parent.asT1()->toDynamicMetaObject(o);
- else
- this->d.superdata = parent.asT2();
+QMetaObject *QQmlInterceptorMetaObject::toDynamicMetaObject(QObject *o)
+{
+ if (!metaObject)
+ metaObject = cache->createMetaObject();
- hasAssignedMetaObjectData = true;
- }
+ if (Q_UNLIKELY(metaObject.tag() == MetaObjectInvalid))
+ return stringCastMetaObject(o, metaObject->superClass());
- return this;
+ // ### Qt7: The const_cast is only due to toDynamicMetaObject having the wrong return type.
+ // It should be const QMetaObject *. Fix this.
+ return const_cast<QMetaObject *>(metaObject.data());
}
QQmlVMEMetaObject::QQmlVMEMetaObject(QV4::ExecutionEngine *engine,
QObject *obj,
- const QQmlRefPointer<QQmlPropertyCache> &cache, const QQmlRefPointer<QV4::ExecutableCompilationUnit> &qmlCompilationUnit, int qmlObjectId)
+ const QQmlPropertyCache::ConstPtr &cache, const QQmlRefPointer<QV4::ExecutableCompilationUnit> &qmlCompilationUnit, int qmlObjectId)
: QQmlInterceptorMetaObject(obj, cache),
engine(engine),
ctxt(QQmlData::get(obj, true)->outerContext),
@@ -426,6 +430,12 @@ QQmlVMEMetaObject::QQmlVMEMetaObject(QV4::ExecutionEngine *engine,
uint size = compiledObject->nProperties + compiledObject->nFunctions;
if (size) {
QV4::Heap::MemberData *data = QV4::MemberData::allocate(engine, size);
+ // we only have a weak reference below; if the VMEMetaObject is already marked
+ // (triggered by the allocate call above)
+ // we therefore might never mark the member data; consequently, mark it now
+ QV4::WriteBarrier::markCustom(engine, [data](QV4::MarkStack *ms) {
+ data->mark(ms);
+ });
propertyAndMethodStorage.set(engine, data);
std::fill(data->values.values, data->values.values + data->values.size, QV4::Encode::undefined());
}
@@ -586,7 +596,21 @@ QDate QQmlVMEMetaObject::readPropertyAsDate(int id) const
return v->d()->data().value<QDate>();
}
-QDateTime QQmlVMEMetaObject::readPropertyAsDateTime(int id)
+QTime QQmlVMEMetaObject::readPropertyAsTime(int id) const
+{
+ QV4::MemberData *md = propertyAndMethodStorageAsMemberData();
+ if (!md)
+ return QTime();
+
+ QV4::Scope scope(engine);
+ QV4::ScopedValue sv(scope, *(md->data() + id));
+ const QV4::VariantObject *v = sv->as<QV4::VariantObject>();
+ if (!v || v->d()->data().userType() != QMetaType::QTime)
+ return QTime();
+ return v->d()->data().value<QTime>();
+}
+
+QDateTime QQmlVMEMetaObject::readPropertyAsDateTime(int id) const
{
QV4::MemberData *md = propertyAndMethodStorageAsMemberData();
if (!md)
@@ -600,6 +624,22 @@ QDateTime QQmlVMEMetaObject::readPropertyAsDateTime(int id)
return v->d()->data().value<QDateTime>();
}
+#if QT_CONFIG(regularexpression)
+QRegularExpression QQmlVMEMetaObject::readPropertyAsRegularExpression(int id) const
+{
+ QV4::MemberData *md = propertyAndMethodStorageAsMemberData();
+ if (!md)
+ return QRegularExpression();
+
+ QV4::Scope scope(engine);
+ QV4::ScopedValue sv(scope, *(md->data() + id));
+ const QV4::VariantObject *v = sv->as<QV4::VariantObject>();
+ if (!v || v->d()->data().userType() != QMetaType::QRegularExpression)
+ return QRegularExpression();
+ return v->d()->data().value<QRegularExpression>();
+}
+#endif
+
QSizeF QQmlVMEMetaObject::readPropertyAsSizeF(int id) const
{
QV4::MemberData *md = propertyAndMethodStorageAsMemberData();
@@ -642,20 +682,19 @@ QObject* QQmlVMEMetaObject::readPropertyAsQObject(int id) const
return wrapper->object();
}
-QVector<QQmlGuard<QObject>> *QQmlVMEMetaObject::readPropertyAsList(int id) const
+void QQmlVMEMetaObject::initPropertyAsList(int id) const
{
QV4::MemberData *md = propertyAndMethodStorageAsMemberData();
if (!md)
- return nullptr;
+ return;
QV4::Scope scope(engine);
- QV4::Scoped<QV4::VariantObject> v(scope, *(md->data() + id));
- if (!v || (int)v->d()->data().userType() != qMetaTypeId<QVector<QQmlGuard<QObject>> >()) {
- QVariant variant(QVariant::fromValue(QVector<QQmlGuard<QObject>>()));
- v = engine->newVariantObject(variant);
+ QV4::ScopedObject v(scope, *(md->data() + id));
+ if (!v) {
+ v = engine->newObject();
+ v->arrayCreate();
md->set(engine, id, v);
}
- return static_cast<QVector<QQmlGuard<QObject>> *>(v->d()->data().data());
}
QRectF QQmlVMEMetaObject::readPropertyAsRectF(int id) const
@@ -692,186 +731,296 @@ int QQmlVMEMetaObject::metaCall(QObject *o, QMetaObject::Call c, int _id, void *
id -= propOffset();
if (id < propertyCount) {
+ // if we reach this point, propertyCount must have been > 0, and thus compiledObject != nullptr
+ Q_ASSERT(compiledObject);
const QV4::CompiledData::Property &property = compiledObject->propertyTable()[id];
- const QV4::CompiledData::BuiltinType t = property.builtinType();
+ const QV4::CompiledData::CommonType t = property.commonType();
// the context can be null if accessing var properties from cpp after re-parenting an item.
QQmlEnginePrivate *ep = (ctxt.isNull() || ctxt->engine() == nullptr)
? nullptr
: QQmlEnginePrivate::get(ctxt->engine());
- const int fallbackMetaType = QQmlPropertyCacheCreatorBase::metaTypeForPropertyType(t).id();
-
if (c == QMetaObject::ReadProperty) {
- switch (t) {
- case QV4::CompiledData::BuiltinType::Int:
- *reinterpret_cast<int *>(a[0]) = readPropertyAsInt(id);
- break;
- case QV4::CompiledData::BuiltinType::Bool:
- *reinterpret_cast<bool *>(a[0]) = readPropertyAsBool(id);
- break;
- case QV4::CompiledData::BuiltinType::Real:
- *reinterpret_cast<double *>(a[0]) = readPropertyAsDouble(id);
- break;
- case QV4::CompiledData::BuiltinType::String:
- *reinterpret_cast<QString *>(a[0]) = readPropertyAsString(id);
- break;
- case QV4::CompiledData::BuiltinType::Url:
- *reinterpret_cast<QUrl *>(a[0]) = readPropertyAsUrl(id);
- break;
- case QV4::CompiledData::BuiltinType::Date:
- *reinterpret_cast<QDate *>(a[0]) = readPropertyAsDate(id);
- break;
- case QV4::CompiledData::BuiltinType::DateTime:
- *reinterpret_cast<QDateTime *>(a[0]) = readPropertyAsDateTime(id);
- break;
- case QV4::CompiledData::BuiltinType::Rect:
- *reinterpret_cast<QRectF *>(a[0]) = readPropertyAsRectF(id);
- break;
- 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::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);
- } 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) {
+ if (property.isList()) {
+ // _id because this is an absolute property ID.
+ const QQmlPropertyData *propertyData = cache->property(_id);
+ const QMetaType propType = propertyData->propType();
+
+ if (propType.flags().testFlag(QMetaType::IsQmlList)) {
// when reading from the list, we need to find the correct MetaObject,
- // namely this. However, obejct->metaObject might point to any MetaObject
- // down the inheritance hierarchy, so we need to store how far we have
- // to go down
+ // namely this. However, obejct->metaObject might point to any
+ // MetaObject down the inheritance hierarchy, so we need to store how
+ // far we have to go down
// To do this, we encode the hierarchy depth together with the id of the
// property in a single quintptr, with the first half storing the depth
// and the second half storing the property id
- auto mo = object->metaObject();
+ auto mo = static_cast<QQmlVMEMetaObject *>(
+ QObjectPrivate::get(object)->metaObject);
quintptr inheritanceDepth = 0u;
while (mo && mo != this) {
- mo = mo->superClass();
+ mo = mo->parentVMEMetaObject();
++inheritanceDepth;
}
- constexpr quintptr usableBits = sizeof(quintptr) * CHAR_BIT;
- if (Q_UNLIKELY(inheritanceDepth >= (quintptr(1) << quintptr(usableBits / 2u) ) )) {
- qmlWarning(object) << "Too many objects in inheritance hierarchy for list property";
+ constexpr quintptr idBits = sizeof(quintptr) * CHAR_BIT / 2u;
+ if (Q_UNLIKELY(inheritanceDepth >= (quintptr(1) << idBits))) {
+ qmlWarning(object) << "Too many objects in inheritance hierarchy "
+ "for list property";
return -1;
}
- if (Q_UNLIKELY(quintptr(id) >= (quintptr(1) << quintptr(usableBits / 2) ) )) {
- qmlWarning(object) << "Too many properties in object for list property";
+ if (Q_UNLIKELY(quintptr(id) >= (quintptr(1) << idBits))) {
+ qmlWarning(object) << "Too many properties in object "
+ "for list property";
return -1;
}
- quintptr encodedIndex = (inheritanceDepth << (usableBits/2)) + id;
-
+ quintptr encodedIndex = (inheritanceDepth << idBits) + id;
- readPropertyAsList(id); // Initializes if necessary
+ initPropertyAsList(id);
*static_cast<QQmlListProperty<QObject> *>(a[0])
= QQmlListProperty<QObject>(
object, reinterpret_cast<void *>(quintptr(encodedIndex)),
list_append, list_count, list_at,
list_clear, list_replace, list_removeLast);
+ } else if (QV4::MemberData *md = propertyAndMethodStorageAsMemberData()) {
+ // Value type list
+ QV4::Scope scope(engine);
+ QV4::Scoped<QV4::Sequence> sequence(scope, *(md->data() + id));
+ const void *data = sequence
+ ? QV4::SequencePrototype::getRawContainerPtr(sequence, propType)
+ : nullptr;
+ propType.destruct(a[0]);
+ propType.construct(a[0], data);
} else {
- *reinterpret_cast<QObject **>(a[0]) = readPropertyAsQObject(id);
+ qmlWarning(object) << "Cannot find member data";
+ }
+ } else {
+ switch (t) {
+ case QV4::CompiledData::CommonType::Void:
+ break;
+ case QV4::CompiledData::CommonType::Int:
+ *reinterpret_cast<int *>(a[0]) = readPropertyAsInt(id);
+ break;
+ case QV4::CompiledData::CommonType::Bool:
+ *reinterpret_cast<bool *>(a[0]) = readPropertyAsBool(id);
+ break;
+ case QV4::CompiledData::CommonType::Real:
+ *reinterpret_cast<double *>(a[0]) = readPropertyAsDouble(id);
+ break;
+ case QV4::CompiledData::CommonType::String:
+ *reinterpret_cast<QString *>(a[0]) = readPropertyAsString(id);
+ break;
+ case QV4::CompiledData::CommonType::Url:
+ *reinterpret_cast<QUrl *>(a[0]) = readPropertyAsUrl(id);
+ break;
+ case QV4::CompiledData::CommonType::Date:
+ *reinterpret_cast<QDate *>(a[0]) = readPropertyAsDate(id);
+ break;
+ case QV4::CompiledData::CommonType::DateTime:
+ *reinterpret_cast<QDateTime *>(a[0]) = readPropertyAsDateTime(id);
+ break;
+ case QV4::CompiledData::CommonType::RegExp:
+#if QT_CONFIG(regularexpression)
+ *reinterpret_cast<QRegularExpression *>(a[0])
+ = readPropertyAsRegularExpression(id);
+#endif
+ break;
+ case QV4::CompiledData::CommonType::Rect:
+ *reinterpret_cast<QRectF *>(a[0]) = readPropertyAsRectF(id);
+ break;
+ case QV4::CompiledData::CommonType::Size:
+ *reinterpret_cast<QSizeF *>(a[0]) = readPropertyAsSizeF(id);
+ break;
+ case QV4::CompiledData::CommonType::Point:
+ *reinterpret_cast<QPointF *>(a[0]) = readPropertyAsPointF(id);
+ break;
+ case QV4::CompiledData::CommonType::Time:
+ *reinterpret_cast<QTime *>(a[0]) = readPropertyAsTime(id);
+ break;
+ case QV4::CompiledData::CommonType::Var:
+ if (ep) {
+ *reinterpret_cast<QVariant *>(a[0]) = readPropertyAsVariant(id);
+ } else {
+ // if the context was disposed,
+ // we just return an invalid variant from read.
+ *reinterpret_cast<QVariant *>(a[0]) = QVariant();
+ }
+ break;
+ case QV4::CompiledData::CommonType::Invalid:
+ if (QV4::MemberData *md = propertyAndMethodStorageAsMemberData()) {
+ QV4::Scope scope(engine);
+ QV4::ScopedValue sv(scope, *(md->data() + id));
+
+ // _id because this is an absolute property ID.
+ const QQmlPropertyData *propertyData = cache->property(_id);
+
+ if (propertyData->isQObject()) {
+ if (const auto *wrap = sv->as<QV4::QObjectWrapper>())
+ *reinterpret_cast<QObject **>(a[0]) = wrap->object();
+ else
+ *reinterpret_cast<QObject **>(a[0]) = nullptr;
+ } else {
+ const QMetaType propType = propertyData->propType();
+ const void *data = nullptr;
+ if (const auto *v = sv->as<QV4::VariantObject>()) {
+ const QVariant &variant = v->d()->data();
+ if (variant.metaType() == propType)
+ data = variant.constData();
+ }
+ propType.destruct(a[0]);
+ propType.construct(a[0], data);
+ }
+ } else {
+ qmlWarning(object) << "Cannot find member data";
+ }
}
}
-
} 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::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());
+
+ if (property.isList()) {
+ // _id because this is an absolute property ID.
+ const QQmlPropertyData *propertyData = cache->property(_id);
+ const QMetaType propType = propertyData->propType();
+
+ if (propType.flags().testFlag(QMetaType::IsQmlList)) {
+ // Writing such a property is not supported. Content is added through
+ // the list property methods.
+ } else if (QV4::MemberData *md = propertyAndMethodStorageAsMemberData()) {
+ // Value type list
+ QV4::Scope scope(engine);
+ QV4::Scoped<QV4::Sequence> sequence(scope, *(md->data() + id));
+ void *data = sequence
+ ? QV4::SequencePrototype::getRawContainerPtr(sequence, propType)
+ : nullptr;
+ if (data) {
+ if (!propType.equals(data, a[0])) {
+ propType.destruct(data);
+ propType.construct(data, a[0]);
+ needActivate = true;
+ }
+ } else {
+ if (const QQmlType type = QQmlMetaType::qmlListType(propType);
+ type.isSequentialContainer()) {
+ sequence = QV4::SequencePrototype::fromData(
+ engine, propType, type.listMetaSequence(), a[0]);
+ } else if (QSequentialIterable iterable;
+ QMetaType::convert(
+ propType, a[0],
+ QMetaType::fromType<QSequentialIterable>(),
+ &iterable)) {
+ sequence = QV4::SequencePrototype::fromData(
+ engine, propType, iterable.metaContainer(), a[0]);
+ } else {
+ sequence = QV4::Encode::undefined();
+ }
+ md->set(engine, id, sequence);
+ if (sequence->isUndefined()) {
+ qmlWarning(object)
+ << "Could not create a QML sequence object for "
+ << propType.name();
+ }
+ needActivate = true;
}
- needActivate = !QQml_valueTypeProvider()->equalValueType(fallbackMetaType, a[0], v->d()->data());
- QQml_valueTypeProvider()->writeValueType(fallbackMetaType, a[0], v->d()->data());
- }
- break;
- case QV4::CompiledData::BuiltinType::Var:
- if (ep)
- writeProperty(id, *reinterpret_cast<QVariant *>(a[0]));
- break;
- case QV4::CompiledData::BuiltinType::InvalidBuiltin:
- if (property.isList) {
- // Writing such a property is not supported. Content is added through the list property
- // methods.
} else {
- needActivate = *reinterpret_cast<QObject **>(a[0]) != readPropertyAsQObject(id);
- writeProperty(id, *reinterpret_cast<QObject **>(a[0]));
+ qmlWarning(object) << "Cannot find member data";
+ }
+ } else {
+ switch (t) {
+ case QV4::CompiledData::CommonType::Void:
+ break;
+ case QV4::CompiledData::CommonType::Int:
+ needActivate = *reinterpret_cast<int *>(a[0]) != readPropertyAsInt(id);
+ writeProperty(id, *reinterpret_cast<int *>(a[0]));
+ break;
+ case QV4::CompiledData::CommonType::Bool:
+ needActivate = *reinterpret_cast<bool *>(a[0]) != readPropertyAsBool(id);
+ writeProperty(id, *reinterpret_cast<bool *>(a[0]));
+ break;
+ case QV4::CompiledData::CommonType::Real:
+ needActivate = *reinterpret_cast<double *>(a[0]) != readPropertyAsDouble(id);
+ writeProperty(id, *reinterpret_cast<double *>(a[0]));
+ break;
+ case QV4::CompiledData::CommonType::String:
+ needActivate = *reinterpret_cast<QString *>(a[0]) != readPropertyAsString(id);
+ writeProperty(id, *reinterpret_cast<QString *>(a[0]));
+ break;
+ case QV4::CompiledData::CommonType::Url:
+ needActivate = *reinterpret_cast<QUrl *>(a[0]) != readPropertyAsUrl(id);
+ writeProperty(id, *reinterpret_cast<QUrl *>(a[0]));
+ break;
+ case QV4::CompiledData::CommonType::Date:
+ needActivate = *reinterpret_cast<QDate *>(a[0]) != readPropertyAsDate(id);
+ writeProperty(id, *reinterpret_cast<QDate *>(a[0]));
+ break;
+ case QV4::CompiledData::CommonType::DateTime:
+ needActivate = *reinterpret_cast<QDateTime *>(a[0]) != readPropertyAsDateTime(id);
+ writeProperty(id, *reinterpret_cast<QDateTime *>(a[0]));
+ break;
+ case QV4::CompiledData::CommonType::RegExp:
+#if QT_CONFIG(regularexpression)
+ needActivate = *reinterpret_cast<QRegularExpression *>(a[0])
+ != readPropertyAsRegularExpression(id);
+ writeProperty(id, *reinterpret_cast<QRegularExpression *>(a[0]));
+#endif
+ break;
+ case QV4::CompiledData::CommonType::Rect:
+ needActivate = *reinterpret_cast<QRectF *>(a[0]) != readPropertyAsRectF(id);
+ writeProperty(id, *reinterpret_cast<QRectF *>(a[0]));
+ break;
+ case QV4::CompiledData::CommonType::Size:
+ needActivate = *reinterpret_cast<QSizeF *>(a[0]) != readPropertyAsSizeF(id);
+ writeProperty(id, *reinterpret_cast<QSizeF *>(a[0]));
+ break;
+ case QV4::CompiledData::CommonType::Point:
+ needActivate = *reinterpret_cast<QPointF *>(a[0]) != readPropertyAsPointF(id);
+ writeProperty(id, *reinterpret_cast<QPointF *>(a[0]));
+ break;
+ case QV4::CompiledData::CommonType::Time:
+ needActivate = *reinterpret_cast<QTime *>(a[0]) != readPropertyAsTime(id);
+ writeProperty(id, *reinterpret_cast<QTime *>(a[0]));
+ break;
+ case QV4::CompiledData::CommonType::Var:
+ if (ep)
+ writeProperty(id, *reinterpret_cast<QVariant *>(a[0]));
+ break;
+ case QV4::CompiledData::CommonType::Invalid:
+ if (QV4::MemberData *md = propertyAndMethodStorageAsMemberData()) {
+ QV4::Scope scope(engine);
+ QV4::ScopedValue sv(scope, *(md->data() + id));
+
+ // _id because this is an absolute property ID.
+ const QQmlPropertyData *propertyData = cache->property(_id);
+
+ if (propertyData->isQObject()) {
+ QObject *arg = *reinterpret_cast<QObject **>(a[0]);
+ if (const auto *wrap = sv->as<QV4::QObjectWrapper>())
+ needActivate = wrap->object() != arg;
+ else if (arg != nullptr || !sv->isNull())
+ needActivate = true;
+ if (needActivate)
+ writeProperty(id, arg);
+ } else {
+ const QMetaType propType = propertyData->propType();
+ if (const auto *v = sv->as<QV4::VariantObject>()) {
+ QVariant &variant = v->d()->data();
+ if (variant.metaType() != propType) {
+ needActivate = true;
+ variant = QVariant(propType, a[0]);
+ } else if (!propType.equals(variant.constData(), a[0])) {
+ needActivate = true;
+ propType.destruct(variant.data());
+ propType.construct(variant.data(), a[0]);
+ }
+ } else {
+ needActivate = true;
+ md->set(engine, id, engine->newVariantObject(
+ propType, a[0]));
+ }
+ }
+ } else {
+ qmlWarning(object) << "Cannot find member data";
+ }
}
-
}
if (needActivate)
@@ -886,16 +1035,18 @@ int QQmlVMEMetaObject::metaCall(QObject *o, QMetaObject::Call c, int _id, void *
if (id < aliasCount) {
const QV4::CompiledData::Alias *aliasData = &compiledObject->aliasTable()[id];
- if ((aliasData->flags & QV4::CompiledData::Alias::AliasPointsToPointerObject) && c == QMetaObject::ReadProperty)
- *reinterpret_cast<void **>(a[0]) = nullptr;
+ if (aliasData->hasFlag(QV4::CompiledData::Alias::AliasPointsToPointerObject)
+ && c == QMetaObject::ReadProperty){
+ *reinterpret_cast<void **>(a[0]) = nullptr;
+ }
if (ctxt.isNull())
return -1;
- while (aliasData->aliasToLocalAlias)
+ while (aliasData->isAliasToLocalAlias())
aliasData = &compiledObject->aliasTable()[aliasData->localAliasIndex];
- QObject *target = ctxt->idValue(aliasData->targetObjectId);
+ QObject *target = ctxt->idValue(aliasData->targetObjectId());
if (!target)
return -1;
@@ -914,15 +1065,20 @@ int QQmlVMEMetaObject::metaCall(QObject *o, QMetaObject::Call c, int _id, void *
int coreIndex = encodedIndex.coreIndex();
const int valueTypePropertyIndex = encodedIndex.valueTypeIndex();
- // Remove binding (if any) on write
- if(c == QMetaObject::WriteProperty) {
- int flags = *reinterpret_cast<int*>(a[3]);
- if (flags & QQmlPropertyData::RemoveBindingOnAliasWrite) {
- QQmlData *targetData = QQmlData::get(target);
- if (targetData && targetData->hasBindingBit(coreIndex))
- QQmlPropertyPrivate::removeBinding(target, encodedIndex);
+ const auto removePendingBinding
+ = [c, a](QObject *target, int coreIndex, QQmlPropertyIndex encodedIndex) {
+ // Remove binding (if any) on write
+ if (c == QMetaObject::WriteProperty) {
+ int flags = *reinterpret_cast<int*>(a[3]);
+ if (flags & QQmlPropertyData::RemoveBindingOnAliasWrite) {
+ QQmlData *targetData = QQmlData::get(target);
+ if (targetData && targetData->hasBindingBit(coreIndex)) {
+ QQmlPropertyPrivate::removeBinding(target, encodedIndex);
+ targetData->clearBindingBit(coreIndex);
+ }
+ }
}
- }
+ };
if (valueTypePropertyIndex != -1) {
if (!targetDData->propertyCache)
@@ -932,21 +1088,27 @@ int QQmlVMEMetaObject::metaCall(QObject *o, QMetaObject::Call c, int _id, void *
QQmlGadgetPtrWrapper *valueType = QQmlGadgetPtrWrapper::instance(
ctxt->engine(), pd->propType());
if (valueType) {
+ removePendingBinding(target, coreIndex, encodedIndex);
valueType->read(target, coreIndex);
int rv = QMetaObject::metacall(valueType, c, valueTypePropertyIndex, a);
if (c == QMetaObject::WriteProperty)
- valueType->write(target, coreIndex, {});
+ valueType->write(target, coreIndex, QQmlPropertyData::HasInternalIndex,
+ valueTypePropertyIndex);
return rv;
} else {
// deep alias
void *argv[1] = { &target };
QMetaObject::metacall(target, QMetaObject::ReadProperty, coreIndex, argv);
+ removePendingBinding(
+ target, valueTypePropertyIndex,
+ QQmlPropertyIndex(valueTypePropertyIndex));
return QMetaObject::metacall(target, c, valueTypePropertyIndex, a);
}
} else {
+ removePendingBinding(target, coreIndex, encodedIndex);
return QMetaObject::metacall(target, c, coreIndex, a);
}
@@ -986,10 +1148,10 @@ int QQmlVMEMetaObject::metaCall(QObject *o, QMetaObject::Call c, int _id, void *
// are not rewritten correctly but this bug is deemed out-of-scope to fix for
// performance reasons; see QTBUG-24064) and thus compilation will have failed.
QQmlError e;
- e.setDescription(QLatin1String("Exception occurred during compilation of "
- "function: ")
- + QString::fromUtf8(QMetaObject::method(_id)
- .methodSignature()));
+ e.setDescription(
+ QStringLiteral(
+ "Exception occurred during compilation of function: ")
+ + QString::fromUtf8(metaObject->method(_id).methodSignature()));
ep->warning(e);
return -1; // The dynamic method with that id is not available.
}
@@ -997,35 +1159,20 @@ int QQmlVMEMetaObject::metaCall(QObject *o, QMetaObject::Call c, int _id, void *
auto methodData = cache->method(_id);
auto arguments = methodData->hasArguments() ? methodData->arguments() : nullptr;
- const unsigned int parameterCount = (arguments && arguments->names) ? arguments->names->count() : 0;
- Q_ASSERT(parameterCount == function->formalParameterCount());
-
- QV4::JSCallData jsCallData(scope, parameterCount);
- *jsCallData->thisObject = v4->global();
-
- for (uint ii = 0; ii < parameterCount; ++ii) {
- jsCallData->args[ii] = scope.engine->metaTypeToJS(QMetaType(arguments->arguments[ii + 1]), a[ii + 1]);
+ if (arguments && arguments->names) {
+ const quint32 parameterCount = arguments->names->size();
+ Q_ASSERT(parameterCount == function->formalParameterCount());
+ function->call(object, a, arguments->types, parameterCount);
+ } else {
+ Q_ASSERT(function->formalParameterCount() == 0);
+ const QMetaType returnType = methodData->propType();
+ function->call(object, a, &returnType, 0);
}
- const QMetaType returnType = methodData->propType();
- QV4::ScopedValue result(scope, function->call(jsCallData));
if (scope.hasException()) {
QQmlError error = scope.engine->catchExceptionAsQmlError();
if (error.isValid())
ep->warning(error);
- if (a[0]) {
- returnType.destruct(a[0]);
- returnType.construct(a[0], nullptr);
- }
- } else {
- if (a[0]) {
- // When the return type is QVariant, JS objects are to be returned as QJSValue wrapped in
- // QVariant.
- if (returnType == QMetaType::fromType<QVariant>())
- *(QVariant *)a[0] = scope.engine->toVariant(result, 0);
- else
- scope.engine->metaTypeFromJS(result, returnType.id(), a[0]);
- }
}
ep->dereferenceScarceResources(); // "release" scarce resources if top-level expression evaluation is complete.
@@ -1057,7 +1204,7 @@ QV4::ReturnedValue QQmlVMEMetaObject::method(int index) const
QV4::ReturnedValue QQmlVMEMetaObject::readVarProperty(int id) const
{
- Q_ASSERT(compiledObject && compiledObject->propertyTable()[id].builtinType() == QV4::CompiledData::BuiltinType::Var);
+ Q_ASSERT(compiledObject && compiledObject->propertyTable()[id].commonType() == QV4::CompiledData::CommonType::Var);
QV4::MemberData *md = propertyAndMethodStorageAsMemberData();
if (md)
@@ -1075,14 +1222,14 @@ QVariant QQmlVMEMetaObject::readPropertyAsVariant(int id) const
const QV4::VariantObject *v = (md->data() + id)->as<QV4::VariantObject>();
if (v)
return v->d()->data();
- return engine->toVariant(*(md->data() + id), -1);
+ return QV4::ExecutionEngine::toVariant(*(md->data() + id), QMetaType {});
}
return QVariant();
}
void QQmlVMEMetaObject::writeVarProperty(int id, const QV4::Value &value)
{
- Q_ASSERT(compiledObject && compiledObject->propertyTable()[id].builtinType() == QV4::CompiledData::BuiltinType::Var);
+ Q_ASSERT(compiledObject && compiledObject->propertyTable()[id].commonType() == QV4::CompiledData::CommonType::Var);
QV4::MemberData *md = propertyAndMethodStorageAsMemberData();
if (!md)
@@ -1101,6 +1248,7 @@ void QQmlVMEMetaObject::writeVarProperty(int id, const QV4::Value &value)
// automatically released by the engine until no other references to it exist.
if (QV4::VariantObject *v = const_cast<QV4::VariantObject*>(value.as<QV4::VariantObject>())) {
v->addVmePropertyReference();
+ md->set(engine, id, value);
} else if (QV4::QObjectWrapper *wrapper = const_cast<QV4::QObjectWrapper*>(value.as<QV4::QObjectWrapper>())) {
// We need to track this QObject to signal its deletion
valueObject = wrapper->object();
@@ -1110,19 +1258,39 @@ void QQmlVMEMetaObject::writeVarProperty(int id, const QV4::Value &value)
guard = new QQmlVMEVariantQObjectPtr();
varObjectGuards.append(guard);
}
+ md->set(engine, id, value);
+ } else if (const QV4::Sequence *sequence = value.as<QV4::Sequence>()) {
+ QV4::Heap::Sequence *p = sequence->d();
+ if (p->enforcesLocation()) {
+ // If the sequence enforces its location, we don't want it to be updated anymore after
+ // being written to a property.
+ md->set(engine, id, QV4::ReferenceObject::detached(p));
+ } else {
+ // Otherwise, make sure the reference carries some value so that we can still call
+ // toVariant() on it (see note in QV4::SequencePrototype::toVariant).
+ if (!p->hasData())
+ QV4::ReferenceObject::readReference(p);
+ md->set(engine, id, p);
+ }
+ } else if (const QV4::QQmlValueTypeWrapper *wrapper = value.as<QV4::QQmlValueTypeWrapper>()) {
+ // If the value type enforces its location, we don't want it to be updated anymore after
+ // being written to a property.
+ QV4::Heap::QQmlValueTypeWrapper *p = wrapper->d();
+ md->set(engine, id, p->enforcesLocation() ? QV4::ReferenceObject::detached(p) : p);
+ } else {
+ md->set(engine, id, value);
}
if (guard)
guard->setGuardedValue(valueObject, this, id);
- // Write the value and emit change signal as appropriate.
- md->set(engine, id, value);
+ // Emit change signal as appropriate.
activate(object, methodOffset() + id, nullptr);
}
void QQmlVMEMetaObject::writeProperty(int id, const QVariant &value)
{
- if (compiledObject && compiledObject->propertyTable()[id].builtinType() == QV4::CompiledData::BuiltinType::Var) {
+ if (compiledObject && compiledObject->propertyTable()[id].commonType() == QV4::CompiledData::CommonType::Var) {
QV4::MemberData *md = propertyAndMethodStorageAsMemberData();
if (!md)
return;
@@ -1161,7 +1329,7 @@ void QQmlVMEMetaObject::writeProperty(int id, const QVariant &value)
v->d()->data() != value);
if (v)
v->removeVmePropertyReference();
- md->set(engine, id, engine->newVariantObject(value));
+ md->set(engine, id, engine->newVariantObject(value.metaType(), value.constData()));
v = static_cast<const QV4::VariantObject *>(md->data() + id);
v->addVmePropertyReference();
}
@@ -1226,7 +1394,7 @@ void QQmlVMEMetaObject::setVMEProperty(int index, const QV4::Value &v)
void QQmlVMEMetaObject::ensureQObjectWrapper()
{
Q_ASSERT(cache);
- QV4::QObjectWrapper::wrap(engine, object);
+ QV4::QObjectWrapper::ensureWrapper(engine, object);
}
void QQmlVMEMetaObject::mark(QV4::MarkStack *markStack)
@@ -1253,9 +1421,9 @@ bool QQmlVMEMetaObject::aliasTarget(int index, QObject **target, int *coreIndex,
const int aliasId = index - propOffset() - compiledObject->nProperties;
const QV4::CompiledData::Alias *aliasData = &compiledObject->aliasTable()[aliasId];
- while (aliasData->aliasToLocalAlias)
+ while (aliasData->isAliasToLocalAlias())
aliasData = &compiledObject->aliasTable()[aliasData->localAliasIndex];
- *target = ctxt->idValue(aliasData->targetObjectId);
+ *target = ctxt->idValue(aliasData->targetObjectId());
if (!*target)
return false;
@@ -1283,7 +1451,7 @@ void QQmlVMEMetaObject::connectAlias(int aliasId)
}
endpoint->metaObject = this;
- endpoint->connect(ctxt->idValueBindings(aliasData->targetObjectId));
+ endpoint->connect(ctxt->idValueBindings(aliasData->targetObjectId()));
endpoint->tryConnect();
}
diff --git a/src/qml/qml/qqmlvmemetaobject_p.h b/src/qml/qml/qqmlvmemetaobject_p.h
index 10fa0d89a2..d37c20a41b 100644
--- a/src/qml/qml/qqmlvmemetaobject_p.h
+++ b/src/qml/qml/qqmlvmemetaobject_p.h
@@ -1,42 +1,6 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Copyright (C) 2016 BasysKom GmbH.
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// Copyright (C) 2016 BasysKom GmbH.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLVMEMETAOBJECT_P_H
#define QQMLVMEMETAOBJECT_P_H
@@ -52,57 +16,102 @@
// We mean it.
//
-#include "qqml.h"
+#include <private/qbipointer_p.h>
+#include <private/qqmlguard_p.h>
+#include <private/qqmlguardedcontextdata_p.h>
+#include <private/qqmlpropertyvalueinterceptor_p.h>
+#include <private/qv4object_p.h>
+#include <private/qv4value_p.h>
-#include <QtCore/QMetaObject>
-#include <QtCore/QBitArray>
-#include <QtCore/QPair>
-#include <QtCore/QDate>
-#include <QtCore/qlist.h>
+#include <QtCore/private/qobject_p.h>
+
+#if QT_CONFIG(regularexpression)
+#include <QtCore/qregularexpression.h>
+#endif
+
+#include <QtCore/qbitarray.h>
+#include <QtCore/qdatetime.h>
#include <QtCore/qdebug.h>
+#include <QtCore/qlist.h>
+#include <QtCore/qmetaobject.h>
+#include <QtCore/qpair.h>
-#include <private/qobject_p.h>
+QT_BEGIN_NAMESPACE
-#include "qqmlguard_p.h"
+class QQmlVMEMetaObject;
+class QQmlVMEResolvedList
+{
+ Q_DISABLE_COPY_MOVE(QQmlVMEResolvedList)
-#include <private/qqmlguardedcontextdata_p.h>
-#include <private/qflagpointer_p.h>
+public:
+ QQmlVMEResolvedList(QQmlListProperty<QObject> *prop);
+ ~QQmlVMEResolvedList();
-#include <private/qv4object_p.h>
-#include <private/qv4value_p.h>
-#include <private/qqmlpropertyvalueinterceptor_p.h>
+ QQmlVMEMetaObject *metaObject() const { return m_metaObject; }
+ QV4::Heap::Object *list() const { return m_list; }
+ quintptr id() const { return m_id; }
-QT_BEGIN_NAMESPACE
+ void append(QObject *o) const;
+ void replace(qsizetype i, QObject *o) const;
+ QObject *at(qsizetype i) const;
+
+ qsizetype size() const { return m_list->arrayData->length(); }
+
+ void clear() const
+ {
+ QV4::Scope scope(m_list->internalClass->engine);
+ QV4::ScopedObject object(scope, m_list);
+ m_list->arrayData->vtable()->truncate(object, 0);
+ }
+
+ void removeLast() const
+ {
+ const uint length = m_list->arrayData->length();
+ if (length == 0)
+ return;
+
+ QV4::Scope scope(m_list->internalClass->engine);
+ QV4::ScopedObject object(scope, m_list);
+ m_list->arrayData->vtable()->truncate(object, length - 1);
+ }
+
+ void activateSignal() const;
+
+private:
+ QQmlVMEMetaObject *m_metaObject = nullptr;
+ QV4::Heap::Object *m_list = nullptr;
+ quintptr m_id = 0;
+};
-class QQmlVMEMetaObject;
class QQmlVMEVariantQObjectPtr : public QQmlGuard<QObject>
{
public:
inline QQmlVMEVariantQObjectPtr();
- inline ~QQmlVMEVariantQObjectPtr() override;
- inline void objectDestroyed(QObject *) override;
inline void setGuardedValue(QObject *obj, QQmlVMEMetaObject *target, int index);
QQmlVMEMetaObject *m_target;
int m_index;
+
+private:
+ static void objectDestroyedImpl(QQmlGuardImpl *guard);
};
-class Q_QML_PRIVATE_EXPORT QQmlInterceptorMetaObject : public QAbstractDynamicMetaObject
+class Q_QML_EXPORT QQmlInterceptorMetaObject : public QDynamicMetaObjectData
{
public:
- QQmlInterceptorMetaObject(QObject *obj, const QQmlRefPointer<QQmlPropertyCache> &cache);
+ QQmlInterceptorMetaObject(QObject *obj, const QQmlPropertyCache::ConstPtr &cache);
~QQmlInterceptorMetaObject() override;
void registerInterceptor(QQmlPropertyIndex index, QQmlPropertyValueInterceptor *interceptor);
static QQmlInterceptorMetaObject *get(QObject *obj);
- QAbstractDynamicMetaObject *toDynamicMetaObject(QObject *o) override;
+ QMetaObject *toDynamicMetaObject(QObject *o) override;
// Used by auto-tests for inspection
- QQmlPropertyCache *propertyCache() const { return cache.data(); }
+ QQmlPropertyCache::ConstPtr propertyCache() const { return cache; }
bool intercepts(QQmlPropertyIndex propertyIndex) const
{
@@ -115,17 +124,40 @@ public:
return false;
}
+ void invalidate() { metaObject.setTag(MetaObjectInvalid); }
+
+ QObject *object = nullptr;
+ QQmlPropertyCache::ConstPtr cache;
+
protected:
int metaCall(QObject *o, QMetaObject::Call c, int id, void **a) override;
- bool intercept(QMetaObject::Call c, int id, void **a);
+ bool intercept(QMetaObject::Call c, int id, void **a)
+ {
+ if (!interceptors)
+ return false;
+
+ switch (c) {
+ case QMetaObject::WriteProperty:
+ if (*reinterpret_cast<int*>(a[3]) & QQmlPropertyData::BypassInterceptor)
+ return false;
+ break;
+ case QMetaObject::BindableProperty:
+ break;
+ default:
+ return false;
+ }
+
+ return doIntercept(c, id, a);
+ }
-public:
- QObject *object;
- QQmlRefPointer<QQmlPropertyCache> cache;
QBiPointer<QDynamicMetaObjectData, const QMetaObject> parent;
- QQmlPropertyValueInterceptor *interceptors;
- bool hasAssignedMetaObjectData;
+ enum MetaObjectValidity { MetaObjectValid, MetaObjectInvalid };
+ QTaggedPointer<const QMetaObject, MetaObjectValidity> metaObject;
+
+private:
+ bool doIntercept(QMetaObject::Call c, int id, void **a);
+ QQmlPropertyValueInterceptor *interceptors = nullptr;
};
inline QQmlInterceptorMetaObject *QQmlInterceptorMetaObject::get(QObject *obj)
@@ -141,11 +173,11 @@ inline QQmlInterceptorMetaObject *QQmlInterceptorMetaObject::get(QObject *obj)
}
class QQmlVMEMetaObjectEndpoint;
-class Q_QML_PRIVATE_EXPORT QQmlVMEMetaObject : public QQmlInterceptorMetaObject
+class Q_QML_EXPORT QQmlVMEMetaObject : public QQmlInterceptorMetaObject
{
public:
QQmlVMEMetaObject(QV4::ExecutionEngine *engine, QObject *obj,
- const QQmlRefPointer<QQmlPropertyCache> &cache,
+ const QQmlPropertyCache::ConstPtr &cache,
const QQmlRefPointer<QV4::ExecutableCompilationUnit> &qmlCompilationUnit,
int qmlObjectId);
~QQmlVMEMetaObject() override;
@@ -163,6 +195,11 @@ public:
static QQmlVMEMetaObject *getForMethod(QObject *o, int coreIndex);
static QQmlVMEMetaObject *getForSignal(QObject *o, int coreIndex);
+ static void list_append(QQmlListProperty<QObject> *prop, QObject *o);
+ static void list_clear(QQmlListProperty<QObject> *prop);
+ static void list_append_nosignal(QQmlListProperty<QObject> *prop, QObject *o);
+ static void list_clear_nosignal(QQmlListProperty<QObject> *prop);
+
protected:
int metaCall(QObject *o, QMetaObject::Call _c, int _id, void **_a) override;
@@ -188,10 +225,16 @@ public:
QPointF readPropertyAsPointF(int id) const;
QUrl readPropertyAsUrl(int id) const;
QDate readPropertyAsDate(int id) const;
- QDateTime readPropertyAsDateTime(int id);
+ QTime readPropertyAsTime(int id) const;
+ QDateTime readPropertyAsDateTime(int id) const;
+
+#if QT_CONFIG(regularexpression)
+ QRegularExpression readPropertyAsRegularExpression(int id) const;
+#endif
+
QRectF readPropertyAsRectF(int id) const;
QObject *readPropertyAsQObject(int id) const;
- QVector<QQmlGuard<QObject> > *readPropertyAsList(int id) const;
+ void initPropertyAsList(int id) const;
void writeProperty(int id, int v);
void writeProperty(int id, bool v);
@@ -204,8 +247,9 @@ public:
QV4::MemberData *md = propertyAndMethodStorageAsMemberData();
if (md) {
QV4::Scope scope(engine);
- QV4::Scoped<QV4::MemberData>(scope, md)->set(engine, id, engine->newVariantObject(
- QVariant::fromValue(v)));
+ QV4::Scoped<QV4::MemberData>(scope, md)->set(
+ engine, id, engine->newVariantObject(
+ QMetaType::fromType<VariantCompatible>(), &v));
}
}
diff --git a/src/qml/qml/qqmlxmlhttprequest.cpp b/src/qml/qml/qqmlxmlhttprequest.cpp
index a1f9377d79..c5d18860db 100644
--- a/src/qml/qml/qqmlxmlhttprequest.cpp
+++ b/src/qml/qml/qqmlxmlhttprequest.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qqmlxmlhttprequest_p.h"
@@ -43,7 +7,6 @@
#include "qqmlengine_p.h"
#include <private/qqmlrefcount_p.h>
#include "qqmlengine_p.h"
-#include "qqmlexpression_p.h"
#include "qqmlglobal_p.h"
#include <private/qv4domerrors_p.h>
#include <private/qv4engine_p.h>
@@ -56,6 +19,8 @@
#include <QtQml/qjsengine.h>
#include <QtQml/qqmlfile.h>
#include <QtNetwork/qnetworkreply.h>
+
+#include <QtCore/qpointer.h>
#include <QtCore/qstringconverter.h>
#include <QtCore/qxmlstream.h>
#include <QtCore/qstack.h>
@@ -153,11 +118,12 @@ public:
QList<NodeImpl *> attributes;
};
-class DocumentImpl : public QQmlRefCount, public NodeImpl
+class DocumentImpl final : public QQmlRefCounted<DocumentImpl>, public NodeImpl
{
+ using Base1 = QQmlRefCounted<DocumentImpl>;
public:
DocumentImpl() : root(nullptr) { type = Document; }
- virtual ~DocumentImpl() {
+ ~DocumentImpl() override {
delete root;
}
@@ -167,8 +133,8 @@ public:
NodeImpl *root;
- void addref() { QQmlRefCount::addref(); }
- void release() { QQmlRefCount::release(); }
+ void addref() { Base1::addref(); }
+ void release() { Base1::release(); }
};
namespace Heap {
@@ -540,7 +506,7 @@ ReturnedValue NodePrototype::method_get_previousSibling(const FunctionObject *b,
if (!r->d()->d->parent)
RETURN_RESULT(Encode::null());
- for (int ii = 0; ii < r->d()->d->parent->children.count(); ++ii) {
+ for (int ii = 0; ii < r->d()->d->parent->children.size(); ++ii) {
if (r->d()->d->parent->children.at(ii) == r->d()->d) {
if (ii == 0)
return Encode::null();
@@ -562,9 +528,9 @@ ReturnedValue NodePrototype::method_get_nextSibling(const FunctionObject *b, con
if (!r->d()->d->parent)
RETURN_RESULT(Encode::null());
- for (int ii = 0; ii < r->d()->d->parent->children.count(); ++ii) {
+ for (int ii = 0; ii < r->d()->d->parent->children.size(); ++ii) {
if (r->d()->d->parent->children.at(ii) == r->d()->d) {
- if ((ii + 1) == r->d()->d->parent->children.count())
+ if ((ii + 1) == r->d()->d->parent->children.size())
return Encode::null();
else
return Node::create(scope.engine, r->d()->d->parent->children.at(ii + 1));
@@ -702,7 +668,7 @@ ReturnedValue CharacterData::method_length(const FunctionObject *b, const Value
if (!r)
RETURN_UNDEFINED();
- return Encode(int(r->d()->d->data.length()));
+ return Encode(int(r->d()->d->data.size()));
}
ReturnedValue CharacterData::prototype(ExecutionEngine *v4)
@@ -895,7 +861,7 @@ ReturnedValue NamedNodeMap::virtualGet(const Managed *m, PropertyKey id, const V
if (id.isArrayIndex()) {
uint index = id.asArrayIndex();
- if ((int)index < r->d()->list().count()) {
+ if ((int)index < r->d()->list().size()) {
if (hasProperty)
*hasProperty = true;
return Node::create(v4, r->d()->list().at(index));
@@ -909,10 +875,10 @@ ReturnedValue NamedNodeMap::virtualGet(const Managed *m, PropertyKey id, const V
return Object::virtualGet(m, id, receiver, hasProperty);
if (id == v4->id_length()->propertyKey())
- return Value::fromInt32(r->d()->list().count()).asReturnedValue();
+ return Value::fromInt32(r->d()->list().size()).asReturnedValue();
QString str = id.toQString();
- for (int ii = 0; ii < r->d()->list().count(); ++ii) {
+ for (int ii = 0; ii < r->d()->list().size(); ++ii) {
if (r->d()->list().at(ii)->name == str) {
if (hasProperty)
*hasProperty = true;
@@ -938,7 +904,7 @@ ReturnedValue NodeList::virtualGet(const Managed *m, PropertyKey id, const Value
if (id.isArrayIndex()) {
uint index = id.asArrayIndex();
- if ((int)index < r->d()->d->children.count()) {
+ if ((int)index < r->d()->d->children.size()) {
if (hasProperty)
*hasProperty = true;
return Node::create(v4, r->d()->d->children.at(index));
@@ -949,7 +915,7 @@ ReturnedValue NodeList::virtualGet(const Managed *m, PropertyKey id, const Value
}
if (id == v4->id_length()->propertyKey())
- return Value::fromInt32(r->d()->d->children.count()).asReturnedValue();
+ return Value::fromInt32(r->d()->d->children.size()).asReturnedValue();
return Object::virtualGet(m, id, receiver, hasProperty);
}
@@ -1006,9 +972,13 @@ public:
AsynchronousLoad,
SynchronousLoad
};
- enum State { Unsent = 0,
- Opened = 1, HeadersReceived = 2,
- Loading = 3, Done = 4 };
+ enum State {
+ Unsent = 0,
+ Opened = 1,
+ HeadersReceived = 2,
+ Loading = 3,
+ Done = 4
+ };
QQmlXMLHttpRequest(QNetworkAccessManager *manager, QV4::ExecutionEngine *v4);
virtual ~QQmlXMLHttpRequest();
@@ -1031,9 +1001,15 @@ public:
QString responseBody();
const QByteArray & rawResponseBody() const;
bool receivedXml() const;
+ QUrl url() const;
const QString & responseType() const;
void setResponseType(const QString &);
+ void setOverrideMimeType(QStringView mimeType) { m_overrideMime = mimeType.toUtf8(); }
+ void setOverrideCharset(QStringView charset) { m_overrideCharset = charset.toUtf8(); }
+
+ const QByteArray mimeType() const;
+ const QByteArray charset() const;
QV4::ReturnedValue jsonResponseBody(QV4::ExecutionEngine*);
QV4::ReturnedValue xmlResponseBody(QV4::ExecutionEngine*);
@@ -1062,6 +1038,9 @@ private:
bool m_gotXml;
QByteArray m_mime;
QByteArray m_charset;
+ QByteArray m_overrideMime;
+ QByteArray m_overrideCharset;
+
QStringDecoder findTextDecoder() const;
void readEncoding();
@@ -1090,8 +1069,6 @@ private:
QQmlXMLHttpRequest::QQmlXMLHttpRequest(QNetworkAccessManager *manager, QV4::ExecutionEngine *v4)
: m_state(Unsent), m_errorFlag(false), m_sendFlag(false)
, m_redirectCount(0), m_gotXml(false), m_network(nullptr), m_nam(manager)
- , m_responseType()
- , m_parsedDocument()
{
m_wasConstructedWithQmlContext = !v4->callingQmlContext().isNull();
}
@@ -1170,7 +1147,7 @@ QString QQmlXMLHttpRequest::headers() const
QString ret;
for (const HeaderPair &header : m_headersList) {
- if (ret.length())
+ if (ret.size())
ret.append(QLatin1String("\r\n"));
ret += QString::fromUtf8(header.first) + QLatin1String(": ")
+ QString::fromUtf8(header.second);
@@ -1195,6 +1172,7 @@ void QQmlXMLHttpRequest::fillHeadersList()
void QQmlXMLHttpRequest::requestFromUrl(const QUrl &url)
{
+ m_url = url;
QNetworkRequest request = m_request;
if (QQmlFile::isLocalFile(url)) {
@@ -1234,7 +1212,7 @@ void QQmlXMLHttpRequest::requestFromUrl(const QUrl &url)
int n = 0;
int semiColon = str.indexOf(QLatin1Char(';'), charsetIdx);
if (semiColon == -1) {
- n = str.length() - charsetIdx;
+ n = str.size() - charsetIdx;
} else {
n = semiColon - charsetIdx;
}
@@ -1343,7 +1321,7 @@ void QQmlXMLHttpRequest::readyRead()
// ### We assume if this is called the headers are now available
if (m_state < HeadersReceived) {
m_state = HeadersReceived;
- fillHeadersList ();
+ fillHeadersList();
dispatchCallbackSafely();
}
@@ -1462,13 +1440,13 @@ void QQmlXMLHttpRequest::finished()
dispatchCallbackSafely();
m_thisObject.clear();
- m_qmlContext = nullptr;
+ m_qmlContext.reset();
}
void QQmlXMLHttpRequest::readEncoding()
{
- for (const HeaderPair &header : qAsConst(m_headersList)) {
+ for (const HeaderPair &header : std::as_const(m_headersList)) {
if (header.first == "content-type") {
int separatorIdx = header.second.indexOf(';');
if (separatorIdx == -1) {
@@ -1479,14 +1457,15 @@ void QQmlXMLHttpRequest::readEncoding()
if (charsetIdx != -1) {
charsetIdx += 8;
separatorIdx = header.second.indexOf(';', charsetIdx);
- m_charset = header.second.mid(charsetIdx, separatorIdx >= 0 ? separatorIdx : header.second.length());
+ m_charset = header.second.mid(charsetIdx, separatorIdx >= 0 ? separatorIdx : header.second.size());
}
}
break;
}
}
- if (m_mime.isEmpty() || m_mime == "text/xml" || m_mime == "application/xml" || m_mime.endsWith("+xml"))
+ const auto mime = mimeType();
+ if (mime.isEmpty() || mime == "text/xml" || mime == "application/xml" || mime.endsWith("+xml"))
m_gotXml = true;
}
@@ -1495,6 +1474,25 @@ bool QQmlXMLHttpRequest::receivedXml() const
return m_gotXml;
}
+QUrl QQmlXMLHttpRequest::url() const
+{
+ return m_url;
+}
+
+const QByteArray QQmlXMLHttpRequest::mimeType() const
+{
+ // Final MIME type is the override MIME type unless that is null in which
+ // case it is the response MIME type.
+ return m_overrideMime.isEmpty() ? m_mime : m_overrideMime;
+}
+
+const QByteArray QQmlXMLHttpRequest::charset() const
+{
+ // Final charset is the override charset unless that is null in which case
+ // it is the response charset.
+ return m_overrideCharset.isEmpty() ? m_charset : m_overrideCharset;
+}
+
const QString & QQmlXMLHttpRequest::responseType() const
{
return m_responseType;
@@ -1512,7 +1510,7 @@ QV4::ReturnedValue QQmlXMLHttpRequest::jsonResponseBody(QV4::ExecutionEngine* en
QJsonParseError error;
const QString& jtext = responseBody();
- JsonParser parser(scope.engine, jtext.constData(), jtext.length());
+ JsonParser parser(scope.engine, jtext.constData(), jtext.size());
ScopedValue jsonObject(scope, parser.parse(&error));
if (error.error != QJsonParseError::NoError)
return engine->throwSyntaxError(QStringLiteral("JSON.parse: Parse error"));
@@ -1536,8 +1534,8 @@ QStringDecoder QQmlXMLHttpRequest::findTextDecoder() const
{
QStringDecoder decoder;
- if (!m_charset.isEmpty())
- decoder = QStringDecoder(m_charset);
+ if (!charset().isEmpty())
+ decoder = QStringDecoder(charset());
if (!decoder.isValid() && m_gotXml) {
QXmlStreamReader reader(m_responseEntityBody);
@@ -1545,11 +1543,8 @@ QStringDecoder QQmlXMLHttpRequest::findTextDecoder() const
decoder = QStringDecoder(reader.documentEncoding().toString().toUtf8());
}
- if (!decoder.isValid() && m_mime == "text/html") {
- auto encoding = QStringConverter::encodingForHtml(m_responseEntityBody);
- if (encoding)
- decoder = QStringDecoder(*encoding);
- }
+ if (!decoder.isValid() && mimeType() == "text/html")
+ decoder = QStringDecoder::decoderForHtml(m_responseEntityBody);
if (!decoder.isValid()) {
auto encoding = QStringConverter::encodingForData(m_responseEntityBody);
@@ -1591,10 +1586,10 @@ void QQmlXMLHttpRequest::dispatchCallbackNow(Object *thisObj, bool done, bool er
if (!callback)
return;
- QV4::JSCallData jsCallData(scope);
+ QV4::JSCallArguments jsCallData(scope);
callback->call(jsCallData);
- if (scope.engine->hasException) {
+ if (scope.hasException()) {
QQmlError error = scope.engine->catchExceptionAsQmlError();
QQmlEnginePrivate *qmlEnginePrivate = scope.engine->qmlEngine() ? QQmlEnginePrivate::get(scope.engine->qmlEngine()) : nullptr;
QQmlEnginePrivate::warning(qmlEnginePrivate, error);
@@ -1653,7 +1648,7 @@ struct QQmlXMLHttpRequestWrapper : Object {
Member(class, Pointer, Object *, proto)
DECLARE_HEAP_OBJECT(QQmlXMLHttpRequestCtor, FunctionObject) {
- DECLARE_MARKOBJECTS(QQmlXMLHttpRequestCtor);
+ DECLARE_MARKOBJECTS(QQmlXMLHttpRequestCtor)
void init(ExecutionEngine *engine);
};
@@ -1665,6 +1660,7 @@ struct QQmlXMLHttpRequestWrapper : public Object
V4_NEEDS_DESTROY
};
+// https://xhr.spec.whatwg.org/
struct QQmlXMLHttpRequestCtor : public FunctionObject
{
V4_OBJECT2(QQmlXMLHttpRequestCtor, FunctionObject)
@@ -1693,6 +1689,7 @@ struct QQmlXMLHttpRequestCtor : public FunctionObject
static ReturnedValue method_abort(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
static ReturnedValue method_getResponseHeader(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
static ReturnedValue method_getAllResponseHeaders(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
+ static ReturnedValue method_overrideMimeType(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
static ReturnedValue method_get_readyState(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
static ReturnedValue method_get_status(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
@@ -1702,6 +1699,7 @@ struct QQmlXMLHttpRequestCtor : public FunctionObject
static ReturnedValue method_get_response(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
static ReturnedValue method_get_responseType(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
static ReturnedValue method_set_responseType(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
+ static ReturnedValue method_get_responseURL(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
};
}
@@ -1714,11 +1712,12 @@ void Heap::QQmlXMLHttpRequestCtor::init(ExecutionEngine *engine)
Scope scope(engine);
Scoped<QV4::QQmlXMLHttpRequestCtor> ctor(scope, this);
- ctor->defineReadonlyProperty(QStringLiteral("UNSENT"), Value::fromInt32(0));
- ctor->defineReadonlyProperty(QStringLiteral("OPENED"), Value::fromInt32(1));
- ctor->defineReadonlyProperty(QStringLiteral("HEADERS_RECEIVED"), Value::fromInt32(2));
- ctor->defineReadonlyProperty(QStringLiteral("LOADING"), Value::fromInt32(3));
- ctor->defineReadonlyProperty(QStringLiteral("DONE"), Value::fromInt32(4));
+ ctor->defineReadonlyProperty(QStringLiteral("UNSENT"), Value::fromInt32(QQmlXMLHttpRequest::Unsent));
+ ctor->defineReadonlyProperty(QStringLiteral("OPENED"), Value::fromInt32(QQmlXMLHttpRequest::Opened));
+ ctor->defineReadonlyProperty(QStringLiteral("HEADERS_RECEIVED"), Value::fromInt32(QQmlXMLHttpRequest::HeadersReceived));
+ ctor->defineReadonlyProperty(QStringLiteral("LOADING"), Value::fromInt32(QQmlXMLHttpRequest::Loading));
+ ctor->defineReadonlyProperty(QStringLiteral("DONE"), Value::fromInt32(QQmlXMLHttpRequest::Done));
+
if (!ctor->d()->proto)
ctor->setupProto();
ScopedString s(scope, engine->id_prototype());
@@ -1741,6 +1740,7 @@ void QQmlXMLHttpRequestCtor::setupProto()
p->defineDefaultProperty(QStringLiteral("abort"), method_abort);
p->defineDefaultProperty(QStringLiteral("getResponseHeader"), method_getResponseHeader);
p->defineDefaultProperty(QStringLiteral("getAllResponseHeaders"), method_getAllResponseHeaders);
+ p->defineDefaultProperty(QStringLiteral("overrideMimeType"), method_overrideMimeType);
// Read-only properties
p->defineAccessorProperty(QStringLiteral("readyState"), method_get_readyState, nullptr);
@@ -1749,6 +1749,7 @@ void QQmlXMLHttpRequestCtor::setupProto()
p->defineAccessorProperty(QStringLiteral("responseText"),method_get_responseText, nullptr);
p->defineAccessorProperty(QStringLiteral("responseXML"),method_get_responseXML, nullptr);
p->defineAccessorProperty(QStringLiteral("response"),method_get_response, nullptr);
+ p->defineAccessorProperty(QStringLiteral("responseURL"),method_get_responseURL, nullptr);
// Read-write properties
p->defineAccessorProperty(QStringLiteral("responseType"), method_get_responseType, method_set_responseType);
@@ -2074,6 +2075,71 @@ ReturnedValue QQmlXMLHttpRequestCtor::method_set_responseType(const FunctionObje
return Encode::undefined();
}
+ReturnedValue QQmlXMLHttpRequestCtor::method_get_responseURL(const FunctionObject *b, const Value *thisObject, const Value *, int)
+{
+ Scope scope(b);
+ Scoped<QQmlXMLHttpRequestWrapper> w(scope, thisObject->as<QQmlXMLHttpRequestWrapper>());
+ if (!w)
+ V4THROW_REFERENCE("Not an XMLHttpRequest object");
+ QQmlXMLHttpRequest *r = w->d()->request;
+
+ if (r->readyState() != QQmlXMLHttpRequest::Loading &&
+ r->readyState() != QQmlXMLHttpRequest::Done) {
+ return Encode(scope.engine->newString(QString()));
+ } else {
+ QUrl url = r->url();
+ url.setFragment(QString());
+ return Encode(scope.engine->newString(url.toString()));
+ }
+}
+
+ReturnedValue QQmlXMLHttpRequestCtor::method_overrideMimeType(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
+{
+ Scope scope(b);
+ Scoped<QQmlXMLHttpRequestWrapper> w(scope, thisObject->as<QQmlXMLHttpRequestWrapper>());
+ if (!w)
+ V4THROW_REFERENCE("Not an XMLHttpRequest object");
+ QQmlXMLHttpRequest *r = w->d()->request;
+
+ if (argc != 1)
+ THROW_DOM(DOMEXCEPTION_SYNTAX_ERR, "Incorrect argument count");
+
+ // If state is loading or done, throw an InvalidStateError exception.
+ if (r->readyState() == QQmlXMLHttpRequest::Loading ||
+ r->readyState() == QQmlXMLHttpRequest::Done)
+ THROW_DOM(DOMEXCEPTION_INVALID_STATE_ERR, "Invalid state");
+
+ // Set override MIME type to `application/octet-stream`.
+ r->setOverrideMimeType(QStringLiteral("application/octet-stream"));
+ const auto parts = argv[0].toQStringNoThrow().split(QLatin1Char(';'));
+ const auto type = parts.at(0).trimmed();
+
+ const auto mimeInvalidCharacter = [](QChar uni) {
+ if (uni.unicode() > 127) // Only accept ASCII
+ return true;
+ const char ch = char(uni.unicode());
+ return !(ch == '-' || ch == '/' || isAsciiLetterOrNumber(ch));
+ };
+
+ // If mime is a parsable MIME type, ...
+ if (type.count(QLatin1Char('/')) == 1
+ && std::find_if(type.begin(), type.end(), mimeInvalidCharacter) == type.end()) {
+ // ... then set override MIME type to its MIME type portion.
+ r->setOverrideMimeType(type);
+ }
+ for (const auto &part : parts) {
+ const QLatin1String charset("charset=");
+ // If override MIME type has a `charset` parameter, ...
+ if (part.trimmed().startsWith(charset)) {
+ // ... then set override charset to its value.
+ const int offset(part.indexOf(charset) + charset.size());
+ r->setOverrideCharset(part.sliced(offset).trimmed());
+ }
+ }
+
+ return Encode::undefined();
+}
+
void qt_rem_qmlxmlhttprequest(ExecutionEngine * /* engine */, void *d)
{
QQmlXMLHttpRequestData *data = (QQmlXMLHttpRequestData *)d;
diff --git a/src/qml/qml/qqmlxmlhttprequest_p.h b/src/qml/qml/qqmlxmlhttprequest_p.h
index 7515ef8dcc..886cf7038e 100644
--- a/src/qml/qml/qqmlxmlhttprequest_p.h
+++ b/src/qml/qml/qqmlxmlhttprequest_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLXMLHTTPREQUEST_P_H
#define QQMLXMLHTTPREQUEST_P_H
@@ -53,7 +17,7 @@
//
#include <QtCore/qglobal.h>
-#include <private/qqmlglobal_p.h>
+#include <private/qtqmlglobal_p.h>
QT_REQUIRE_CONFIG(qml_xml_http_request);
diff --git a/src/qml/qml/v8/qv4domerrors.cpp b/src/qml/qml/v8/qv4domerrors.cpp
deleted file mode 100644
index 7ad37d098f..0000000000
--- a/src/qml/qml/v8/qv4domerrors.cpp
+++ /dev/null
@@ -1,71 +0,0 @@
-/****************************************************************************
-**
-** 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 "qv4domerrors_p.h"
-#include "qv4object_p.h"
-
-QT_BEGIN_NAMESPACE
-
-using namespace QV4;
-
-void qt_add_domexceptions(ExecutionEngine *e)
-{
- Scope scope(e);
- ScopedObject domexception(scope, e->newObject());
- domexception->defineReadonlyProperty(QStringLiteral("INDEX_SIZE_ERR"), Value::fromInt32(DOMEXCEPTION_INDEX_SIZE_ERR));
- domexception->defineReadonlyProperty(QStringLiteral("DOMSTRING_SIZE_ERR"), Value::fromInt32(DOMEXCEPTION_DOMSTRING_SIZE_ERR));
- domexception->defineReadonlyProperty(QStringLiteral("HIERARCHY_REQUEST_ERR"), Value::fromInt32(DOMEXCEPTION_HIERARCHY_REQUEST_ERR));
- domexception->defineReadonlyProperty(QStringLiteral("WRONG_DOCUMENT_ERR"), Value::fromInt32(DOMEXCEPTION_WRONG_DOCUMENT_ERR));
- domexception->defineReadonlyProperty(QStringLiteral("INVALID_CHARACTER_ERR"), Value::fromInt32(DOMEXCEPTION_INVALID_CHARACTER_ERR));
- domexception->defineReadonlyProperty(QStringLiteral("NO_DATA_ALLOWED_ERR"), Value::fromInt32(DOMEXCEPTION_NO_DATA_ALLOWED_ERR));
- domexception->defineReadonlyProperty(QStringLiteral("NO_MODIFICATION_ALLOWED_ERR"), Value::fromInt32(DOMEXCEPTION_NO_MODIFICATION_ALLOWED_ERR));
- domexception->defineReadonlyProperty(QStringLiteral("NOT_FOUND_ERR"), Value::fromInt32(DOMEXCEPTION_NOT_FOUND_ERR));
- domexception->defineReadonlyProperty(QStringLiteral("NOT_SUPPORTED_ERR"), Value::fromInt32(DOMEXCEPTION_NOT_SUPPORTED_ERR));
- domexception->defineReadonlyProperty(QStringLiteral("INUSE_ATTRIBUTE_ERR"), Value::fromInt32(DOMEXCEPTION_INUSE_ATTRIBUTE_ERR));
- domexception->defineReadonlyProperty(QStringLiteral("INVALID_STATE_ERR"), Value::fromInt32(DOMEXCEPTION_INVALID_STATE_ERR));
- domexception->defineReadonlyProperty(QStringLiteral("SYNTAX_ERR"), Value::fromInt32(DOMEXCEPTION_SYNTAX_ERR));
- domexception->defineReadonlyProperty(QStringLiteral("INVALID_MODIFICATION_ERR"), Value::fromInt32(DOMEXCEPTION_INVALID_MODIFICATION_ERR));
- domexception->defineReadonlyProperty(QStringLiteral("NAMESPACE_ERR"), Value::fromInt32(DOMEXCEPTION_NAMESPACE_ERR));
- domexception->defineReadonlyProperty(QStringLiteral("INVALID_ACCESS_ERR"), Value::fromInt32(DOMEXCEPTION_INVALID_ACCESS_ERR));
- domexception->defineReadonlyProperty(QStringLiteral("VALIDATION_ERR"), Value::fromInt32(DOMEXCEPTION_VALIDATION_ERR));
- domexception->defineReadonlyProperty(QStringLiteral("TYPE_MISMATCH_ERR"), Value::fromInt32(DOMEXCEPTION_TYPE_MISMATCH_ERR));
- e->globalObject->defineDefaultProperty(QStringLiteral("DOMException"), domexception);
-}
-
-QT_END_NAMESPACE
diff --git a/src/qml/qml/v8/qv4domerrors_p.h b/src/qml/qml/v8/qv4domerrors_p.h
deleted file mode 100644
index 1842e46a9c..0000000000
--- a/src/qml/qml/v8/qv4domerrors_p.h
+++ /dev/null
@@ -1,93 +0,0 @@
-/****************************************************************************
-**
-** 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 QV8DOMERRORS_P_H
-#define QV8DOMERRORS_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>
-
-QT_BEGIN_NAMESPACE
-// From DOM-Level-3-Core spec
-// http://www.w3.org/TR/DOM-Level-3-Core/core.html
-#define DOMEXCEPTION_INDEX_SIZE_ERR 1
-#define DOMEXCEPTION_DOMSTRING_SIZE_ERR 2
-#define DOMEXCEPTION_HIERARCHY_REQUEST_ERR 3
-#define DOMEXCEPTION_WRONG_DOCUMENT_ERR 4
-#define DOMEXCEPTION_INVALID_CHARACTER_ERR 5
-#define DOMEXCEPTION_NO_DATA_ALLOWED_ERR 6
-#define DOMEXCEPTION_NO_MODIFICATION_ALLOWED_ERR 7
-#define DOMEXCEPTION_NOT_FOUND_ERR 8
-#define DOMEXCEPTION_NOT_SUPPORTED_ERR 9
-#define DOMEXCEPTION_INUSE_ATTRIBUTE_ERR 10
-#define DOMEXCEPTION_INVALID_STATE_ERR 11
-#define DOMEXCEPTION_SYNTAX_ERR 12
-#define DOMEXCEPTION_INVALID_MODIFICATION_ERR 13
-#define DOMEXCEPTION_NAMESPACE_ERR 14
-#define DOMEXCEPTION_INVALID_ACCESS_ERR 15
-#define DOMEXCEPTION_VALIDATION_ERR 16
-#define DOMEXCEPTION_TYPE_MISMATCH_ERR 17
-
-#define THROW_DOM(error, string) { \
- QV4::ScopedValue v(scope, scope.engine->newString(QStringLiteral(string))); \
- QV4::ScopedObject ex(scope, scope.engine->newErrorObject(v)); \
- ex->put(QV4::ScopedString(scope, scope.engine->newIdentifier(QStringLiteral("code"))), QV4::ScopedValue(scope, QV4::Value::fromInt32(error))); \
- return scope.engine->throwError(ex); \
-}
-
-namespace QV4 {
-struct ExecutionEngine;
-}
-
-
-void qt_add_domexceptions(QV4::ExecutionEngine *e);
-
-QT_END_NAMESPACE
-
-#endif // QV8DOMERRORS_P_H
diff --git a/src/qml/qml/v8/qv4sqlerrors.cpp b/src/qml/qml/v8/qv4sqlerrors.cpp
deleted file mode 100644
index 3f1744a687..0000000000
--- a/src/qml/qml/v8/qv4sqlerrors.cpp
+++ /dev/null
@@ -1,63 +0,0 @@
-/****************************************************************************
-**
-** 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 "qv4sqlerrors_p.h"
-#include "private/qv4engine_p.h"
-#include "private/qv4object_p.h"
-
-QT_BEGIN_NAMESPACE
-
-using namespace QV4;
-
-void qt_add_sqlexceptions(QV4::ExecutionEngine *engine)
-{
- Scope scope(engine);
- ScopedObject sqlexception(scope, engine->newObject());
- sqlexception->defineReadonlyProperty(QStringLiteral("UNKNOWN_ERR"), Value::fromInt32(SQLEXCEPTION_UNKNOWN_ERR));
- sqlexception->defineReadonlyProperty(QStringLiteral("DATABASE_ERR"), Value::fromInt32(SQLEXCEPTION_DATABASE_ERR));
- sqlexception->defineReadonlyProperty(QStringLiteral("VERSION_ERR"), Value::fromInt32(SQLEXCEPTION_VERSION_ERR));
- sqlexception->defineReadonlyProperty(QStringLiteral("TOO_LARGE_ERR"), Value::fromInt32(SQLEXCEPTION_TOO_LARGE_ERR));
- sqlexception->defineReadonlyProperty(QStringLiteral("QUOTA_ERR"), Value::fromInt32(SQLEXCEPTION_QUOTA_ERR));
- sqlexception->defineReadonlyProperty(QStringLiteral("SYNTAX_ERR"), Value::fromInt32(SQLEXCEPTION_SYNTAX_ERR));
- sqlexception->defineReadonlyProperty(QStringLiteral("CONSTRAINT_ERR"), Value::fromInt32(SQLEXCEPTION_CONSTRAINT_ERR));
- sqlexception->defineReadonlyProperty(QStringLiteral("TIMEOUT_ERR"), Value::fromInt32(SQLEXCEPTION_TIMEOUT_ERR));
- engine->globalObject->defineDefaultProperty(QStringLiteral("SQLException"), sqlexception);
-}
-
-QT_END_NAMESPACE
diff --git a/src/qml/qml/v8/qv4sqlerrors_p.h b/src/qml/qml/v8/qv4sqlerrors_p.h
deleted file mode 100644
index 51dcb286de..0000000000
--- a/src/qml/qml/v8/qv4sqlerrors_p.h
+++ /dev/null
@@ -1,74 +0,0 @@
-/****************************************************************************
-**
-** 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 QV8SQLERRORS_P_H
-#define QV8SQLERRORS_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>
-
-QT_BEGIN_NAMESPACE
-#define SQLEXCEPTION_UNKNOWN_ERR 1
-#define SQLEXCEPTION_DATABASE_ERR 2
-#define SQLEXCEPTION_VERSION_ERR 3
-#define SQLEXCEPTION_TOO_LARGE_ERR 4
-#define SQLEXCEPTION_QUOTA_ERR 5
-#define SQLEXCEPTION_SYNTAX_ERR 6
-#define SQLEXCEPTION_CONSTRAINT_ERR 7
-#define SQLEXCEPTION_TIMEOUT_ERR 8
-
-namespace QV4 {
-struct ExecutionEngine;
-}
-
-void qt_add_sqlexceptions(QV4::ExecutionEngine *engine);
-
-QT_END_NAMESPACE
-
-#endif // QV8SQLERRORS_P_H