aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/qml
diff options
context:
space:
mode:
Diffstat (limited to 'src/qml/qml')
-rw-r--r--src/qml/qml/ftw/ftw.pri26
-rw-r--r--src/qml/qml/ftw/qbipointer_p.h203
-rw-r--r--src/qml/qml/ftw/qbitfield_p.h167
-rw-r--r--src/qml/qml/ftw/qdoubleendedlist_p.h256
-rw-r--r--src/qml/qml/ftw/qfieldlist_p.h171
-rw-r--r--src/qml/qml/ftw/qfinitestack_p.h42
-rw-r--r--src/qml/qml/ftw/qflagpointer_p.h350
-rw-r--r--src/qml/qml/ftw/qhashedstring.cpp138
-rw-r--r--src/qml/qml/ftw/qhashedstring_p.h121
-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.h109
-rw-r--r--src/qml/qml/ftw/qlinkedstringhash_p.h42
-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.h146
-rw-r--r--src/qml/qml/ftw/qqmlthread.cpp167
-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.h140
-rw-r--r--src/qml/qml/qml.pri194
-rw-r--r--src/qml/qml/qqml.cpp2441
-rw-r--r--src/qml/qml/qqml.h792
-rw-r--r--src/qml/qml/qqmlabstractbinding.cpp174
-rw-r--r--src/qml/qml/qqmlabstractbinding_p.h120
-rw-r--r--src/qml/qml/qqmlabstracturlinterceptor.cpp40
-rw-r--r--src/qml/qml/qqmlabstracturlinterceptor.h43
-rw-r--r--src/qml/qml/qqmlanybinding_p.h473
-rw-r--r--src/qml/qml/qqmlapplicationengine.cpp276
-rw-r--r--src/qml/qml/qqmlapplicationengine.h49
-rw-r--r--src/qml/qml/qqmlapplicationengine_p.h53
-rw-r--r--src/qml/qml/qqmlbinding.cpp712
-rw-r--r--src/qml/qml/qqmlbinding_p.h129
-rw-r--r--src/qml/qml/qqmlboundsignal.cpp244
-rw-r--r--src/qml/qml/qqmlboundsignal_p.h89
-rw-r--r--src/qml/qml/qqmlboundsignalexpressionpointer_p.h81
-rw-r--r--src/qml/qml/qqmlbuiltinfunctions.cpp (renamed from src/qml/qml/v8/qqmlbuiltinfunctions.cpp)1940
-rw-r--r--src/qml/qml/qqmlbuiltinfunctions_p.h267
-rw-r--r--src/qml/qml/qqmlcleanup.cpp116
-rw-r--r--src/qml/qml/qqmlcleanup_p.h84
-rw-r--r--src/qml/qml/qqmlcomponent.cpp897
-rw-r--r--src/qml/qml/qqmlcomponent.h68
-rw-r--r--src/qml/qml/qqmlcomponent_p.h283
-rw-r--r--src/qml/qml/qqmlcomponentandaliasresolver_p.h484
-rw-r--r--src/qml/qml/qqmlcomponentattached_p.h81
-rw-r--r--src/qml/qml/qqmlcontext.cpp835
-rw-r--r--src/qml/qml/qqmlcontext.h55
-rw-r--r--src/qml/qml/qqmlcontext_p.h382
-rw-r--r--src/qml/qml/qqmlcontextdata.cpp346
-rw-r--r--src/qml/qml/qqmlcontextdata_p.h472
-rw-r--r--src/qml/qml/qqmlcustomparser.cpp153
-rw-r--r--src/qml/qml/qqmlcustomparser_p.h58
-rw-r--r--src/qml/qml/qqmldata_p.h258
-rw-r--r--src/qml/qml/qqmldatablob.cpp128
-rw-r--r--src/qml/qml/qqmldatablob_p.h64
-rw-r--r--src/qml/qml/qqmldelayedcallqueue.cpp102
-rw-r--r--src/qml/qml/qqmldelayedcallqueue_p.h45
-rw-r--r--src/qml/qml/qqmldirdata.cpp70
-rw-r--r--src/qml/qml/qqmldirdata_p.h72
-rw-r--r--src/qml/qml/qqmlengine.cpp1873
-rw-r--r--src/qml/qml/qqmlengine.h100
-rw-r--r--src/qml/qml/qqmlengine_p.h417
-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.cpp78
-rw-r--r--src/qml/qml/qqmlerror.h53
-rw-r--r--src/qml/qml/qqmlexpression.cpp97
-rw-r--r--src/qml/qml/qqmlexpression.h43
-rw-r--r--src/qml/qml/qqmlexpression_p.h46
-rw-r--r--src/qml/qml/qqmlextensioninterface.cpp17
-rw-r--r--src/qml/qml/qqmlextensioninterface.h46
-rw-r--r--src/qml/qml/qqmlextensionplugin.cpp115
-rw-r--r--src/qml/qml/qqmlextensionplugin.h53
-rw-r--r--src/qml/qml/qqmlextensionplugin_p.h42
-rw-r--r--src/qml/qml/qqmlfile.cpp420
-rw-r--r--src/qml/qml/qqmlfile.h46
-rw-r--r--src/qml/qml/qqmlfileselector.cpp115
-rw-r--r--src/qml/qml/qqmlfileselector.h48
-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.cpp931
-rw-r--r--src/qml/qml/qqmlglobal_p.h179
-rw-r--r--src/qml/qml/qqmlguard_p.h162
-rw-r--r--src/qml/qml/qqmlguardedcontextdata_p.h95
-rw-r--r--src/qml/qml/qqmlimport.cpp1967
-rw-r--r--src/qml/qml/qqmlimport_p.h405
-rw-r--r--src/qml/qml/qqmlincubator.cpp225
-rw-r--r--src/qml/qml/qqmlincubator.h44
-rw-r--r--src/qml/qml/qqmlincubator_p.h72
-rw-r--r--src/qml/qml/qqmlinfo.cpp133
-rw-r--r--src/qml/qml/qqmlinfo.h86
-rw-r--r--src/qml/qml/qqmlirloader.cpp151
-rw-r--r--src/qml/qml/qqmlirloader_p.h42
-rw-r--r--src/qml/qml/qqmljavascriptexpression.cpp381
-rw-r--r--src/qml/qml/qqmljavascriptexpression_p.h127
-rw-r--r--src/qml/qml/qqmllist.cpp350
-rw-r--r--src/qml/qml/qqmllist.h228
-rw-r--r--src/qml/qml/qqmllist_p.h230
-rw-r--r--src/qml/qml/qqmllistwrapper.cpp741
-rw-r--r--src/qml/qml/qqmllistwrapper_p.h89
-rw-r--r--src/qml/qml/qqmllocale.cpp640
-rw-r--r--src/qml/qml/qqmllocale_p.h286
-rw-r--r--src/qml/qml/qqmlloggingcategory.cpp160
-rw-r--r--src/qml/qml/qqmlloggingcategory_p.h105
-rw-r--r--src/qml/qml/qqmlloggingcategorybase_p.h47
-rw-r--r--src/qml/qml/qqmlmetaobject.cpp298
-rw-r--r--src/qml/qml/qqmlmetaobject_p.h217
-rw-r--r--src/qml/qml/qqmlmetatype.cpp1674
-rw-r--r--src/qml/qml/qqmlmetatype_p.h352
-rw-r--r--src/qml/qml/qqmlmetatypedata.cpp219
-rw-r--r--src/qml/qml/qqmlmetatypedata_p.h127
-rw-r--r--src/qml/qml/qqmlmoduleregistration.cpp68
-rw-r--r--src/qml/qml/qqmlmoduleregistration.h52
-rw-r--r--src/qml/qml/qqmlnetworkaccessmanagerfactory.cpp55
-rw-r--r--src/qml/qml/qqmlnetworkaccessmanagerfactory.h40
-rw-r--r--src/qml/qml/qqmlnotifier.cpp52
-rw-r--r--src/qml/qml/qqmlnotifier_p.h57
-rw-r--r--src/qml/qml/qqmlobjectcreator.cpp1286
-rw-r--r--src/qml/qml/qqmlobjectcreator_p.h240
-rw-r--r--src/qml/qml/qqmlobjectorgadget.cpp45
-rw-r--r--src/qml/qml/qqmlobjectorgadget_p.h56
-rw-r--r--src/qml/qml/qqmlopenmetaobject.cpp234
-rw-r--r--src/qml/qml/qqmlopenmetaobject_p.h65
-rw-r--r--src/qml/qml/qqmlparserstatus.cpp54
-rw-r--r--src/qml/qml/qqmlparserstatus.h40
-rw-r--r--src/qml/qml/qqmlplatform.cpp51
-rw-r--r--src/qml/qml/qqmlplatform_p.h45
-rw-r--r--src/qml/qml/qqmlpluginimporter.cpp610
-rw-r--r--src/qml/qml/qqmlpluginimporter_p.h81
-rw-r--r--src/qml/qml/qqmlprivate.h889
-rw-r--r--src/qml/qml/qqmlproperty.cpp1149
-rw-r--r--src/qml/qml/qqmlproperty.h62
-rw-r--r--src/qml/qml/qqmlproperty_p.h119
-rw-r--r--src/qml/qml/qqmlpropertybinding.cpp383
-rw-r--r--src/qml/qml/qqmlpropertybinding_p.h421
-rw-r--r--src/qml/qml/qqmlpropertycache.cpp890
-rw-r--r--src/qml/qml/qqmlpropertycache_p.h394
-rw-r--r--src/qml/qml/qqmlpropertycachecreator.cpp163
-rw-r--r--src/qml/qml/qqmlpropertycachecreator_p.h961
-rw-r--r--src/qml/qml/qqmlpropertycachemethodarguments_p.h52
-rw-r--r--src/qml/qml/qqmlpropertycachevector_p.h159
-rw-r--r--src/qml/qml/qqmlpropertydata_p.h429
-rw-r--r--src/qml/qml/qqmlpropertyindex_p.h40
-rw-r--r--src/qml/qml/qqmlpropertyresolver.cpp56
-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.cpp509
-rw-r--r--src/qml/qml/qqmlpropertyvalidator_p.h72
-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.cpp179
-rw-r--r--src/qml/qml/qqmlproxymetaobject_p.h72
-rw-r--r--src/qml/qml/qqmlregistration.h15
-rw-r--r--src/qml/qml/qqmlscriptblob.cpp146
-rw-r--r--src/qml/qml/qqmlscriptblob_p.h46
-rw-r--r--src/qml/qml/qqmlscriptdata.cpp136
-rw-r--r--src/qml/qml/qqmlscriptdata_p.h72
-rw-r--r--src/qml/qml/qqmlscriptstring.cpp64
-rw-r--r--src/qml/qml/qqmlscriptstring.h43
-rw-r--r--src/qml/qml/qqmlscriptstring_p.h41
-rw-r--r--src/qml/qml/qqmlsourcecoordinate_p.h42
-rw-r--r--src/qml/qml/qqmlstaticmetaobject.cpp51
-rw-r--r--src/qml/qml/qqmlstaticmetaobject_p.h68
-rw-r--r--src/qml/qml/qqmlstringconverters.cpp231
-rw-r--r--src/qml/qml/qqmlstringconverters_p.h132
-rw-r--r--src/qml/qml/qqmltype.cpp743
-rw-r--r--src/qml/qml/qqmltype_p.h126
-rw-r--r--src/qml/qml/qqmltype_p_p.h287
-rw-r--r--src/qml/qml/qqmltypecompiler.cpp1015
-rw-r--r--src/qml/qml/qqmltypecompiler_p.h174
-rw-r--r--src/qml/qml/qqmltypedata.cpp723
-rw-r--r--src/qml/qml/qqmltypedata_p.h93
-rw-r--r--src/qml/qml/qqmltypeloader.cpp774
-rw-r--r--src/qml/qml/qqmltypeloader_p.h146
-rw-r--r--src/qml/qml/qqmltypeloadernetworkreplyproxy.cpp42
-rw-r--r--src/qml/qml/qqmltypeloadernetworkreplyproxy_p.h43
-rw-r--r--src/qml/qml/qqmltypeloaderqmldircontent.cpp98
-rw-r--r--src/qml/qml/qqmltypeloaderqmldircontent_p.h69
-rw-r--r--src/qml/qml/qqmltypeloaderthread.cpp104
-rw-r--r--src/qml/qml/qqmltypeloaderthread_p.h79
-rw-r--r--src/qml/qml/qqmltypemodule.cpp155
-rw-r--r--src/qml/qml/qqmltypemodule_p.h128
-rw-r--r--src/qml/qml/qqmltypemodule_p_p.h89
-rw-r--r--src/qml/qml/qqmltypemoduleversion.cpp72
-rw-r--r--src/qml/qml/qqmltypemoduleversion_p.h61
-rw-r--r--src/qml/qml/qqmltypenamecache.cpp167
-rw-r--r--src/qml/qml/qqmltypenamecache_p.h184
-rw-r--r--src/qml/qml/qqmltypenotavailable.cpp53
-rw-r--r--src/qml/qml/qqmltypenotavailable_p.h72
-rw-r--r--src/qml/qml/qqmltypewrapper.cpp558
-rw-r--r--src/qml/qml/qqmltypewrapper_p.h135
-rw-r--r--src/qml/qml/qqmlvaluetype.cpp326
-rw-r--r--src/qml/qml/qqmlvaluetype_p.h306
-rw-r--r--src/qml/qml/qqmlvaluetypeproxybinding.cpp45
-rw-r--r--src/qml/qml/qqmlvaluetypeproxybinding_p.h42
-rw-r--r--src/qml/qml/qqmlvaluetypewrapper.cpp843
-rw-r--r--src/qml/qml/qqmlvaluetypewrapper_p.h152
-rw-r--r--src/qml/qml/qqmlvme.cpp69
-rw-r--r--src/qml/qml/qqmlvme_p.h116
-rw-r--r--src/qml/qml/qqmlvmemetaobject.cpp1036
-rw-r--r--src/qml/qml/qqmlvmemetaobject_p.h205
-rw-r--r--src/qml/qml/qqmlxmlhttprequest.cpp323
-rw-r--r--src/qml/qml/qqmlxmlhttprequest_p.h42
-rw-r--r--src/qml/qml/v8/qqmlbuiltinfunctions_p.h200
-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
-rw-r--r--src/qml/qml/v8/v8.pri9
215 files changed, 28904 insertions, 23730 deletions
diff --git a/src/qml/qml/ftw/ftw.pri b/src/qml/qml/ftw/ftw.pri
deleted file mode 100644
index eadba394b4..0000000000
--- a/src/qml/qml/ftw/ftw.pri
+++ /dev/null
@@ -1,26 +0,0 @@
-HEADERS += \
- $$PWD/qbitfield_p.h \
- $$PWD/qintrusivelist_p.h \
- $$PWD/qpodvector_p.h \
- $$PWD/qhashedstring_p.h \
- $$PWD/qprimefornumbits_p.h \
- $$PWD/qqmlrefcount_p.h \
- $$PWD/qfieldlist_p.h \
- $$PWD/qqmlthread_p.h \
- $$PWD/qfinitestack_p.h \
- $$PWD/qrecursionwatcher_p.h \
- $$PWD/qrecyclepool_p.h \
- $$PWD/qflagpointer_p.h \
- $$PWD/qlazilyallocated_p.h \
- $$PWD/qqmlnullablevalue_p.h \
- $$PWD/qstringhash_p.h \
- $$PWD/qlinkedstringhash_p.h
-
-SOURCES += \
- $$PWD/qintrusivelist.cpp \
- $$PWD/qhashedstring.cpp \
- $$PWD/qqmlthread.cpp
-
-# mirrors logic in $$QT_SOURCE_TREE/config.tests/unix/clock-gettime/clock-gettime.pri
-# clock_gettime() is implemented in librt on these systems
-qtConfig(clock-gettime):linux-*|hpux-*|solaris-*:LIBS_PRIVATE *= -lrt
diff --git a/src/qml/qml/ftw/qbipointer_p.h b/src/qml/qml/ftw/qbipointer_p.h
new file mode 100644
index 0000000000..1597b9e4fc
--- /dev/null
+++ b/src/qml/qml/ftw/qbipointer_p.h
@@ -0,0 +1,203 @@
+// 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
+// -------------
+//
+// 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/private/qglobal_p.h>
+
+#include <QtCore/qhashfunctions.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace QtPrivate {
+template <typename T> struct QFlagPointerAlignment
+{
+ enum : size_t { Value = Q_ALIGNOF(T) };
+};
+template <> struct QFlagPointerAlignment<void>
+{
+ enum : size_t { Value = ~size_t(0) };
+};
+}
+
+/*!
+ \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:
+ 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;
+ inline bool isT2() const;
+
+ inline bool flag() const;
+ inline void setFlag();
+ inline void clearFlag();
+ inline void setFlagValue(bool);
+
+ inline QBiPointer<T, T2> &operator=(T *);
+ inline QBiPointer<T, T2> &operator=(T2 *);
+
+ friend inline bool operator==(QBiPointer<T, T2> ptr1, QBiPointer<T, T2> ptr2)
+ {
+ if (ptr1.isNull() && ptr2.isNull())
+ return true;
+ if (ptr1.isT1() && ptr2.isT1())
+ return ptr1.asT1() == ptr2.asT1();
+ if (ptr1.isT2() && ptr2.isT2())
+ return ptr1.asT2() == ptr2.asT2();
+ return false;
+ }
+ friend inline bool operator!=(QBiPointer<T, T2> ptr1, QBiPointer<T, T2> ptr2)
+ {
+ return !(ptr1 == ptr2);
+ }
+
+ 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;
+
+ static const quintptr FlagBit = 0x1;
+ static const quintptr Flag2Bit = 0x2;
+ static const quintptr FlagsMask = FlagBit | Flag2Bit;
+};
+
+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)
+: ptr_value(quintptr(v))
+{
+ Q_STATIC_ASSERT_X(QtPrivate::QFlagPointerAlignment<T>::Value >= 4,
+ "Type T does not have sufficient alignment");
+ Q_ASSERT((quintptr(v) & FlagsMask) == 0);
+}
+
+template<typename T, typename T2>
+QBiPointer<T, T2>::QBiPointer(T2 *v)
+: ptr_value(quintptr(v) | Flag2Bit)
+{
+ Q_STATIC_ASSERT_X(QtPrivate::QFlagPointerAlignment<T2>::Value >= 4,
+ "Type T2 does not have sufficient alignment");
+ Q_ASSERT((quintptr(v) & FlagsMask) == 0);
+}
+
+template<typename T, typename T2>
+bool QBiPointer<T, T2>::isNull() const
+{
+ return 0 == (ptr_value & (~FlagsMask));
+}
+
+template<typename T, typename T2>
+bool QBiPointer<T, T2>::isT1() const
+{
+ return !(ptr_value & Flag2Bit);
+}
+
+template<typename T, typename T2>
+bool QBiPointer<T, T2>::isT2() const
+{
+ return ptr_value & Flag2Bit;
+}
+
+template<typename T, typename T2>
+bool QBiPointer<T, T2>::flag() const
+{
+ return ptr_value & FlagBit;
+}
+
+template<typename T, typename T2>
+void QBiPointer<T, T2>::setFlag()
+{
+ ptr_value |= FlagBit;
+}
+
+template<typename T, typename T2>
+void QBiPointer<T, T2>::clearFlag()
+{
+ ptr_value &= ~FlagBit;
+}
+
+template<typename T, typename T2>
+void QBiPointer<T, T2>::setFlagValue(bool v)
+{
+ if (v) setFlag();
+ else clearFlag();
+}
+
+template<typename T, typename T2>
+QBiPointer<T, T2> &QBiPointer<T, T2>::operator=(T *o)
+{
+ Q_ASSERT((quintptr(o) & FlagsMask) == 0);
+
+ ptr_value = quintptr(o) | (ptr_value & FlagBit);
+ return *this;
+}
+
+template<typename T, typename T2>
+QBiPointer<T, T2> &QBiPointer<T, T2>::operator=(T2 *o)
+{
+ Q_ASSERT((quintptr(o) & FlagsMask) == 0);
+
+ ptr_value = quintptr(o) | (ptr_value & FlagBit) | Flag2Bit;
+ return *this;
+}
+
+template<typename T, typename T2>
+T *QBiPointer<T, T2>::asT1() const
+{
+ Q_ASSERT(isT1());
+ return (T *)(ptr_value & ~FlagsMask);
+}
+
+template<typename T, typename T2>
+T2 *QBiPointer<T, T2>::asT2() const
+{
+ Q_ASSERT(isT2());
+ return (T2 *)(ptr_value & ~FlagsMask);
+}
+
+QT_END_NAMESPACE
+
+#endif // QBIPOINTER_P_H
diff --git a/src/qml/qml/ftw/qbitfield_p.h b/src/qml/qml/ftw/qbitfield_p.h
deleted file mode 100644
index 92017580d6..0000000000
--- a/src/qml/qml/ftw/qbitfield_p.h
+++ /dev/null
@@ -1,167 +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 QBITFIELD_P_H
-#define QBITFIELD_P_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists purely as an
-// implementation detail. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include <QtCore/qglobal.h>
-#include <QtCore/qtypeinfo.h>
-
-QT_BEGIN_NAMESPACE
-
-class QBitField
-{
-public:
- inline QBitField();
- inline QBitField(const quint32 *, int bits);
- inline QBitField(const QBitField &);
- inline ~QBitField();
-
- inline QBitField &operator=(const QBitField &);
-
- inline quint32 size() const;
- inline QBitField united(const QBitField &);
- inline bool testBit(int) const;
-
-private:
- quint32 bits:31;
- quint32 *ownData;
- const quint32 *data;
-};
-
-QBitField::QBitField()
-: bits(0), ownData(nullptr), data(nullptr)
-{
-}
-
-QBitField::QBitField(const quint32 *bitData, int bitCount)
-: bits((quint32)bitCount), ownData(nullptr), data(bitData)
-{
-}
-
-QBitField::QBitField(const QBitField &other)
-: bits(other.bits), ownData(other.ownData), data(other.data)
-{
- if (ownData)
- ++(*ownData);
-}
-
-QBitField::~QBitField()
-{
- if (ownData)
- if(0 == --(*ownData)) delete [] ownData;
-}
-
-QBitField &QBitField::operator=(const QBitField &other)
-{
- if (other.data == data)
- return *this;
-
- if (ownData)
- if(0 == --(*ownData)) delete [] ownData;
-
- bits = other.bits;
- ownData = other.ownData;
- data = other.data;
-
- if (ownData)
- ++(*ownData);
-
- return *this;
-}
-
-inline quint32 QBitField::size() const
-{
- return bits;
-}
-
-QBitField QBitField::united(const QBitField &o)
-{
- if (o.bits == 0) {
- return *this;
- } else if (bits == 0) {
- return o;
- } else {
- int max = (bits > o.bits)?bits:o.bits;
- int length = (max + 31) / 32;
- QBitField rv;
- rv.bits = max;
- rv.ownData = new quint32[length + 1];
- *(rv.ownData) = 1;
- quint32 *rvdata;
- rv.data = rvdata = rv.ownData + 1;
- if (bits > o.bits) {
- ::memcpy(rvdata, data, length * sizeof(quint32));
- for (quint32 ii = 0; ii < (o.bits + quint32(31)) / 32; ++ii)
- (rvdata)[ii] |= o.data[ii];
- } else {
- ::memcpy(rvdata, o.data, length * sizeof(quint32));
- for (quint32 ii = 0; ii < (bits + quint32(31)) / 32; ++ii)
- (rvdata)[ii] |= data[ii];
- }
- return rv;
- }
-}
-
-bool QBitField::testBit(int b) const
-{
- Q_ASSERT(b >= 0);
- if ((quint32)b < bits) {
- return data[b / 32] & (1 << (b % 32));
- } else {
- return false;
- }
-}
-
-Q_DECLARE_TYPEINFO(QBitField, Q_MOVABLE_TYPE);
-
-QT_END_NAMESPACE
-
-#endif // QBITFIELD_P_H
diff --git a/src/qml/qml/ftw/qdoubleendedlist_p.h b/src/qml/qml/ftw/qdoubleendedlist_p.h
new file mode 100644
index 0000000000..0a4d9f75d3
--- /dev/null
+++ b/src/qml/qml/ftw/qdoubleendedlist_p.h
@@ -0,0 +1,256 @@
+// 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
+
+//
+// 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/private/qglobal_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QInheritedListNode
+{
+public:
+ ~QInheritedListNode() { remove(); }
+ bool isInList() const
+ {
+ Q_ASSERT((m_prev && m_next) || (!m_prev && !m_next));
+ return m_prev != nullptr;
+ }
+
+private:
+ template<class N>
+ friend class QDoubleEndedList;
+
+ void remove()
+ {
+ Q_ASSERT((m_prev && m_next) || (!m_prev && !m_next));
+ if (!m_prev)
+ return;
+
+ m_prev->m_next = m_next;
+ m_next->m_prev = m_prev;
+ m_prev = nullptr;
+ m_next = nullptr;
+ }
+
+ QInheritedListNode *m_next = nullptr;
+ QInheritedListNode *m_prev = nullptr;
+};
+
+template<class N>
+class QDoubleEndedList
+{
+public:
+ QDoubleEndedList()
+ {
+ m_head.m_next = &m_head;
+ m_head.m_prev = &m_head;
+ assertHeadConsistent();
+ }
+
+ ~QDoubleEndedList()
+ {
+ assertHeadConsistent();
+ while (!isEmpty())
+ m_head.m_next->remove();
+ assertHeadConsistent();
+ }
+
+ bool isEmpty() const
+ {
+ assertHeadConsistent();
+ return m_head.m_next == &m_head;
+ }
+
+ void prepend(N *n)
+ {
+ assertHeadConsistent();
+ QInheritedListNode *nnode = n;
+ nnode->remove();
+
+ nnode->m_next = m_head.m_next ? m_head.m_next : &m_head;
+ nnode->m_next->m_prev = nnode;
+
+ m_head.m_next = nnode;
+ nnode->m_prev = &m_head;
+ assertHeadConsistent();
+ }
+
+ void append(N *n)
+ {
+ assertHeadConsistent();
+ QInheritedListNode *nnode = n;
+ nnode->remove();
+
+ nnode->m_prev = m_head.m_prev ? m_head.m_prev : &m_head;
+ nnode->m_prev->m_next = nnode;
+
+ m_head.m_prev = nnode;
+ nnode->m_next = &m_head;
+ assertHeadConsistent();
+ }
+
+ void remove(N *n) {
+ Q_ASSERT(contains(n));
+ QInheritedListNode *nnode = n;
+ nnode->remove();
+ assertHeadConsistent();
+ }
+
+ bool contains(const N *n) const
+ {
+ assertHeadConsistent();
+ for (const QInheritedListNode *nnode = m_head.m_next;
+ nnode != &m_head; nnode = nnode->m_next) {
+ if (nnode == n)
+ return true;
+ }
+
+ return false;
+ }
+
+ template<typename T, typename Node>
+ class base_iterator {
+ public:
+ T *operator*() const { return QDoubleEndedList<N>::nodeToN(m_node); }
+ T *operator->() const { return QDoubleEndedList<N>::nodeToN(m_node); }
+
+ bool operator==(const base_iterator &other) const { return other.m_node == m_node; }
+ bool operator!=(const base_iterator &other) const { return other.m_node != m_node; }
+
+ base_iterator &operator++()
+ {
+ m_node = m_node->m_next;
+ return *this;
+ }
+
+ base_iterator operator++(int)
+ {
+ const base_iterator self(m_node);
+ m_node = m_node->m_next;
+ return self;
+ }
+
+ private:
+ friend class QDoubleEndedList<N>;
+
+ base_iterator(Node *node) : m_node(node)
+ {
+ Q_ASSERT(m_node != nullptr);
+ }
+
+ Node *m_node = nullptr;
+ };
+
+ using iterator = base_iterator<N, QInheritedListNode>;
+ using const_iterator = base_iterator<const N, const QInheritedListNode>;
+
+ const N *first() const { return checkedNodeToN(m_head.m_next); }
+ N *first() { return checkedNodeToN(m_head.m_next); }
+
+ const N *last() const { return checkedNodeToN(m_head.m_prev); }
+ N *last() { return checkedNodeToN(m_head.m_prev); }
+
+ const N *next(const N *current) const
+ {
+ Q_ASSERT(contains(current));
+ const QInheritedListNode *nnode = current;
+ return checkedNodeToN(nnode->m_next);
+ }
+
+ N *next(N *current)
+ {
+ Q_ASSERT(contains(current));
+ const QInheritedListNode *nnode = current;
+ return checkedNodeToN(nnode->m_next);
+ }
+
+ const N *prev(const N *current) const
+ {
+ Q_ASSERT(contains(current));
+ const QInheritedListNode *nnode = current;
+ return checkedNodeToN(nnode->m_prev);
+ }
+
+ N *prev(N *current)
+ {
+ Q_ASSERT(contains(current));
+ const QInheritedListNode *nnode = current;
+ return checkedNodeToN(nnode->m_prev);
+ }
+
+ iterator begin()
+ {
+ assertHeadConsistent();
+ return iterator(m_head.m_next);
+ }
+
+ iterator end()
+ {
+ assertHeadConsistent();
+ return iterator(&m_head);
+ }
+
+ const_iterator begin() const
+ {
+ assertHeadConsistent();
+ return const_iterator(m_head.m_next);
+ }
+
+ const_iterator end() const
+ {
+ assertHeadConsistent();
+ return const_iterator(&m_head);
+ }
+
+ qsizetype count() const
+ {
+ assertHeadConsistent();
+ qsizetype result = 0;
+ for (const auto *node = m_head.m_next; node != &m_head; node = node->m_next)
+ ++result;
+ return result;
+ }
+
+private:
+ static N *nodeToN(QInheritedListNode *node)
+ {
+ return static_cast<N *>(node);
+ }
+
+ static const N *nodeToN(const QInheritedListNode *node)
+ {
+ return static_cast<const N *>(node);
+ }
+
+ N *checkedNodeToN(QInheritedListNode *node) const
+ {
+ assertHeadConsistent();
+ return (!node || node == &m_head) ? nullptr : nodeToN(node);
+ }
+
+ void assertHeadConsistent() const
+ {
+ Q_ASSERT(m_head.m_next != nullptr);
+ Q_ASSERT(m_head.m_prev != nullptr);
+ Q_ASSERT(m_head.m_next != &m_head || m_head.m_prev == &m_head);
+ }
+
+ QInheritedListNode m_head;
+};
+
+QT_END_NAMESPACE
+
+#endif // QDOUBLEENDEDLIST_P_H
diff --git a/src/qml/qml/ftw/qfieldlist_p.h b/src/qml/qml/ftw/qfieldlist_p.h
index 2bf07fb20d..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,12 +15,12 @@
// 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>
+template<class N, N *N::*nextMember, typename Tag = QtPrivate::TagInfo<N>>
class QForwardFieldList
{
public:
@@ -65,6 +29,8 @@ public:
inline N *takeFirst();
inline void prepend(N *);
+ template <typename OtherTag>
+ inline void copyAndClearPrepend(QForwardFieldList<N, nextMember, OtherTag> &);
inline bool isEmpty() const;
inline bool isOne() const;
@@ -72,17 +38,10 @@ public:
static inline N *next(N *v);
- inline bool flag() const;
- inline void setFlag();
- inline void clearFlag();
- inline void setFlagValue(bool);
-
- inline bool flag2() const;
- inline void setFlag2();
- inline void clearFlag2();
- inline void setFlag2Value(bool);
+ inline Tag tag() const;
+ inline void setTag(Tag t);
private:
- QFlagPointer<N> _first;
+ QTaggedPointer<N, Tag> _first;
};
// QFieldList is a simple linked list, that can append and prepend and also
@@ -108,8 +67,10 @@ public:
inline void insertAfter(N *, QFieldList<N, nextMember> &);
inline void copyAndClear(QFieldList<N, nextMember> &);
- inline void copyAndClearAppend(QForwardFieldList<N, nextMember> &);
- inline void copyAndClearPrepend(QForwardFieldList<N, nextMember> &);
+ template <typename Tag>
+ inline void copyAndClearAppend(QForwardFieldList<N, nextMember, Tag> &);
+ template <typename Tag>
+ inline void copyAndClearPrepend(QForwardFieldList<N, nextMember, Tag> &);
static inline N *next(N *v);
@@ -124,21 +85,21 @@ private:
quint32 _count:31;
};
-template<class N, N *N::*nextMember>
-QForwardFieldList<N, nextMember>::QForwardFieldList()
+template<class N, N *N::*nextMember, typename Tag>
+QForwardFieldList<N, nextMember, Tag>::QForwardFieldList()
{
}
-template<class N, N *N::*nextMember>
-N *QForwardFieldList<N, nextMember>::first() const
+template<class N, N *N::*nextMember, typename Tag>
+N *QForwardFieldList<N, nextMember, Tag>::first() const
{
- return *_first;
+ return _first.data();
}
-template<class N, N *N::*nextMember>
-N *QForwardFieldList<N, nextMember>::takeFirst()
+template<class N, N *N::*nextMember, typename Tag>
+N *QForwardFieldList<N, nextMember, Tag>::takeFirst()
{
- N *value = *_first;
+ N *value = _first.data();
if (value) {
_first = next(value);
value->*nextMember = nullptr;
@@ -146,85 +107,57 @@ N *QForwardFieldList<N, nextMember>::takeFirst()
return value;
}
-template<class N, N *N::*nextMember>
-void QForwardFieldList<N, nextMember>::prepend(N *v)
+template<class N, N *N::*nextMember, typename Tag>
+void QForwardFieldList<N, nextMember, Tag>::prepend(N *v)
{
Q_ASSERT(v->*nextMember == nullptr);
- v->*nextMember = *_first;
+ v->*nextMember = _first.data();
_first = v;
}
-template<class N, N *N::*nextMember>
-bool QForwardFieldList<N, nextMember>::isEmpty() const
+template<class N, N *N::*nextMember, typename Tag>
+template <typename OtherTag>
+void QForwardFieldList<N, nextMember, Tag>::copyAndClearPrepend(QForwardFieldList<N, nextMember, OtherTag> &o)
{
- return _first.isNull();
-}
-
-template<class N, N *N::*nextMember>
-bool QForwardFieldList<N, nextMember>::isOne() const
-{
- return *_first && _first->*nextMember == 0;
-}
-
-template<class N, N *N::*nextMember>
-bool QForwardFieldList<N, nextMember>::isMany() const
-{
- return *_first && _first->*nextMember != 0;
-}
-
-template<class N, N *N::*nextMember>
-N *QForwardFieldList<N, nextMember>::next(N *v)
-{
- Q_ASSERT(v);
- return v->*nextMember;
-}
-
-template<class N, N *N::*nextMember>
-bool QForwardFieldList<N, nextMember>::flag() const
-{
- return _first.flag();
-}
-
-template<class N, N *N::*nextMember>
-void QForwardFieldList<N, nextMember>::setFlag()
-{
- _first.setFlag();
+ _first = nullptr;
+ while (N *n = o.takeFirst()) prepend(n);
}
-template<class N, N *N::*nextMember>
-void QForwardFieldList<N, nextMember>::clearFlag()
+template<class N, N *N::*nextMember, typename Tag>
+bool QForwardFieldList<N, nextMember, Tag>::isEmpty() const
{
- _first.clearFlag();
+ return _first.isNull();
}
-template<class N, N *N::*nextMember>
-void QForwardFieldList<N, nextMember>::setFlagValue(bool v)
+template<class N, N *N::*nextMember, typename Tag>
+bool QForwardFieldList<N, nextMember, Tag>::isOne() const
{
- _first.setFlagValue(v);
+ return _first.data() && _first->*nextMember == 0;
}
-template<class N, N *N::*nextMember>
-bool QForwardFieldList<N, nextMember>::flag2() const
+template<class N, N *N::*nextMember, typename Tag>
+bool QForwardFieldList<N, nextMember, Tag>::isMany() const
{
- return _first.flag2();
+ return _first.data() && _first->*nextMember != 0;
}
-template<class N, N *N::*nextMember>
-void QForwardFieldList<N, nextMember>::setFlag2()
+template<class N, N *N::*nextMember, typename Tag>
+N *QForwardFieldList<N, nextMember, Tag>::next(N *v)
{
- _first.setFlag2();
+ Q_ASSERT(v);
+ return v->*nextMember;
}
-template<class N, N *N::*nextMember>
-void QForwardFieldList<N, nextMember>::clearFlag2()
+template<class N, N *N::*nextMember, typename Tag>
+Tag QForwardFieldList<N, nextMember, Tag>::tag() const
{
- _first.clearFlag2();
+ return _first.tag();
}
-template<class N, N *N::*nextMember>
-void QForwardFieldList<N, nextMember>::setFlag2Value(bool v)
+template<class N, N *N::*nextMember, typename Tag>
+void QForwardFieldList<N, nextMember, Tag>::setTag(Tag t)
{
- _first.setFlag2Value(v);
+ _first.setTag(t);
}
template<class N, N *N::*nextMember>
@@ -380,7 +313,8 @@ void QFieldList<N, nextMember>::copyAndClear(QFieldList<N, nextMember> &o)
}
template<class N, N *N::*nextMember>
-void QFieldList<N, nextMember>::copyAndClearAppend(QForwardFieldList<N, nextMember> &o)
+template <typename Tag>
+void QFieldList<N, nextMember>::copyAndClearAppend(QForwardFieldList<N, nextMember, Tag> &o)
{
_first = 0;
_last = 0;
@@ -389,7 +323,8 @@ void QFieldList<N, nextMember>::copyAndClearAppend(QForwardFieldList<N, nextMemb
}
template<class N, N *N::*nextMember>
-void QFieldList<N, nextMember>::copyAndClearPrepend(QForwardFieldList<N, nextMember> &o)
+template <typename Tag>
+void QFieldList<N, nextMember>::copyAndClearPrepend(QForwardFieldList<N, nextMember, Tag> &o)
{
_first = nullptr;
_last = nullptr;
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/qflagpointer_p.h b/src/qml/qml/ftw/qflagpointer_p.h
deleted file mode 100644
index 71b41cd30b..0000000000
--- a/src/qml/qml/ftw/qflagpointer_p.h
+++ /dev/null
@@ -1,350 +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 QFLAGPOINTER_P_H
-#define QFLAGPOINTER_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
-
-template<typename T>
-class QFlagPointer {
-public:
- inline QFlagPointer();
- inline QFlagPointer(T *);
- inline QFlagPointer(const QFlagPointer<T> &o);
-
- inline bool isNull() const;
-
- inline bool flag() const;
- inline void setFlag();
- inline void clearFlag();
- inline void setFlagValue(bool);
-
- inline bool flag2() const;
- inline void setFlag2();
- inline void clearFlag2();
- inline void setFlag2Value(bool);
-
- inline QFlagPointer<T> &operator=(const QFlagPointer &o);
- inline QFlagPointer<T> &operator=(T *);
-
- inline T *operator->() const;
- inline T *operator*() const;
-
- inline T *data() const;
-
- inline explicit operator bool() const;
-
-private:
- quintptr ptr_value = 0;
-
- static const quintptr FlagBit = 0x1;
- static const quintptr Flag2Bit = 0x2;
- static const quintptr FlagsMask = FlagBit | Flag2Bit;
-};
-
-template<typename T, typename T2>
-class QBiPointer {
-public:
- inline QBiPointer();
- inline QBiPointer(T *);
- inline QBiPointer(T2 *);
- inline QBiPointer(const QBiPointer<T, T2> &o);
-
- inline bool isNull() const;
- inline bool isT1() const;
- inline bool isT2() const;
-
- inline bool flag() const;
- inline void setFlag();
- 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 *);
-
- inline T *asT1() const;
- inline T2 *asT2() const;
-
-private:
- quintptr ptr_value = 0;
-
- static const quintptr FlagBit = 0x1;
- static const quintptr Flag2Bit = 0x2;
- static const quintptr FlagsMask = FlagBit | Flag2Bit;
-};
-
-template<typename T>
-QFlagPointer<T>::QFlagPointer()
-{
-}
-
-template<typename T>
-QFlagPointer<T>::QFlagPointer(T *v)
-: ptr_value(quintptr(v))
-{
- Q_ASSERT((ptr_value & FlagsMask) == 0);
-}
-
-template<typename T>
-QFlagPointer<T>::QFlagPointer(const QFlagPointer<T> &o)
-: ptr_value(o.ptr_value)
-{
-}
-
-template<typename T>
-bool QFlagPointer<T>::isNull() const
-{
- return 0 == (ptr_value & (~FlagsMask));
-}
-
-template<typename T>
-bool QFlagPointer<T>::flag() const
-{
- return ptr_value & FlagBit;
-}
-
-template<typename T>
-void QFlagPointer<T>::setFlag()
-{
- ptr_value |= FlagBit;
-}
-
-template<typename T>
-void QFlagPointer<T>::clearFlag()
-{
- ptr_value &= ~FlagBit;
-}
-
-template<typename T>
-void QFlagPointer<T>::setFlagValue(bool v)
-{
- if (v) setFlag();
- else clearFlag();
-}
-
-template<typename T>
-bool QFlagPointer<T>::flag2() const
-{
- return ptr_value & Flag2Bit;
-}
-
-template<typename T>
-void QFlagPointer<T>::setFlag2()
-{
- ptr_value|= Flag2Bit;
-}
-
-template<typename T>
-void QFlagPointer<T>::clearFlag2()
-{
- ptr_value &= ~Flag2Bit;
-}
-
-template<typename T>
-void QFlagPointer<T>::setFlag2Value(bool v)
-{
- if (v) setFlag2();
- else clearFlag2();
-}
-
-template<typename T>
-QFlagPointer<T> &QFlagPointer<T>::operator=(const QFlagPointer &o)
-{
- ptr_value = o.ptr_value;
- return *this;
-}
-
-template<typename T>
-QFlagPointer<T> &QFlagPointer<T>::operator=(T *o)
-{
- Q_ASSERT((quintptr(o) & FlagsMask) == 0);
-
- ptr_value = quintptr(o) | (ptr_value & FlagsMask);
- return *this;
-}
-
-template<typename T>
-T *QFlagPointer<T>::operator->() const
-{
- return (T *)(ptr_value & ~FlagsMask);
-}
-
-template<typename T>
-T *QFlagPointer<T>::operator*() const
-{
- return (T *)(ptr_value & ~FlagsMask);
-}
-
-template<typename T>
-T *QFlagPointer<T>::data() const
-{
- return (T *)(ptr_value & ~FlagsMask);
-}
-
-template<typename T>
-QFlagPointer<T>::operator bool() const
-{
- return data() != nullptr;
-}
-
-template<typename T, typename T2>
-QBiPointer<T, T2>::QBiPointer()
-{
-}
-
-template<typename T, typename T2>
-QBiPointer<T, T2>::QBiPointer(T *v)
-: ptr_value(quintptr(v))
-{
- Q_ASSERT((quintptr(v) & FlagsMask) == 0);
-}
-
-template<typename T, typename T2>
-QBiPointer<T, T2>::QBiPointer(T2 *v)
-: ptr_value(quintptr(v) | Flag2Bit)
-{
- Q_ASSERT((quintptr(v) & FlagsMask) == 0);
-}
-
-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));
-}
-
-template<typename T, typename T2>
-bool QBiPointer<T, T2>::isT1() const
-{
- return !(ptr_value & Flag2Bit);
-}
-
-template<typename T, typename T2>
-bool QBiPointer<T, T2>::isT2() const
-{
- return ptr_value & Flag2Bit;
-}
-
-template<typename T, typename T2>
-bool QBiPointer<T, T2>::flag() const
-{
- return ptr_value & FlagBit;
-}
-
-template<typename T, typename T2>
-void QBiPointer<T, T2>::setFlag()
-{
- ptr_value |= FlagBit;
-}
-
-template<typename T, typename T2>
-void QBiPointer<T, T2>::clearFlag()
-{
- ptr_value &= ~FlagBit;
-}
-
-template<typename T, typename T2>
-void QBiPointer<T, T2>::setFlagValue(bool v)
-{
- if (v) setFlag();
- else clearFlag();
-}
-
-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);
-
- ptr_value = quintptr(o) | (ptr_value & FlagBit);
- return *this;
-}
-
-template<typename T, typename T2>
-QBiPointer<T, T2> &QBiPointer<T, T2>::operator=(T2 *o)
-{
- Q_ASSERT((quintptr(o) & FlagsMask) == 0);
-
- ptr_value = quintptr(o) | (ptr_value & FlagBit) | Flag2Bit;
- return *this;
-}
-
-template<typename T, typename T2>
-T *QBiPointer<T, T2>::asT1() const
-{
- Q_ASSERT(isT1());
- return (T *)(ptr_value & ~FlagsMask);
-}
-
-template<typename T, typename T2>
-T2 *QBiPointer<T, T2>::asT2() const
-{
- Q_ASSERT(isT2());
- return (T2 *)(ptr_value & ~FlagsMask);
-}
-
-QT_END_NAMESPACE
-
-#endif // QFLAGPOINTER_P_H
diff --git a/src/qml/qml/ftw/qhashedstring.cpp b/src/qml/qml/ftw/qhashedstring.cpp
index 7a8fdd0a14..b963bc7984 100644
--- a/src/qml/qml/ftw/qhashedstring.cpp
+++ b/src/qml/qml/ftw/qhashedstring.cpp
@@ -1,100 +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 "qhashedstring_p.h"
QT_BEGIN_NAMESPACE
-// Copy of QString's qMemCompare
-bool QHashedString::compare(const QChar *lhs, const QChar *rhs, int length)
-{
- Q_ASSERT(lhs && rhs);
- const quint16 *a = (const quint16 *)lhs;
- const quint16 *b = (const quint16 *)rhs;
-
- if (a == b || !length)
- return true;
-
- union {
- const quint16 *w;
- const quint32 *d;
- quintptr value;
- } sa, sb;
- sa.w = a;
- sb.w = b;
-
- // check alignment
- if ((sa.value & 2) == (sb.value & 2)) {
- // both addresses have the same alignment
- if (sa.value & 2) {
- // both addresses are not aligned to 4-bytes boundaries
- // compare the first character
- if (*sa.w != *sb.w)
- return false;
- --length;
- ++sa.w;
- ++sb.w;
-
- // now both addresses are 4-bytes aligned
- }
-
- // both addresses are 4-bytes aligned
- // do a fast 32-bit comparison
- const quint32 *e = sa.d + (length >> 1);
- for ( ; sa.d != e; ++sa.d, ++sb.d) {
- if (*sa.d != *sb.d)
- return false;
- }
-
- // do we have a tail?
- return (length & 1) ? *sa.w == *sb.w : true;
- } else {
- // one of the addresses isn't 4-byte aligned but the other is
- const quint16 *e = sa.w + length;
- for ( ; sa.w != e; ++sa.w, ++sb.w) {
- if (*sa.w != *sb.w)
- return false;
- }
- }
- return true;
-}
-
QHashedStringRef QHashedStringRef::mid(int offset, int length) const
{
Q_ASSERT(offset < m_length);
@@ -102,37 +12,41 @@ QHashedStringRef QHashedStringRef::mid(int offset, int length) const
(length == -1 || (offset + length) > m_length)?(m_length - offset):length);
}
-bool QHashedStringRef::endsWith(const QString &s) const
+QVector<QHashedStringRef> QHashedStringRef::split(const QChar sep) const
{
- return s.length() < m_length &&
- QHashedString::compare(s.constData(), m_data + m_length - s.length(), s.length());
+ QVector<QHashedStringRef> ret;
+ auto curLength = 0;
+ auto curOffset = m_data;
+ for (int offset = 0; offset < m_length; ++offset) {
+ if (*(m_data + offset) == sep) {
+ ret.push_back({curOffset, curLength});
+ curOffset = m_data + offset + 1;
+ curLength = 0;
+ } else {
+ ++curLength;
+ }
+ }
+ if (curLength > 0)
+ ret.push_back({curOffset, curLength});
+ return ret;
}
-bool QHashedStringRef::startsWith(const QString &s) const
+bool QHashedStringRef::endsWith(const QString &s) const
{
- return s.length() < m_length &&
- QHashedString::compare(s.constData(), m_data, s.length());
+ QStringView view {m_data, m_length};
+ return view.endsWith(s);
}
-static int findChar(const QChar *str, int len, QChar ch, int from)
+bool QHashedStringRef::startsWith(const QString &s) const
{
- const ushort *s = (const ushort *)str;
- ushort c = ch.unicode();
- if (from < 0)
- from = qMax(from + len, 0);
- if (from < len) {
- const ushort *n = s + from - 1;
- const ushort *e = s + len;
- while (++n != e)
- if (*n == c)
- return n - s;
- }
- return -1;
+ QStringView view {m_data, m_length};
+ return view.startsWith(s);
}
int QHashedStringRef::indexOf(const QChar &c, int from) const
{
- return findChar(m_data, m_length, c, from);
+ QStringView view {m_data, m_length};
+ return view.indexOf(c, from);
}
QString QHashedStringRef::toString() const
diff --git a/src/qml/qml/ftw/qhashedstring_p.h b/src/qml/qml/ftw/qhashedstring_p.h
index b9f3f81219..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();
@@ -79,7 +41,6 @@ public:
inline quint32 hash() const;
inline quint32 existingHash() const;
- static bool compare(const QChar *lhs, const QChar *rhs, int length);
static inline bool compare(const QChar *lhs, const char *rhs, int length);
static inline bool compare(const char *lhs, const char *rhs, int length);
@@ -95,12 +56,12 @@ private:
};
class QHashedCStringRef;
-class Q_QML_PRIVATE_EXPORT QHashedStringRef
+class Q_QML_EXPORT QHashedStringRef
{
public:
inline QHashedStringRef();
inline QHashedStringRef(const QString &);
- inline QHashedStringRef(const QStringRef &);
+ inline QHashedStringRef(QStringView);
inline QHashedStringRef(const QChar *, int);
inline QHashedStringRef(const QChar *, int, quint32);
inline QHashedStringRef(const QHashedString &);
@@ -125,6 +86,7 @@ public:
bool endsWith(const QString &) const;
int indexOf(const QChar &, int from=0) const;
QHashedStringRef mid(int, int) const;
+ QVector<QHashedStringRef> split(const QChar sep) const;
inline bool isEmpty() const;
inline int length() const;
@@ -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;
@@ -171,12 +133,12 @@ private:
mutable quint32 m_hash = 0;
};
-inline uint qHash(const QHashedString &string)
+inline size_t qHash(const QHashedString &string)
{
return uint(string.hash());
}
-inline uint qHash(const QHashedStringRef &string)
+inline size_t qHash(const QHashedStringRef &string)
{
return uint(string.hash());
}
@@ -216,9 +178,10 @@ bool QHashedString::operator==(const QHashedString &string) const
bool QHashedString::operator==(const QHashedStringRef &string) const
{
- return length() == string.m_length &&
- (string.m_hash == m_hash || !string.m_hash || !m_hash) &&
- QHashedString::compare(constData(), string.m_data, string.m_length);
+ if (m_hash && string.m_hash && m_hash != string.m_hash)
+ return false;
+ QStringView otherView {string.m_data, string.m_length};
+ return static_cast<const QString &>(*this) == otherView;
}
quint32 QHashedString::hash() const
@@ -236,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(const QStringRef &str)
-: m_data(str.constData()), m_length(str.length()), m_hash(0)
+QHashedStringRef::QHashedStringRef(QStringView str)
+: 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)
@@ -257,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)
@@ -276,22 +244,26 @@ QHashedStringRef &QHashedStringRef::operator=(const QHashedStringRef &o)
bool QHashedStringRef::operator==(const QString &string) const
{
- return m_length == string.length() &&
- QHashedString::compare(string.constData(), m_data, m_length);
+ QStringView view {m_data, m_length};
+ return view == string;
}
bool QHashedStringRef::operator==(const QHashedString &string) const
{
- return m_length == string.length() &&
- (m_hash == string.m_hash || !m_hash || !string.m_hash) &&
- QHashedString::compare(string.constData(), m_data, m_length);
+ if (m_hash && string.m_hash && m_hash != string.m_hash)
+ return false;
+ QStringView view {m_data, m_length};
+ QStringView otherView {string.constData(), string.size()};
+ return view == otherView;
}
bool QHashedStringRef::operator==(const QHashedStringRef &string) const
{
- return m_length == string.m_length &&
- (m_hash == string.m_hash || !m_hash || !string.m_hash) &&
- QHashedString::compare(string.m_data, m_data, m_length);
+ if (m_hash && string.m_hash && m_hash != string.m_hash)
+ return false;
+ QStringView view {m_data, m_length};
+ QStringView otherView {string.m_data, string.m_length};
+ return view == otherView;
}
bool QHashedStringRef::operator==(const QHashedCStringRef &string) const
@@ -303,29 +275,22 @@ bool QHashedStringRef::operator==(const QHashedCStringRef &string) const
bool QHashedStringRef::operator!=(const QString &string) const
{
- return m_length != string.length() ||
- !QHashedString::compare(string.constData(), m_data, m_length);
+ return !(*this == string);
}
bool QHashedStringRef::operator!=(const QHashedString &string) const
{
- return m_length != string.length() ||
- (m_hash != string.m_hash && m_hash && string.m_hash) ||
- !QHashedString::compare(string.constData(), m_data, m_length);
+ return !(*this == string);
}
bool QHashedStringRef::operator!=(const QHashedStringRef &string) const
{
- return m_length != string.m_length ||
- (m_hash != string.m_hash && m_hash && string.m_hash) ||
- QHashedString::compare(string.m_data, m_data, m_length);
+ return !(*this == string);
}
bool QHashedStringRef::operator!=(const QHashedCStringRef &string) const
{
- return m_length != string.m_length ||
- (m_hash != string.m_hash && m_hash && string.m_hash) ||
- QHashedString::compare(m_data, string.m_data, m_length);
+ return !(*this == string);
}
QChar *QHashedStringRef::data()
@@ -451,6 +416,7 @@ bool QHashedString::compare(const char *lhs, const char *rhs, int length)
return 0 == ::memcmp(lhs, rhs, length);
}
+
quint32 QHashedString::stringHash(const QChar *data, int length)
{
return QV4::String::createHashValue(data, length, nullptr);
@@ -463,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 9073e41558..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,13 +15,12 @@
// We mean it.
//
-#include <QtCore/qglobal.h>
-
-#include <private/qflagpointer_p.h>
+#include <QtCore/private/qglobal_p.h>
+#include <QtCore/qtaggedpointer.h>
QT_BEGIN_NAMESPACE
-template<typename T>
+template<typename T, typename Tag = typename QtPrivate::TagInfo<T>::TagType>
class QLazilyAllocated {
public:
inline QLazilyAllocated();
@@ -70,73 +33,59 @@ public:
inline T &value();
inline const T &value() const;
- inline bool flag() const;
- inline void setFlag();
- inline void clearFlag();
- inline void setFlagValue(bool);
+ inline Tag tag() const;
+ inline void setTag(Tag t);
private:
- mutable QFlagPointer<T> d;
+ mutable QTaggedPointer<T, Tag> d;
};
-template<typename T>
-QLazilyAllocated<T>::QLazilyAllocated()
+template<typename T, typename Tag>
+QLazilyAllocated<T, Tag>::QLazilyAllocated()
{
}
-template<typename T>
-QLazilyAllocated<T>::~QLazilyAllocated()
+template<typename T, typename Tag>
+QLazilyAllocated<T, Tag>::~QLazilyAllocated()
{
- delete *d;
+ delete d.data();
}
-template<typename T>
-bool QLazilyAllocated<T>::isAllocated() const
+template<typename T, typename Tag>
+bool QLazilyAllocated<T, Tag>::isAllocated() const
{
return !d.isNull();
}
-template<typename T>
-T &QLazilyAllocated<T>::value()
+template<typename T, typename Tag>
+T &QLazilyAllocated<T, Tag>::value()
{
if (d.isNull()) d = new T;
- return *(*d);
+ return *d;
}
-template<typename T>
-const T &QLazilyAllocated<T>::value() const
+template<typename T, typename Tag>
+const T &QLazilyAllocated<T, Tag>::value() const
{
if (d.isNull()) d = new T;
- return *(*d);
-}
-
-template<typename T>
-T *QLazilyAllocated<T>::operator->() const
-{
return *d;
}
-template<typename T>
-bool QLazilyAllocated<T>::flag() const
-{
- return d.flag();
-}
-
-template<typename T>
-void QLazilyAllocated<T>::setFlag()
+template<typename T, typename Tag>
+T *QLazilyAllocated<T, Tag>::operator->() const
{
- d.setFlag();
+ return d.data();
}
-template<typename T>
-void QLazilyAllocated<T>::clearFlag()
+template<typename T, typename Tag>
+Tag QLazilyAllocated<T, Tag>::tag() const
{
- d.clearFlag();
+ return d.tag();
}
-template<typename T>
-void QLazilyAllocated<T>::setFlagValue(bool v)
+template<typename T, typename Tag>
+void QLazilyAllocated<T, Tag>::setTag(Tag t)
{
- d.setFlagValue(v);
+ d.setTag(t);
}
QT_END_NAMESPACE
diff --git a/src/qml/qml/ftw/qlinkedstringhash_p.h b/src/qml/qml/ftw/qlinkedstringhash_p.h
index 67ced7fbbf..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
@@ -223,7 +187,7 @@ public:
{
if (auto *node = iter.node()) {
QHashedString key(node->key());
- while ((node = static_cast<typename QLinkedStringHash<T>::Node *>(*node->next))) {
+ while ((node = static_cast<typename QLinkedStringHash<T>::Node *>(node->next.data()))) {
if (node->equals(key))
return QLinkedStringHash<T>::iterator(node);
}
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..62899e4644 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.m_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 b4f8acad49..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,10 +79,54 @@ public:
inline T* take() { T *res = o; o = nullptr; return res; }
+ 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)
{
@@ -122,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
@@ -135,7 +167,7 @@ int QQmlRefCount::count() const
}
template<class T>
-QQmlRefPointer<T>::QQmlRefPointer()
+QQmlRefPointer<T>::QQmlRefPointer() noexcept
: o(nullptr)
{
}
@@ -156,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())
{
}
@@ -170,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 e961ed3d0d..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;
@@ -131,6 +94,9 @@ QQmlThreadPrivate::QQmlThreadPrivate(QQmlThread *q)
m_mainThreadWaiting(false), mainSync(nullptr), m_mainObject(this)
{
setObjectName(QStringLiteral("QQmlThread"));
+ // This size is aligned with the recursion depth limits in the parser/codegen. In case of
+ // absurd content we want to hit the recursion checks instead of running out of stack.
+ setStackSize(8 * 1024 * 1024);
}
bool QQmlThreadPrivate::event(QEvent *e)
@@ -140,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();
@@ -185,13 +138,7 @@ void QQmlThreadPrivate::threadEvent()
lock();
for (;;) {
- if (m_shutdown) {
- quit();
- wakeOne();
- unlock();
-
- return;
- } else if (!threadList.isEmpty()) {
+ if (!threadList.isEmpty()) {
m_threadProcessing = true;
QQmlThread::Message *message = threadList.first();
@@ -203,6 +150,12 @@ void QQmlThreadPrivate::threadEvent()
lock();
delete threadList.takeFirst();
+ } else if (m_shutdown) {
+ quit();
+ wakeOne();
+ unlock();
+
+ return;
} else {
wakeOne();
@@ -225,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);
}
@@ -239,28 +193,19 @@ void QQmlThread::shutdown()
d->lock();
Q_ASSERT(!d->m_shutdown);
- for (;;) {
- if (d->mainSync || !d->mainList.isEmpty()) {
- d->unlock();
- d->mainEvent();
- d->lock();
- } else if (!d->threadList.isEmpty()) {
- d->wait();
- } else {
- break;
- }
- }
-
d->m_shutdown = true;
- if (QCoreApplication::closingDown()) {
+
+ if (QCoreApplication::closingDown())
d->quit();
- } else {
+ else
d->triggerThreadEvent();
- d->wait();
- }
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
@@ -288,11 +233,6 @@ void QQmlThread::wakeOne()
d->wakeOne();
}
-void QQmlThread::wakeAll()
-{
- d->wakeAll();
-}
-
void QQmlThread::wait()
{
d->wait();
@@ -300,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
@@ -308,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)
@@ -355,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)
@@ -418,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;
@@ -443,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 f9435b4919..c431a4d6b3 100644
--- a/src/qml/qml/ftw/qstringhash_p.h
+++ b/src/qml/qml/ftw/qstringhash_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) 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
@@ -54,25 +18,34 @@
#include <private/qhashedstring_p.h>
#include <private/qprimefornumbits_p.h>
-#include <QtCore/qglobal.h>
+#include <QtCore/qbytearray.h>
+#include <QtCore/qstring.h>
+#include <QtCore/qtaggedpointer.h>
QT_BEGIN_NAMESPACE
+static inline QString::DataPointer &mutableStringData(const QHashedString &key)
+{
+ return const_cast<QHashedString &>(key).data_ptr();
+}
+
class QStringHashData;
class QStringHashNode
{
public:
QStringHashNode()
- : ckey(nullptr)
{
}
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())
{
- strData = const_cast<QHashedString &>(key).data_ptr();
+ Q_ASSERT(key.size() <= std::numeric_limits<int>::max());
+ if (arrayData)
+ arrayData->ref();
setQString(true);
- strData->ref.ref();
}
QStringHashNode(const QHashedCStringRef &key)
@@ -81,49 +54,63 @@ public:
}
QStringHashNode(const QStringHashNode &o)
- : length(o.length), hash(o.hash), symbolId(o.symbolId), ckey(o.ckey)
+ : length(o.length), hash(o.hash), symbolId(o.symbolId), arrayData(o.arrayData)
{
setQString(o.isQString());
- if (isQString()) { strData->ref.ref(); }
+ if (isQString()) {
+ strData = o.strData;
+ if (arrayData)
+ arrayData->ref();
+ } else {
+ ckey = o.ckey;
+ }
}
~QStringHashNode()
{
- if (isQString()) { if (!strData->ref.deref()) free(strData); }
+ if (isQString() && arrayData && !arrayData->deref())
+ QTypedArrayData<char16_t>::deallocate(arrayData);
}
- QFlagPointer<QStringHashNode> next;
+ enum Tag {
+ NodeIsCString,
+ NodeIsQString
+ };
+
+ QTaggedPointer<QStringHashNode, Tag> next;
qint32 length = 0;
quint32 hash = 0;
quint32 symbolId = 0;
+ QTypedArrayData<char16_t> *arrayData = nullptr;
union {
- const char *ckey;
- QStringData *strData;
+ const char *ckey = nullptr;
+ char16_t *strData;
};
inline QHashedString key() const
{
- if (isQString())
- return QHashedString(QString((QChar *)strData->data(), length), hash);
+ if (isQString()) {
+ if (arrayData)
+ arrayData->ref();
+ return QHashedString(QString(QStringPrivate(arrayData, strData, length)), hash);
+ }
return QHashedString(QString::fromLatin1(ckey, length), hash);
}
- bool isQString() const { return next.flag(); }
- void setQString(bool v) { if (v) next.setFlag(); else next.clearFlag(); }
+ bool isQString() const { return next.tag() == NodeIsQString; }
+ void setQString(bool v) { if (v) next.setTag(NodeIsQString); else next.setTag(NodeIsCString); }
- inline char *cStrData() const { return (char *)ckey; }
- inline quint16 *utf16Data() const { return (quint16 *)strData->data(); }
+ inline qsizetype size() const { return length; }
+ inline const char *cStrData() const { return ckey; }
+ inline const char16_t *utf16Data() const { return strData; }
inline bool equals(const QV4::Value &string) const {
QString s = string.toQStringNoThrow();
if (isQString()) {
- QStringDataPtr dd;
- dd.ptr = strData;
- strData->ref.ref();
- return QString(dd) == s;
+ return QStringView(utf16Data(), length) == s;
} else {
return QLatin1String(cStrData(), length) == s;
}
@@ -133,10 +120,7 @@ public:
if (length != string->d()->length() || hash != string->hashValue())
return false;
if (isQString()) {
- QStringDataPtr dd;
- dd.ptr = strData;
- strData->ref.ref();
- return QString(dd) == string->toQString();
+ return QStringView(utf16Data(), length) == string->toQString();
} else {
return QLatin1String(cStrData(), length) == string->toQString();
}
@@ -145,7 +129,7 @@ public:
inline bool equals(const QHashedStringRef &string) const {
return length == string.length() &&
hash == string.hash() &&
- (isQString()?QHashedString::compare(string.constData(), (const QChar *)utf16Data(), length):
+ (isQString()? string == QStringView {utf16Data(), length}:
QHashedString::compare(string.constData(), cStrData(), length));
}
@@ -237,7 +221,7 @@ template<typename T>
struct HashedForm {};
template<> struct HashedForm<QString> { typedef QHashedString Type; };
-template<> struct HashedForm<QStringRef> { typedef QHashedStringRef Type; };
+template<> struct HashedForm<QStringView> { typedef QHashedStringRef Type; };
template<> struct HashedForm<QHashedString> { typedef const QHashedString &Type; };
template<> struct HashedForm<QV4::String *> { typedef const QV4::String *Type; };
template<> struct HashedForm<const QV4::String *> { typedef const QV4::String *Type; };
@@ -249,13 +233,21 @@ class QStringHashBase
{
public:
static HashedForm<QString>::Type hashedString(const QString &s) { return QHashedString(s);}
- static HashedForm<QStringRef>::Type hashedString(const QStringRef &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; }
@@ -508,10 +500,12 @@ 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->strData = const_cast<QHashedString &>(key).data_ptr();
- node->strData->ref.ref();
+ node->arrayData = mutableStringData(key).d_ptr();
+ node->strData = mutableStringData(key).data();
+ if (node->arrayData)
+ node->arrayData->ref();
node->setQString(true);
}
@@ -547,10 +541,12 @@ typename QStringHash<T>::Node *QStringHash<T>::takeNode(const Node &o)
Node *rv = nodePool->nodes + nodePool->used++;
rv->length = o.length;
rv->hash = o.hash;
+ rv->arrayData = o.arrayData;
if (o.isQString()) {
rv->strData = o.strData;
- rv->strData->ref.ref();
rv->setQString(true);
+ if (rv->arrayData)
+ rv->arrayData->ref();
} else {
rv->ckey = o.ckey;
}
@@ -700,7 +696,7 @@ typename QStringHash<T>::Node *QStringHash<T>::findNode(const K &key) const
typename HashedForm<K>::Type hashedKey(hashedString(key));
while (node && !node->equals(hashedKey))
- node = (*node->next);
+ node = node->next.data();
return (Node *)node;
}
diff --git a/src/qml/qml/qml.pri b/src/qml/qml/qml.pri
deleted file mode 100644
index a16f3d4167..0000000000
--- a/src/qml/qml/qml.pri
+++ /dev/null
@@ -1,194 +0,0 @@
-SOURCES += \
- $$PWD/qqml.cpp \
- $$PWD/qqmldatablob.cpp \
- $$PWD/qqmldirdata.cpp \
- $$PWD/qqmlerror.cpp \
- $$PWD/qqmlmoduleregistration.cpp \
- $$PWD/qqmlopenmetaobject.cpp \
- $$PWD/qqmlscriptblob.cpp \
- $$PWD/qqmlscriptdata.cpp \
- $$PWD/qqmltypedata.cpp \
- $$PWD/qqmltypeloaderqmldircontent.cpp \
- $$PWD/qqmltypeloaderthread.cpp \
- $$PWD/qqmlvmemetaobject.cpp \
- $$PWD/qqmlengine.cpp \
- $$PWD/qqmlexpression.cpp \
- $$PWD/qqmlproperty.cpp \
- $$PWD/qqmlcomponent.cpp \
- $$PWD/qqmlincubator.cpp \
- $$PWD/qqmlcontext.cpp \
- $$PWD/qqmlcustomparser.cpp \
- $$PWD/qqmlpropertyvaluesource.cpp \
- $$PWD/qqmlpropertyvalueinterceptor.cpp \
- $$PWD/qqmlproxymetaobject.cpp \
- $$PWD/qqmlvme.cpp \
- $$PWD/qqmlboundsignal.cpp \
- $$PWD/qqmlmetatype.cpp \
- $$PWD/qqmlmetatypedata.cpp \
- $$PWD/qqmlstringconverters.cpp \
- $$PWD/qqmltype.cpp \
- $$PWD/qqmltypemodule.cpp \
- $$PWD/qqmltypemoduleversion.cpp \
- $$PWD/qqmlparserstatus.cpp \
- $$PWD/qqmltypeloader.cpp \
- $$PWD/qqmlinfo.cpp \
- $$PWD/qqmlvaluetype.cpp \
- $$PWD/qqmlcleanup.cpp \
- $$PWD/qqmlpropertycache.cpp \
- $$PWD/qqmlmetaobject.cpp \
- $$PWD/qqmlnotifier.cpp \
- $$PWD/qqmlobjectorgadget.cpp \
- $$PWD/qqmlstaticmetaobject.cpp \
- $$PWD/qqmltypenotavailable.cpp \
- $$PWD/qqmltypenamecache.cpp \
- $$PWD/qqmlscriptstring.cpp \
- $$PWD/qqmlnetworkaccessmanagerfactory.cpp \
- $$PWD/qqmlextensionplugin.cpp \
- $$PWD/qqmlimport.cpp \
- $$PWD/qqmllist.cpp \
- $$PWD/qqmljavascriptexpression.cpp \
- $$PWD/qqmlabstractbinding.cpp \
- $$PWD/qqmlvaluetypeproxybinding.cpp \
- $$PWD/qqmlglobal.cpp \
- $$PWD/qqmlfile.cpp \
- $$PWD/qqmlplatform.cpp \
- $$PWD/qqmlbinding.cpp \
- $$PWD/qqmlabstracturlinterceptor.cpp \
- $$PWD/qqmlapplicationengine.cpp \
- $$PWD/qqmllistwrapper.cpp \
- $$PWD/qqmlvaluetypewrapper.cpp \
- $$PWD/qqmltypewrapper.cpp \
- $$PWD/qqmlfileselector.cpp \
- $$PWD/qqmlobjectcreator.cpp \
- $$PWD/qqmldelayedcallqueue.cpp \
- $$PWD/qqmlloggingcategory.cpp \
- $$PWD/qqmlirloader.cpp \
- $$PWD/qqmlpropertyresolver.cpp \
- $$PWD/qqmltypecompiler.cpp \
- $$PWD/qqmlpropertycachecreator.cpp \
- $$PWD/qqmlpropertyvalidator.cpp
-
-HEADERS += \
- $$PWD/qqmldatablob_p.h \
- $$PWD/qqmldirdata_p.h \
- $$PWD/qqmlglobal_p.h \
- $$PWD/qqmlmoduleregistration.h \
- $$PWD/qqmlopenmetaobject_p.h \
- $$PWD/qqmlscriptblob_p.h \
- $$PWD/qqmlscriptdata_p.h \
- $$PWD/qqmltypedata_p.h \
- $$PWD/qqmltypeloaderqmldircontent_p.h \
- $$PWD/qqmltypeloaderthread_p.h \
- $$PWD/qqmlvmemetaobject_p.h \
- $$PWD/qqml.h \
- $$PWD/qqmlerror.h \
- $$PWD/qqmlproperty.h \
- $$PWD/qqmlcomponent.h \
- $$PWD/qqmlcomponent_p.h \
- $$PWD/qqmlincubator.h \
- $$PWD/qqmlincubator_p.h \
- $$PWD/qqmlcustomparser_p.h \
- $$PWD/qqmlpropertyvaluesource.h \
- $$PWD/qqmlpropertyvalueinterceptor_p.h \
- $$PWD/qqmlboundsignal_p.h \
- $$PWD/qqmlboundsignalexpressionpointer_p.h \
- $$PWD/qqmlparserstatus.h \
- $$PWD/qqmlproxymetaobject_p.h \
- $$PWD/qqmlvme_p.h \
- $$PWD/qqmlengine_p.h \
- $$PWD/qqmlexpression_p.h \
- $$PWD/qqmlprivate.h \
- $$PWD/qqmlmetatype_p.h \
- $$PWD/qqmlmetatypedata_p.h \
- $$PWD/qqmltype_p.h \
- $$PWD/qqmltype_p_p.h \
- $$PWD/qqmltypemodule_p.h \
- $$PWD/qqmltypemodule_p_p.h \
- $$PWD/qqmltypemoduleversion_p.h \
- $$PWD/qqmlengine.h \
- $$PWD/qqmlcontext.h \
- $$PWD/qqmlexpression.h \
- $$PWD/qqmlstringconverters_p.h \
- $$PWD/qqmlinfo.h \
- $$PWD/qqmlproperty_p.h \
- $$PWD/qqmlcontext_p.h \
- $$PWD/qqmltypeloader_p.h \
- $$PWD/qqmllist.h \
- $$PWD/qqmllist_p.h \
- $$PWD/qqmldata_p.h \
- $$PWD/qqmlvaluetype_p.h \
- $$PWD/qqmlcleanup_p.h \
- $$PWD/qqmlenumdata_p.h \
- $$PWD/qqmlenumvalue_p.h \
- $$PWD/qqmlpropertycache_p.h \
- $$PWD/qqmlpropertycachemethodarguments_p.h \
- $$PWD/qqmlpropertycachevector_p.h \
- $$PWD/qqmlpropertydata_p.h \
- $$PWD/qqmlpropertyindex_p.h \
- $$PWD/qqmlmetaobject_p.h \
- $$PWD/qqmlnotifier_p.h \
- $$PWD/qqmlobjectorgadget_p.h \
- $$PWD/qqmlstaticmetaobject_p.h \
- $$PWD/qqmltypenotavailable_p.h \
- $$PWD/qqmltypenamecache_p.h \
- $$PWD/qqmlscriptstring.h \
- $$PWD/qqmlguard_p.h \
- $$PWD/qqmlnetworkaccessmanagerfactory.h \
- $$PWD/qqmlextensioninterface.h \
- $$PWD/qqmlimport_p.h \
- $$PWD/qqmlextensionplugin.h \
- $$PWD/qqmlscriptstring_p.h \
- $$PWD/qqmlcomponentattached_p.h \
- $$PWD/qqmljavascriptexpression_p.h \
- $$PWD/qqmlabstractbinding_p.h \
- $$PWD/qqmlvaluetypeproxybinding_p.h \
- $$PWD/qqmlfile.h \
- $$PWD/qqmlplatform_p.h \
- $$PWD/qqmlbinding_p.h \
- $$PWD/qqmlextensionplugin_p.h \
- $$PWD/qqmlabstracturlinterceptor.h \
- $$PWD/qqmlapplicationengine_p.h \
- $$PWD/qqmlapplicationengine.h \
- $$PWD/qqmllistwrapper_p.h \
- $$PWD/qqmltypewrapper_p.h \
- $$PWD/qqmlfileselector_p.h \
- $$PWD/qqmlfileselector.h \
- $$PWD/qqmlobjectcreator_p.h \
- $$PWD/qqmldelayedcallqueue_p.h \
- $$PWD/qqmlloggingcategory_p.h \
- $$PWD/qqmlirloader_p.h \
- $$PWD/qqmlpropertyresolver_p.h \
- $$PWD/qqmltypecompiler_p.h \
- $$PWD/qqmlpropertycachecreator_p.h \
- $$PWD/qqmlpropertyvalidator_p.h \
- $$PWD/qqmlsourcecoordinate_p.h
-
-qtConfig(qml-xml-http-request) {
- HEADERS += \
- $$PWD/qqmlxmlhttprequest_p.h
-
- SOURCES += \
- $$PWD/qqmlxmlhttprequest.cpp
-
-}
-
-qtConfig(qml-locale) {
- HEADERS += \
- $$PWD/qqmllocale_p.h
-
- SOURCES += \
- $$PWD/qqmllocale.cpp
-}
-
-qtConfig(qml-network) {
- HEADERS += \
- $$PWD/qqmltypeloadernetworkreplyproxy_p.h
-
- SOURCES += \
- $$PWD/qqmltypeloadernetworkreplyproxy.cpp
-}
-
-android: DEFINES += LIBS_SUFFIX='\\"_$${QT_ARCH}.so\\"'
-
-include(ftw/ftw.pri)
-include(v8/v8.pri)
diff --git a/src/qml/qml/qqml.cpp b/src/qml/qml/qqml.cpp
index a33936647f..63e67ac804 100644
--- a/src/qml/qml/qqml.cpp
+++ b/src/qml/qml/qqml.cpp
@@ -1,56 +1,232 @@
-/****************************************************************************
-**
-** 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/qqmlloggingcategorybase_p.h>
#include <private/qqmlmetatype_p.h>
#include <private/qqmlmetatypedata_p.h>
#include <private/qqmltype_p_p.h>
-#include <private/qqmltypemodule_p_p.h>
+#include <private/qqmltypemodule_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->context
+ || !data->context->engine()
+ || data->deferredData.isEmpty()
+ || data->wasDeleted(object)) {
+ return;
+ }
+
+ if (!data->propertyCache)
+ data->propertyCache = QQmlMetaType::propertyCache(object->metaObject());
+
+ QQmlEnginePrivate *ep = QQmlEnginePrivate::get(data->context->engine());
+
+ 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)
+{
+ return QQmlEngine::contextForObject(obj);
+}
+
+QQmlEngine *qmlEngine(const QObject *obj)
+{
+ QQmlData *data = QQmlData::get(obj);
+ if (!data || !data->context)
+ return nullptr;
+ return data->context->engine();
+}
+
+static QObject *resolveAttachedProperties(QQmlAttachedPropertiesFunc pf, QQmlData *data,
+ QObject *object, bool create)
+{
+ if (!pf)
+ return nullptr;
+
+ QObject *rv = data->hasExtendedData() ? data->attachedProperties()->value(pf) : 0;
+ if (rv || !create)
+ return rv;
+
+ rv = pf(object);
+
+ if (rv)
+ data->attachedProperties()->insert(pf, rv);
+
+ return rv;
+}
+
+QQmlAttachedPropertiesFunc qmlAttachedPropertiesFunction(QObject *object,
+ const QMetaObject *attachedMetaObject)
+{
+ QQmlEngine *engine = object ? qmlEngine(object) : nullptr;
+ return QQmlMetaType::attachedPropertiesFunc(engine ? QQmlEnginePrivate::get(engine) : nullptr,
+ attachedMetaObject);
+}
+
+QObject *qmlAttachedPropertiesObject(QObject *object, QQmlAttachedPropertiesFunc func, bool create)
+{
+ if (!object)
+ return nullptr;
+
+ QQmlData *data = QQmlData::get(object, create);
+
+ // Attached properties are only on objects created by QML,
+ // unless explicitly requested (create==true)
+ if (!data)
+ return nullptr;
+
+ 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 = {
+ QQmlPrivate::RegisterType::CurrentVersion,
+ QMetaType(),
+ QMetaType(),
+ 0,
+ nullptr,
+ nullptr,
+ reason,
+ nullptr,
+
+ uri, QTypeRevision::fromVersion(versionMajor, versionMinor), qmlName, &staticMetaObject,
+
+ QQmlAttachedPropertiesFunc(),
+ nullptr,
+
+ -1,
+ -1,
+ -1,
+
+ nullptr, nullptr,
+
+ nullptr,
+ QTypeRevision::zero(),
+ -1,
+ QQmlPrivate::ValueTypeCreationMethod::None
+ };
+
+ return QQmlPrivate::qmlregister(QQmlPrivate::TypeRegistration, &type);
+}
+
void qmlClearTypeRegistrations() // Declared in qqml.h
{
QQmlMetaType::clearTypeRegistrations();
@@ -61,60 +237,200 @@ void qmlClearTypeRegistrations() // Declared in qqml.h
//From qqml.h
bool qmlProtectModule(const char *uri, int majVersion)
{
- return QQmlMetaType::protectModule(QString::fromUtf8(uri), majVersion);
+ return QQmlMetaType::protectModule(QString::fromUtf8(uri),
+ QTypeRevision::fromMajorVersion(majVersion));
}
//From qqml.h
void qmlRegisterModule(const char *uri, int versionMajor, int versionMinor)
{
- QQmlMetaType::registerModule(uri, versionMajor, versionMinor);
+ QQmlMetaType::registerModule(uri, QTypeRevision::fromVersion(versionMajor, versionMinor));
+}
+
+static QQmlDirParser::Import resolveImport(const QString &uri, int importMajor, int importMinor)
+{
+ if (importMajor == QQmlModuleImportAuto)
+ return QQmlDirParser::Import(uri, QTypeRevision(), QQmlDirParser::Import::Auto);
+ else if (importMajor == QQmlModuleImportLatest)
+ return QQmlDirParser::Import(uri, QTypeRevision(), QQmlDirParser::Import::Default);
+ else if (importMinor == QQmlModuleImportLatest)
+ return QQmlDirParser::Import(uri, QTypeRevision::fromMajorVersion(importMajor), QQmlDirParser::Import::Default);
+ return QQmlDirParser::Import(uri, QTypeRevision::fromVersion(importMajor, importMinor), QQmlDirParser::Import::Default);
+}
+
+static QTypeRevision resolveModuleVersion(int moduleMajor)
+{
+ return moduleMajor == QQmlModuleImportModuleAny
+ ? QTypeRevision()
+ : QTypeRevision::fromMajorVersion(moduleMajor);
+}
+
+/*!
+ * \enum QQmlModuleImportSpecialVersions
+ * \relates QQmlEngine
+ *
+ * Defines some special values that can be passed to the version arguments of
+ * qmlRegisterModuleImport() and qmlUnregisterModuleImport().
+ *
+ * \value QQmlModuleImportModuleAny When passed as majorVersion of the base
+ * module, signifies that the import is to be
+ * applied to any version of the module.
+ * \value QQmlModuleImportLatest When passed as major or minor version of
+ * the imported module, signifies that the
+ * latest overall, or latest minor version
+ * of a specified major version shall be
+ * imported.
+ * \value QQmlModuleImportAuto When passed as major version of the imported
+ * module, signifies that the version of the
+ * base module shall be forwarded.
+ */
+
+/*!
+ * \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 QQmlModuleImportLatest the latest version
+ * available of that module is imported, and \a importMinor does not matter. If
+ * \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 \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", QQmlModuleImportModuleAny,
+ * "MyOtherModule", QQmlModuleImportLatest);
+ * \endcode
+ *
+ * Or, you may specify that whenever major version 5 of "MyModule" is imported,
+ * then version 3.14 of "MyOtherModule" should be imported:
+ *
+ * \code
+ * qmlRegisterModuleImport("MyModule", 5, "MyOtherModule", 3, 14);
+ * \endcode
+ *
+ * Finally, if you always want the same version of "MyOtherModule" to be
+ * imported whenever "MyModule" is imported, specify the following:
+ *
+ * \code
+ * qmlRegisterModuleImport("MyModule", QQmlModuleImportModuleAny,
+ * "MyOtherModule", QQmlModuleImportAuto);
+ * \endcode
+ *
+ * \sa qmlUnregisterModuleImport()
+ */
+void qmlRegisterModuleImport(const char *uri, int moduleMajor,
+ const char *import, int importMajor, int importMinor)
+{
+ QQmlMetaType::registerModuleImport(
+ QString::fromUtf8(uri), resolveModuleVersion(moduleMajor),
+ resolveImport(QString::fromUtf8(import), importMajor, importMinor));
+}
+
+
+/*!
+ * \relates QQmlEngine
+ * Removes a module import previously registered with qmlRegisterModuleImport()
+ *
+ * Calling this function makes sure that \a import of version
+ * \a{importMajor}.\a{importMinor} is not automatically imported anymore when
+ * \a uri of version \a moduleMajor is. The version resolution works the same
+ * way as with \l qmlRegisterModuleImport().
+ *
+ * \sa qmlRegisterModuleImport()
+ */
+void qmlUnregisterModuleImport(const char *uri, int moduleMajor,
+ const char *import, int importMajor, int importMinor)
+{
+ QQmlMetaType::unregisterModuleImport(
+ QString::fromUtf8(uri), resolveModuleVersion(moduleMajor),
+ resolveImport(QString::fromUtf8(import), importMajor, importMinor));
}
//From qqml.h
int qmlTypeId(const char *uri, int versionMajor, int versionMinor, const char *qmlName)
{
- return QQmlMetaType::typeId(uri, versionMajor, versionMinor, qmlName);
+ return QQmlMetaType::typeId(uri, QTypeRevision::fromVersion(versionMajor, versionMinor), qmlName);
}
-// From qqmlprivate.h
-QObject *QQmlPrivate::RegisterSingletonFunctor::operator()(QQmlEngine *qeng, QJSEngine *)
+static bool checkSingletonInstance(QQmlEngine *engine, QObject *instance)
{
- if (!m_object) {
+ if (!instance) {
QQmlError error;
- error.setDescription(QLatin1String("The registered singleton has already been deleted. Ensure that it outlives the engine."));
- QQmlEnginePrivate::get(qeng)->warning(qeng, error);
- return nullptr;
+ 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 (qeng->thread() != m_object->thread()) {
+ 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 (!checkSingletonInstance(qeng, m_object))
+ return nullptr;
+
+ 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;
};
-static QVector<int> availableRevisions(const QMetaObject *metaObject)
+static QVector<QTypeRevision> availableRevisions(const QMetaObject *metaObject)
{
- QVector<int> revisions;
+ QVector<QTypeRevision> revisions;
if (!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(revision);
+ revisions.append(QTypeRevision::fromEncodedVersion(revision));
}
const int methodOffset = metaObject->methodOffset();
const int methodCount = metaObject->methodCount();
@@ -122,7 +438,7 @@ static QVector<int> availableRevisions(const QMetaObject *metaObject)
methodIndex < methodEnd; ++methodIndex) {
const QMetaMethod method = metaObject->method(methodIndex);
if (int revision = method.revision())
- revisions.append(revision);
+ revisions.append(QTypeRevision::fromEncodedVersion(revision));
}
// Need to also check parent meta objects, as their revisions are inherited.
@@ -132,13 +448,328 @@ static QVector<int> availableRevisions(const QMetaObject *metaObject)
return revisions;
}
+template<typename Registration>
+void assignVersions(Registration *registration, QTypeRevision revision,
+ QTypeRevision defaultVersion)
+{
+ const quint8 majorVersion = revision.hasMajorVersion() ? revision.majorVersion()
+ : defaultVersion.majorVersion();
+ registration->version = revision.hasMinorVersion()
+ ? QTypeRevision::fromVersion(majorVersion, revision.minorVersion())
+ : QTypeRevision::fromMajorVersion(majorVersion);
+ registration->revision = revision;
+}
+
+static QVector<QTypeRevision> prepareRevisions(const QMetaObject *metaObject, QTypeRevision added)
+{
+ auto revisions = availableRevisions(metaObject);
+ revisions.append(added);
+ return revisions;
+}
+
+static void uniqueRevisions(QVector<QTypeRevision> *revisions, QTypeRevision defaultVersion,
+ QTypeRevision added)
+{
+ bool revisionsHaveMajorVersions = false;
+ for (QTypeRevision revision : QVector<QTypeRevision>(*revisions)) { // yes, copy
+ // allow any minor version for each explicitly specified past major one
+ if (revision.hasMajorVersion()) {
+ revisionsHaveMajorVersions = true;
+ if (revision.majorVersion() < defaultVersion.majorVersion())
+ revisions->append(QTypeRevision::fromVersion(revision.majorVersion(), 254));
+ }
+ }
+
+ if (revisionsHaveMajorVersions) {
+ if (!added.hasMajorVersion()) {
+ // If added in unspecified major version, assume default one.
+ revisions->append(QTypeRevision::fromVersion(defaultVersion.majorVersion(),
+ added.minorVersion()));
+ } else if (added.majorVersion() < defaultVersion.majorVersion()) {
+ // If added in past major version, add .0 of default version.
+ revisions->append(QTypeRevision::fromVersion(defaultVersion.majorVersion(), 0));
+ }
+ }
+
+ std::sort(revisions->begin(), revisions->end());
+ const auto it = std::unique(revisions->begin(), revisions->end());
+ 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(
@@ -148,149 +779,91 @@ 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);
-
- const QString noCreateReason = creatable
- ? QString()
- : QString::fromUtf8(classInfo(type.classInfoMetaObject, "QML.UncreatableReason"));
- RegisterType revisionRegistration = {
- 1,
- type.typeId,
- type.listId,
- creatable ? type.objectSize : 0,
- nullptr,
- noCreateReason,
- type.uri,
- type.versionMajor,
- -1,
- nullptr,
- type.metaObject,
- type.attachedPropertiesFunction,
- type.attachedPropertiesMetaObject,
- type.parserStatusCast,
- type.valueSourceCast,
- type.valueInterceptorCast,
- type.extensionObjectCreate,
- type.extensionMetaObject,
- nullptr,
- -1
- };
-
- const int added = intClassInfo(type.classInfoMetaObject, "QML.AddedInMinorVersion", 0);
- const int removed = intClassInfo(type.classInfoMetaObject, "QML.RemovedInMinorVersion", -1);
-
- auto revisions = availableRevisions(type.metaObject);
- revisions.append(qMax(added, 0));
- if (type.attachedPropertiesMetaObject)
- revisions += availableRevisions(type.attachedPropertiesMetaObject);
-
- std::sort(revisions.begin(), revisions.end());
- const auto it = std::unique(revisions.begin(), revisions.end());
- revisions.erase(it, revisions.end());
-
- const bool typeWasRemoved = removed >= added;
- for (int revision : revisions) {
- if (revision < added)
- continue;
-
- // When removed, we still add revisions, but anonymous ones
- if (typeWasRemoved && 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;
+ doRegisterTypeAndRevisions(type, names);
}
- // Equivalent of qmlRegisterRevision<T, revision>(...)
- revisionRegistration.versionMinor = revision;
- revisionRegistration.revision = revision;
- revisionRegistration.customParser = type.customParserFactory();
-
- qmlregister(TypeRegistration, &revisionRegistration);
}
break;
}
case SingletonAndRevisionsRegistration: {
const RegisterSingletonTypeAndRevisions &type
= *reinterpret_cast<RegisterSingletonTypeAndRevisions *>(data);
- const char *elementName = classElementName(type.classInfoMetaObject);
- RegisterSingletonType revisionRegistration = {
- QmlCurrentSingletonTypeRegistrationVersion,
+ 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);
+ RegisterSequentialContainer revisionRegistration = {
+ 0,
type.uri,
- type.versionMajor,
- -1,
- elementName,
-
- type.scriptApi,
+ type.version,
nullptr,
- type.instanceMetaObject,
type.typeId,
- -1,
-
- type.generalizedQobjectApi
+ type.metaSequence,
+ QTypeRevision()
};
- const int added = intClassInfo(type.classInfoMetaObject, "QML.AddedInMinorVersion", 0);
- const int removed = intClassInfo(type.classInfoMetaObject, "QML.RemovedInMinorVersion", -1);
-
- auto revisions = availableRevisions(type.instanceMetaObject);
- revisions.append(qMax(added, 0));
+ const QTypeRevision added = revisionClassInfo(
+ type.classInfoMetaObject, "QML.AddedInVersion",
+ QTypeRevision::fromMinorVersion(0));
+ QList<QTypeRevision> revisions = revisionClassInfos(
+ type.classInfoMetaObject, "QML.ExtraVersion");
+ revisions.append(added);
+ uniqueRevisions(&revisions, type.version, added);
- std::sort(revisions.begin(), revisions.end());
- const auto it = std::unique(revisions.begin(), revisions.end());
- revisions.erase(it, revisions.end());
-
- const bool typeWasRemoved = removed >= added;
- for (int 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 (typeWasRemoved && revision >= removed) {
- revisionRegistration.typeName = nullptr;
- revisionRegistration.scriptApi = nullptr;
- revisionRegistration.generalizedQobjectApi = nullptr;
- } else {
- revisionRegistration.typeName = elementName;
- revisionRegistration.scriptApi = type.scriptApi;
- revisionRegistration.generalizedQobjectApi = type.generalizedQobjectApi;
- }
-
- // Equivalent of qmlRegisterRevision<T, revision>(...)
- revisionRegistration.versionMinor = revision;
- revisionRegistration.revision = revision;
-
- qmlregister(SingletonRegistration, &revisionRegistration);
+ assignVersions(&revisionRegistration, revision, type.version);
+ const int id = qmlregister(SequentialContainerRegistration, &revisionRegistration);
+ if (type.qmlTypeIds)
+ type.qmlTypeIds->append(id);
}
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:
+ 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)
@@ -303,6 +876,9 @@ void QQmlPrivate::qmlunregister(RegistrationType type, quintptr data)
QQmlMetaType::removeCachedUnitLookupFunction(
reinterpret_cast<QmlUnitCacheLookupFunction>(data));
break;
+ case SequentialContainerRegistration:
+ QQmlMetaType::unregisterSequentialContainer(data);
+ break;
case TypeRegistration:
case InterfaceRegistration:
case SingletonRegistration:
@@ -312,6 +888,7 @@ void QQmlPrivate::qmlunregister(RegistrationType type, quintptr data)
break;
case TypeAndRevisionsRegistration:
case SingletonAndRevisionsRegistration:
+ case SequentialContainerAndRevisionsRegistration:
// Currently unnecessary. We'd need a special data structure to hold
// URI + majorVersion and then we'd iterate the minor versions, look up the
// associated QQmlType objects by uri/elementName/major/minor and qmlunregister
@@ -321,4 +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, bool)
+{
+ using T = QQmlTypeNotAvailable;
+
+ RegisterTypeAndRevisions type = {
+ 3,
+ QmlMetaType<T>::self(),
+ QmlMetaType<T>::list(),
+ 0,
+ nullptr,
+ nullptr,
+ nullptr,
+
+ uri,
+ QTypeRevision::fromMajorVersion(versionMajor),
+
+ &QQmlTypeNotAvailable::staticMetaObject,
+ classInfoMetaObject,
+
+ attachedPropertiesFunc<T>(),
+ attachedPropertiesMetaObject<T>(),
+
+ StaticCastSelector<T, QQmlParserStatus>::cast(),
+ StaticCastSelector<T, QQmlPropertyValueSource>::cast(),
+ StaticCastSelector<T, QQmlPropertyValueInterceptor>::cast(),
+
+ nullptr,
+ extension,
+ qmlCreateCustomParser<T>,
+ qmlTypeIds,
+ QQmlPrivate::StaticCastSelector<T, QQmlFinalizerHook>::cast(),
+ false,
+ QmlMetaType<T>::sequence(),
+ };
+
+ qmlregister(TypeAndRevisionsRegistration, &type);
+}
+
+QObject *AOTCompiledContext::thisObject() const
+{
+ return static_cast<QV4::MetaTypesStackFrame *>(engine->handle()->currentStackFrame)
+ ->thisObject();
+}
+
+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 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 QQmlLoggingCategoryBase at run time.
+ if (QQmlLoggingCategoryBase *qQmlLoggingCategory
+ = qobject_cast<QQmlLoggingCategoryBase *>(wrapper)) {
+ const 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 ae3893dd73..3e6441bfa7 100644
--- a/src/qml/qml/qqml.h
+++ b/src/qml/qml/qqml.h
@@ -1,61 +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) 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>
+#include <QtCore/qmetacontainer.h>
+#include <QtCore/qversionnumber.h>
#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) \
@@ -67,52 +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_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);
-
-#define QML_ADDED_IN_MINOR_VERSION(VERSION) \
- Q_CLASSINFO("QML.AddedInMinorVersion", #VERSION)
-
-#define QML_REMOVED_IN_MINOR_VERSION(VERSION) \
- Q_CLASSINFO("QML.RemovedInMinorVersion", #VERSION)
-
-#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);
-
-#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);
-
enum { /* TYPEINFO flags */
QML_HAS_ATTACHED_PROPERTIES = 0x01
};
@@ -139,18 +55,17 @@ QQmlCustomParser *qmlCreateCustomParser();
template<typename T>
int qmlRegisterAnonymousType(const char *uri, int versionMajor)
{
- QML_GETTYPENAMES
-
QQmlPrivate::RegisterType type = {
+ QQmlPrivate::RegisterType::CurrentVersion,
+ QQmlPrivate::QmlMetaType<T>::self(),
+ QQmlPrivate::QmlMetaType<T>::list(),
0,
-
- qRegisterNormalizedMetaType<T *>(pointerName.constData()),
- qRegisterNormalizedMetaType<QQmlListProperty<T> >(listName.constData()),
- 0,
- nullptr,
+ nullptr, nullptr,
QString(),
+ QQmlPrivate::ValueType<T, void>::create,
- uri, versionMajor, 0, nullptr, &T::staticMetaObject,
+ uri, QTypeRevision::fromVersion(versionMajor, 0), nullptr,
+ QQmlPrivate::StaticMetaObject<T>::staticMetaObject(),
QQmlPrivate::attachedPropertiesFunc<T>(),
QQmlPrivate::attachedPropertiesMetaObject<T>(),
@@ -162,37 +77,88 @@ int qmlRegisterAnonymousType(const char *uri, int versionMajor)
nullptr, nullptr,
nullptr,
- 0
+ 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);
}
-#if QT_DEPRECATED_SINCE(5, 14)
+//! \internal
template<typename T>
-QT_DEPRECATED_VERSION_X_5_14("Use qmlRegisterAnonymousType instead") int qmlRegisterType()
+void qmlRegisterAnonymousTypesAndRevisions(const char *uri, int versionMajor)
{
- return qmlRegisterAnonymousType<T>("", 1);
+ // 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);
}
-#endif
-int Q_QML_EXPORT qmlRegisterTypeNotAvailable(const char *uri, int versionMajor, int versionMinor, const char *qmlName, const QString& message);
+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);
template<typename T>
int qmlRegisterUncreatableType(const char *uri, int versionMajor, int versionMinor, const char *qmlName, const QString& reason)
{
- QML_GETTYPENAMES
-
QQmlPrivate::RegisterType type = {
+ QQmlPrivate::RegisterType::CurrentVersion,
+ QQmlPrivate::QmlMetaType<T>::self(),
+ QQmlPrivate::QmlMetaType<T>::list(),
0,
-
- qRegisterNormalizedMetaType<T *>(pointerName.constData()),
- qRegisterNormalizedMetaType<QQmlListProperty<T> >(listName.constData()),
- 0,
+ nullptr,
nullptr,
reason,
+ QQmlPrivate::ValueType<T, void>::create,
- uri, versionMajor, versionMinor, qmlName, &T::staticMetaObject,
+ uri, QTypeRevision::fromVersion(versionMajor, versionMinor), qmlName,
+ QQmlPrivate::StaticMetaObject<T>::staticMetaObject(),
QQmlPrivate::attachedPropertiesFunc<T>(),
QQmlPrivate::attachedPropertiesMetaObject<T>(),
@@ -204,7 +170,9 @@ int qmlRegisterUncreatableType(const char *uri, int versionMajor, int versionMin
nullptr, nullptr,
nullptr,
- 0
+ QTypeRevision::zero(),
+ QQmlPrivate::StaticCastSelector<T,QQmlFinalizerHook>::cast(),
+ QQmlPrivate::ValueTypeCreationMethod::None,
};
return QQmlPrivate::qmlregister(QQmlPrivate::TypeRegistration, &type);
@@ -213,18 +181,18 @@ int qmlRegisterUncreatableType(const char *uri, int versionMajor, int versionMin
template<typename T, int metaObjectRevision>
int qmlRegisterUncreatableType(const char *uri, int versionMajor, int versionMinor, const char *qmlName, const QString& reason)
{
- QML_GETTYPENAMES
-
QQmlPrivate::RegisterType type = {
- 1,
-
- qRegisterNormalizedMetaType<T *>(pointerName.constData()),
- qRegisterNormalizedMetaType<QQmlListProperty<T> >(listName.constData()),
+ QQmlPrivate::RegisterType::CurrentVersion,
+ QQmlPrivate::QmlMetaType<T>::self(),
+ QQmlPrivate::QmlMetaType<T>::list(),
0,
nullptr,
+ nullptr,
reason,
+ QQmlPrivate::ValueType<T, void>::create,
- uri, versionMajor, versionMinor, qmlName, &T::staticMetaObject,
+ uri, QTypeRevision::fromVersion(versionMajor, versionMinor), qmlName,
+ QQmlPrivate::StaticMetaObject<T>::staticMetaObject(),
QQmlPrivate::attachedPropertiesFunc<T>(),
QQmlPrivate::attachedPropertiesMetaObject<T>(),
@@ -236,7 +204,9 @@ int qmlRegisterUncreatableType(const char *uri, int versionMajor, int versionMin
nullptr, nullptr,
nullptr,
- metaObjectRevision
+ QTypeRevision::fromMinorVersion(metaObjectRevision),
+ QQmlPrivate::StaticCastSelector<T,QQmlFinalizerHook>::cast(),
+ QQmlPrivate::ValueTypeCreationMethod::None,
};
return QQmlPrivate::qmlregister(QQmlPrivate::TypeRegistration, &type);
@@ -245,8 +215,6 @@ int qmlRegisterUncreatableType(const char *uri, int versionMajor, int versionMin
template<typename T, typename E>
int qmlRegisterExtendedUncreatableType(const char *uri, int versionMajor, int versionMinor, const char *qmlName, const QString& reason)
{
- QML_GETTYPENAMES
-
QQmlAttachedPropertiesFunc attached = QQmlPrivate::attachedPropertiesFunc<E>();
const QMetaObject * attachedMetaObject = QQmlPrivate::attachedPropertiesMetaObject<E>();
if (!attached) {
@@ -255,15 +223,17 @@ int qmlRegisterExtendedUncreatableType(const char *uri, int versionMajor, int ve
}
QQmlPrivate::RegisterType type = {
- 0,
-
- qRegisterNormalizedMetaType<T *>(pointerName.constData()),
- qRegisterNormalizedMetaType<QQmlListProperty<T> >(listName.constData()),
+ QQmlPrivate::RegisterType::CurrentVersion,
+ QQmlPrivate::QmlMetaType<T>::self(),
+ QQmlPrivate::QmlMetaType<T>::list(),
0,
nullptr,
+ nullptr,
reason,
+ QQmlPrivate::ValueType<T, E>::create,
- uri, versionMajor, versionMinor, qmlName, &T::staticMetaObject,
+ uri, QTypeRevision::fromVersion(versionMajor, versionMinor), qmlName,
+ QQmlPrivate::StaticMetaObject<T>::staticMetaObject(),
attached,
attachedMetaObject,
@@ -272,10 +242,12 @@ int qmlRegisterExtendedUncreatableType(const char *uri, int versionMajor, int ve
QQmlPrivate::StaticCastSelector<T,QQmlPropertyValueSource>::cast(),
QQmlPrivate::StaticCastSelector<T,QQmlPropertyValueInterceptor>::cast(),
- QQmlPrivate::createParent<E>, &E::staticMetaObject,
+ QQmlPrivate::ExtendedType<E>::createParent, QQmlPrivate::ExtendedType<E>::staticMetaObject(),
nullptr,
- 0
+ QTypeRevision::zero(),
+ QQmlPrivate::StaticCastSelector<T,QQmlFinalizerHook>::cast(),
+ QQmlPrivate::ValueTypeCreationMethod::None,
};
return QQmlPrivate::qmlregister(QQmlPrivate::TypeRegistration, &type);
@@ -284,8 +256,6 @@ int qmlRegisterExtendedUncreatableType(const char *uri, int versionMajor, int ve
template<typename T, typename E, int metaObjectRevision>
int qmlRegisterExtendedUncreatableType(const char *uri, int versionMajor, int versionMinor, const char *qmlName, const QString& reason)
{
- QML_GETTYPENAMES
-
QQmlAttachedPropertiesFunc attached = QQmlPrivate::attachedPropertiesFunc<E>();
const QMetaObject * attachedMetaObject = QQmlPrivate::attachedPropertiesMetaObject<E>();
if (!attached) {
@@ -294,15 +264,17 @@ int qmlRegisterExtendedUncreatableType(const char *uri, int versionMajor, int ve
}
QQmlPrivate::RegisterType type = {
- 1,
-
- qRegisterNormalizedMetaType<T *>(pointerName.constData()),
- qRegisterNormalizedMetaType<QQmlListProperty<T> >(listName.constData()),
+ QQmlPrivate::RegisterType::CurrentVersion,
+ QQmlPrivate::QmlMetaType<T>::self(),
+ QQmlPrivate::QmlMetaType<T>::list(),
0,
nullptr,
+ nullptr,
reason,
+ QQmlPrivate::ValueType<T, E>::create,
- uri, versionMajor, versionMinor, qmlName, &T::staticMetaObject,
+ uri, QTypeRevision::fromVersion(versionMajor, versionMinor), qmlName,
+ QQmlPrivate::StaticMetaObject<T>::staticMetaObject(),
attached,
attachedMetaObject,
@@ -311,10 +283,12 @@ int qmlRegisterExtendedUncreatableType(const char *uri, int versionMajor, int ve
QQmlPrivate::StaticCastSelector<T,QQmlPropertyValueSource>::cast(),
QQmlPrivate::StaticCastSelector<T,QQmlPropertyValueInterceptor>::cast(),
- QQmlPrivate::createParent<E>, &E::staticMetaObject,
+ QQmlPrivate::ExtendedType<E>::createParent, QQmlPrivate::ExtendedType<E>::staticMetaObject(),
nullptr,
- metaObjectRevision
+ QTypeRevision::fromMinorVersion(metaObjectRevision),
+ QQmlPrivate::StaticCastSelector<T,QQmlFinalizerHook>::cast(),
+ QQmlPrivate::ValueTypeCreationMethod::None,
};
return QQmlPrivate::qmlregister(QQmlPrivate::TypeRegistration, &type);
@@ -325,17 +299,20 @@ Q_QML_EXPORT int qmlRegisterUncreatableMetaObject(const QMetaObject &staticMetaO
template<typename T>
int qmlRegisterType(const char *uri, int versionMajor, int versionMinor, const char *qmlName)
{
- QML_GETTYPENAMES
+ 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,
-
- qRegisterNormalizedMetaType<T *>(pointerName.constData()),
- qRegisterNormalizedMetaType<QQmlListProperty<T> >(listName.constData()),
- sizeof(T), QQmlPrivate::createInto<T>,
+ QQmlPrivate::RegisterType::CurrentVersion,
+ QQmlPrivate::QmlMetaType<T>::self(),
+ QQmlPrivate::QmlMetaType<T>::list(),
+ sizeof(T), QQmlPrivate::Constructors<T>::createInto, nullptr,
QString(),
+ QQmlPrivate::ValueType<T, void>::create,
- uri, versionMajor, versionMinor, qmlName, &T::staticMetaObject,
+ uri, QTypeRevision::fromVersion(versionMajor, versionMinor), qmlName,
+ QQmlPrivate::StaticMetaObject<T>::staticMetaObject(),
QQmlPrivate::attachedPropertiesFunc<T>(),
QQmlPrivate::attachedPropertiesMetaObject<T>(),
@@ -347,7 +324,9 @@ int qmlRegisterType(const char *uri, int versionMajor, int versionMinor, const c
nullptr, nullptr,
nullptr,
- 0
+ QTypeRevision::zero(),
+ QQmlPrivate::StaticCastSelector<T,QQmlFinalizerHook>::cast(),
+ QQmlPrivate::ValueTypeCreationMethod::None,
};
return QQmlPrivate::qmlregister(QQmlPrivate::TypeRegistration, &type);
@@ -356,17 +335,20 @@ 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)
{
- QML_GETTYPENAMES
+ 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 = {
- 1,
-
- qRegisterNormalizedMetaType<T *>(pointerName.constData()),
- qRegisterNormalizedMetaType<QQmlListProperty<T> >(listName.constData()),
- sizeof(T), QQmlPrivate::createInto<T>,
+ QQmlPrivate::RegisterType::CurrentVersion,
+ QQmlPrivate::QmlMetaType<T>::self(),
+ QQmlPrivate::QmlMetaType<T>::list(),
+ sizeof(T), QQmlPrivate::Constructors<T>::createInto, nullptr,
QString(),
+ QQmlPrivate::ValueType<T, void>::create,
- uri, versionMajor, versionMinor, qmlName, &T::staticMetaObject,
+ uri, QTypeRevision::fromVersion(versionMajor, versionMinor), qmlName,
+ QQmlPrivate::StaticMetaObject<T>::staticMetaObject(),
QQmlPrivate::attachedPropertiesFunc<T>(),
QQmlPrivate::attachedPropertiesMetaObject<T>(),
@@ -378,7 +360,9 @@ int qmlRegisterType(const char *uri, int versionMajor, int versionMinor, const c
nullptr, nullptr,
nullptr,
- metaObjectRevision
+ QTypeRevision::fromMinorVersion(metaObjectRevision),
+ QQmlPrivate::StaticCastSelector<T,QQmlFinalizerHook>::cast(),
+ QQmlPrivate::ValueTypeCreationMethod::None,
};
return QQmlPrivate::qmlregister(QQmlPrivate::TypeRegistration, &type);
@@ -387,17 +371,16 @@ int qmlRegisterType(const char *uri, int versionMajor, int versionMinor, const c
template<typename T, int metaObjectRevision>
int qmlRegisterRevision(const char *uri, int versionMajor, int versionMinor)
{
- QML_GETTYPENAMES
-
QQmlPrivate::RegisterType type = {
- 1,
-
- qRegisterNormalizedMetaType<T *>(pointerName.constData()),
- qRegisterNormalizedMetaType<QQmlListProperty<T> >(listName.constData()),
- sizeof(T), QQmlPrivate::createInto<T>,
+ QQmlPrivate::RegisterType::CurrentVersion,
+ QQmlPrivate::QmlMetaType<T>::self(),
+ QQmlPrivate::QmlMetaType<T>::list(),
+ sizeof(T), QQmlPrivate::Constructors<T>::createInto, nullptr,
QString(),
+ QQmlPrivate::ValueType<T, void>::create,
- uri, versionMajor, versionMinor, nullptr, &T::staticMetaObject,
+ uri, QTypeRevision::fromVersion(versionMajor, versionMinor), nullptr,
+ QQmlPrivate::StaticMetaObject<T>::staticMetaObject(),
QQmlPrivate::attachedPropertiesFunc<T>(),
QQmlPrivate::attachedPropertiesMetaObject<T>(),
@@ -409,28 +392,36 @@ int qmlRegisterRevision(const char *uri, int versionMajor, int versionMinor)
nullptr, nullptr,
nullptr,
- metaObjectRevision
+ QTypeRevision::fromMinorVersion(metaObjectRevision),
+ QQmlPrivate::StaticCastSelector<T,QQmlFinalizerHook>::cast(),
+ QQmlPrivate::ValueTypeCreationMethod::None,
};
return QQmlPrivate::qmlregister(QQmlPrivate::TypeRegistration, &type);
}
-
template<typename T, typename E>
-int qmlRegisterExtendedType()
+int qmlRegisterExtendedType(const char *uri, int versionMajor)
{
- QML_GETTYPENAMES
+ static_assert(!std::is_abstract_v<T>,
+ "It is not possible to register an extension to an abstract type with qmlRegisterExtendedType.");
- QQmlPrivate::RegisterType type = {
- 0,
+ static_assert(!std::is_abstract_v<E>,
+ "It is not possible to register an abstract type with qmlRegisterExtendedType. "
+ "Maybe you wanted qmlRegisterExtendedUncreatableType?");
- qRegisterNormalizedMetaType<T *>(pointerName.constData()),
- qRegisterNormalizedMetaType<QQmlListProperty<T> >(listName.constData()),
+ QQmlPrivate::RegisterType type = {
+ QQmlPrivate::RegisterType::CurrentVersion,
+ QQmlPrivate::QmlMetaType<T>::self(),
+ QQmlPrivate::QmlMetaType<T>::list(),
0,
nullptr,
+ nullptr,
QString(),
+ QQmlPrivate::ValueType<T, E>::create,
- nullptr, 0, 0, nullptr, &T::staticMetaObject,
+ uri, QTypeRevision::fromVersion(versionMajor, 0), nullptr,
+ QQmlPrivate::StaticMetaObject<T>::staticMetaObject(),
QQmlPrivate::attachedPropertiesFunc<T>(),
QQmlPrivate::attachedPropertiesMetaObject<T>(),
@@ -439,10 +430,12 @@ int qmlRegisterExtendedType()
QQmlPrivate::StaticCastSelector<T,QQmlPropertyValueSource>::cast(),
QQmlPrivate::StaticCastSelector<T,QQmlPropertyValueInterceptor>::cast(),
- QQmlPrivate::createParent<E>, &E::staticMetaObject,
+ QQmlPrivate::ExtendedType<E>::createParent, QQmlPrivate::ExtendedType<E>::staticMetaObject(),
nullptr,
- 0
+ QTypeRevision::zero(),
+ QQmlPrivate::StaticCastSelector<T,QQmlFinalizerHook>::cast(),
+ QQmlPrivate::ValueTypeCreationMethod::None,
};
return QQmlPrivate::qmlregister(QQmlPrivate::TypeRegistration, &type);
@@ -452,7 +445,12 @@ template<typename T, typename E>
int qmlRegisterExtendedType(const char *uri, int versionMajor, int versionMinor,
const char *qmlName)
{
- QML_GETTYPENAMES
+ 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>();
@@ -462,14 +460,15 @@ int qmlRegisterExtendedType(const char *uri, int versionMajor, int versionMinor,
}
QQmlPrivate::RegisterType type = {
- 0,
-
- qRegisterNormalizedMetaType<T *>(pointerName.constData()),
- qRegisterNormalizedMetaType<QQmlListProperty<T> >(listName.constData()),
- sizeof(T), QQmlPrivate::createInto<T>,
+ QQmlPrivate::RegisterType::CurrentVersion,
+ QQmlPrivate::QmlMetaType<T>::self(),
+ QQmlPrivate::QmlMetaType<T>::list(),
+ sizeof(T), QQmlPrivate::Constructors<T>::createInto, nullptr,
QString(),
+ QQmlPrivate::ValueType<T, E>::create,
- uri, versionMajor, versionMinor, qmlName, &T::staticMetaObject,
+ uri, QTypeRevision::fromVersion(versionMajor, versionMinor), qmlName,
+ QQmlPrivate::StaticMetaObject<T>::staticMetaObject(),
attached,
attachedMetaObject,
@@ -478,30 +477,30 @@ int qmlRegisterExtendedType(const char *uri, int versionMajor, int versionMinor,
QQmlPrivate::StaticCastSelector<T,QQmlPropertyValueSource>::cast(),
QQmlPrivate::StaticCastSelector<T,QQmlPropertyValueInterceptor>::cast(),
- QQmlPrivate::createParent<E>, &E::staticMetaObject,
+ QQmlPrivate::ExtendedType<E>::createParent, QQmlPrivate::ExtendedType<E>::staticMetaObject(),
nullptr,
- 0
+ QTypeRevision::zero(),
+ QQmlPrivate::StaticCastSelector<T,QQmlFinalizerHook>::cast(),
+ QQmlPrivate::ValueTypeCreationMethod::None,
};
return QQmlPrivate::qmlregister(QQmlPrivate::TypeRegistration, &type);
}
template<typename T>
-int qmlRegisterInterface(const char *typeName)
+int qmlRegisterInterface(const char *uri, int versionMajor)
{
- QByteArray name(typeName);
-
- QByteArray pointerName(name + '*');
- QByteArray listName("QQmlListProperty<" + name + '>');
-
QQmlPrivate::RegisterInterface qmlInterface = {
0,
+ // An interface is not a QObject itself but is typically casted to one.
+ // Therefore, we still want the pointer.
+ QMetaType::fromType<T *>(),
+ QMetaType::fromType<QQmlListProperty<T> >(),
+ qobject_interface_iid<T *>(),
- qRegisterNormalizedMetaType<T *>(pointerName.constData()),
- qRegisterNormalizedMetaType<QQmlListProperty<T> >(listName.constData()),
-
- qobject_interface_iid<T *>()
+ uri,
+ QTypeRevision::fromVersion(versionMajor, 0)
};
return QQmlPrivate::qmlregister(QQmlPrivate::InterfaceRegistration, &qmlInterface);
@@ -511,17 +510,20 @@ template<typename T>
int qmlRegisterCustomType(const char *uri, int versionMajor, int versionMinor,
const char *qmlName, QQmlCustomParser *parser)
{
- QML_GETTYPENAMES
+ 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,
-
- qRegisterNormalizedMetaType<T *>(pointerName.constData()),
- qRegisterNormalizedMetaType<QQmlListProperty<T> >(listName.constData()),
- sizeof(T), QQmlPrivate::createInto<T>,
+ QQmlPrivate::RegisterType::CurrentVersion,
+ QQmlPrivate::QmlMetaType<T>::self(),
+ QQmlPrivate::QmlMetaType<T>::list(),
+ sizeof(T), QQmlPrivate::Constructors<T>::createInto, nullptr,
QString(),
+ QQmlPrivate::ValueType<T, void>::create,
- uri, versionMajor, versionMinor, qmlName, &T::staticMetaObject,
+ uri, QTypeRevision::fromVersion(versionMajor, versionMinor), qmlName,
+ QQmlPrivate::StaticMetaObject<T>::staticMetaObject(),
QQmlPrivate::attachedPropertiesFunc<T>(),
QQmlPrivate::attachedPropertiesMetaObject<T>(),
@@ -533,7 +535,9 @@ int qmlRegisterCustomType(const char *uri, int versionMajor, int versionMinor,
nullptr, nullptr,
parser,
- 0
+ QTypeRevision::zero(),
+ QQmlPrivate::StaticCastSelector<T,QQmlFinalizerHook>::cast(),
+ QQmlPrivate::ValueTypeCreationMethod::None,
};
return QQmlPrivate::qmlregister(QQmlPrivate::TypeRegistration, &type);
@@ -543,17 +547,20 @@ template<typename T, int metaObjectRevision>
int qmlRegisterCustomType(const char *uri, int versionMajor, int versionMinor,
const char *qmlName, QQmlCustomParser *parser)
{
- QML_GETTYPENAMES
+ 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 = {
- 1,
-
- qRegisterNormalizedMetaType<T *>(pointerName.constData()),
- qRegisterNormalizedMetaType<QQmlListProperty<T> >(listName.constData()),
- sizeof(T), QQmlPrivate::createInto<T>,
+ QQmlPrivate::RegisterType::CurrentVersion,
+ QQmlPrivate::QmlMetaType<T>::self(),
+ QQmlPrivate::QmlMetaType<T>::list(),
+ sizeof(T), QQmlPrivate::Constructors<T>::createInto, nullptr,
QString(),
+ QQmlPrivate::ValueType<T, void>::create,
- uri, versionMajor, versionMinor, qmlName, &T::staticMetaObject,
+ uri, QTypeRevision::fromVersion(versionMajor, versionMinor), qmlName,
+ QQmlPrivate::StaticMetaObject<T>::staticMetaObject(),
QQmlPrivate::attachedPropertiesFunc<T>(),
QQmlPrivate::attachedPropertiesMetaObject<T>(),
@@ -565,7 +572,9 @@ int qmlRegisterCustomType(const char *uri, int versionMajor, int versionMinor,
nullptr, nullptr,
parser,
- metaObjectRevision
+ QTypeRevision::fromMinorVersion(metaObjectRevision),
+ QQmlPrivate::StaticCastSelector<T,QQmlFinalizerHook>::cast(),
+ QQmlPrivate::ValueTypeCreationMethod::None,
};
return QQmlPrivate::qmlregister(QQmlPrivate::TypeRegistration, &type);
@@ -575,7 +584,11 @@ template<typename T, typename E>
int qmlRegisterCustomExtendedType(const char *uri, int versionMajor, int versionMinor,
const char *qmlName, QQmlCustomParser *parser)
{
- QML_GETTYPENAMES
+ 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>();
@@ -585,14 +598,15 @@ int qmlRegisterCustomExtendedType(const char *uri, int versionMajor, int version
}
QQmlPrivate::RegisterType type = {
- 0,
-
- qRegisterNormalizedMetaType<T *>(pointerName.constData()),
- qRegisterNormalizedMetaType<QQmlListProperty<T> >(listName.constData()),
- sizeof(T), QQmlPrivate::createInto<T>,
+ QQmlPrivate::RegisterType::CurrentVersion,
+ QQmlPrivate::QmlMetaType<T>::self(),
+ QQmlPrivate::QmlMetaType<T>::list(),
+ sizeof(T), QQmlPrivate::Constructors<T>::createInto, nullptr,
QString(),
+ QQmlPrivate::ValueType<T, E>::create,
- uri, versionMajor, versionMinor, qmlName, &T::staticMetaObject,
+ uri, QTypeRevision::fromVersion(versionMajor, versionMinor), qmlName,
+ QQmlPrivate::StaticMetaObject<T>::staticMetaObject(),
attached,
attachedMetaObject,
@@ -601,10 +615,12 @@ int qmlRegisterCustomExtendedType(const char *uri, int versionMajor, int version
QQmlPrivate::StaticCastSelector<T,QQmlPropertyValueSource>::cast(),
QQmlPrivate::StaticCastSelector<T,QQmlPropertyValueInterceptor>::cast(),
- QQmlPrivate::createParent<E>, &E::staticMetaObject,
+ QQmlPrivate::ExtendedType<E>::createParent, QQmlPrivate::ExtendedType<E>::staticMetaObject(),
parser,
- 0
+ QTypeRevision::zero(),
+ QQmlPrivate::StaticCastSelector<T,QQmlFinalizerHook>::cast(),
+ QQmlPrivate::ValueTypeCreationMethod::None,
};
return QQmlPrivate::qmlregister(QQmlPrivate::TypeRegistration, &type);
@@ -615,41 +631,34 @@ class QQmlEngine;
class QJSValue;
class QJSEngine;
-#ifndef Q_QDOC
-namespace QtQml {
-#endif
- // declared in namespace to avoid symbol conflicts with QtDeclarative
- Q_QML_EXPORT void qmlExecuteDeferred(QObject *);
- Q_QML_EXPORT QQmlContext *qmlContext(const QObject *);
- Q_QML_EXPORT QQmlEngine *qmlEngine(const QObject *);
-#if QT_DEPRECATED_SINCE(5, 14)
- Q_QML_EXPORT QT_DEPRECATED_VERSION_X_5_14("Use qmlAttachedPropertiesObject(QObject *, QQmlAttachedPropertiesFunc, bool")
- QObject *qmlAttachedPropertiesObjectById(int, const QObject *, bool create = true);
- Q_QML_EXPORT QT_DEPRECATED_VERSION_X_5_14("Use qmlAttachedPropertiesObject(QObject *, QQmlAttachedPropertiesFunc, bool")
- QObject *qmlAttachedPropertiesObject(
- int *, const QObject *, const QMetaObject *, bool create);
-#endif
- Q_QML_EXPORT QQmlAttachedPropertiesFunc qmlAttachedPropertiesFunction(QObject *,
- const QMetaObject *);
- Q_QML_EXPORT QObject *qmlAttachedPropertiesObject(QObject *, QQmlAttachedPropertiesFunc func,
- bool create = true);
-#ifndef Q_QDOC
-}
-
-QT_WARNING_PUSH
-QT_WARNING_DISABLE_CLANG("-Wheader-hygiene")
-
-// This is necessary to allow for QtQuick1 and QtQuick2 scenes in a single application.
-using namespace QtQml;
-
-QT_WARNING_POP
-
-#endif // Q_QDOC
+Q_QML_EXPORT void qmlExecuteDeferred(QObject *);
+Q_QML_EXPORT QQmlContext *qmlContext(const QObject *);
+Q_QML_EXPORT QQmlEngine *qmlEngine(const QObject *);
+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);
Q_QML_EXPORT void qmlRegisterModule(const char *uri, int versionMajor, int versionMinor);
+enum QQmlModuleImportSpecialVersions: int {
+ QQmlModuleImportModuleAny = -1,
+ QQmlModuleImportLatest = -1,
+ QQmlModuleImportAuto = -2
+};
+
+Q_QML_EXPORT void qmlRegisterModuleImport(const char *uri, int moduleMajor,
+ const char *import,
+ int importMajor = QQmlModuleImportLatest,
+ int importMinor = QQmlModuleImportLatest);
+Q_QML_EXPORT void qmlUnregisterModuleImport(const char *uri, int moduleMajor,
+ const char *import,
+ int importMajor = QQmlModuleImportLatest,
+ int importMinor = QQmlModuleImportLatest);
+
template<typename T>
QObject *qmlAttachedPropertiesObject(const QObject *obj, bool create = true)
{
@@ -661,62 +670,68 @@ 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 *))
+#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, versionMajor, versionMinor, typeName,
-
- callback, nullptr, nullptr, 0, 0, {}
+ uri,
+ QTypeRevision::fromVersion(versionMajor, versionMinor),
+ typeName,
+ std::forward<F>(callback),
+ nullptr,
+ nullptr,
+ QMetaType(),
+ nullptr, nullptr,
+ QTypeRevision::zero()
};
return QQmlPrivate::qmlregister(QQmlPrivate::SingletonRegistration, &api);
}
-enum { QmlCurrentSingletonTypeRegistrationVersion = 3 };
+#ifdef Q_QDOC
template <typename T>
-inline int qmlRegisterSingletonType(const char *uri, int versionMajor, int versionMinor, const char *typeName,
- QObject *(*callback)(QQmlEngine *, QJSEngine *))
-{
- QML_GETTYPENAMES
-
- QQmlPrivate::RegisterSingletonType api = {
- QmlCurrentSingletonTypeRegistrationVersion,
-
- uri, versionMajor, versionMinor, typeName,
-
- nullptr, nullptr, &T::staticMetaObject, qRegisterNormalizedMetaType<T *>(pointerName.constData()), 0, callback
- };
-
- return QQmlPrivate::qmlregister(QQmlPrivate::SingletonRegistration, &api);
-}
-
-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)
+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, void>::type* = nullptr>
+int qmlRegisterSingletonType(
+ const char *uri, int versionMajor, int versionMinor, const char *typeName, F &&callback)
+#endif
{
-
- QML_GETTYPENAMES
-
QQmlPrivate::RegisterSingletonType api = {
- QmlCurrentSingletonTypeRegistrationVersion,
-
- uri, versionMajor, versionMinor, typeName,
-
- nullptr, nullptr, &T::staticMetaObject, qRegisterNormalizedMetaType<T *>(pointerName.constData()), 0, callback
+ 0,
+ uri,
+ QTypeRevision::fromVersion(versionMajor, versionMinor),
+ typeName,
+ nullptr,
+ std::forward<F>(callback),
+ QQmlPrivate::StaticMetaObject<T>::staticMetaObject(),
+ QQmlPrivate::QmlMetaType<T>::self(),
+ nullptr, nullptr,
+ QTypeRevision::zero()
};
return QQmlPrivate::qmlregister(QQmlPrivate::SingletonRegistration, &api);
}
+#ifdef Q_QDOC
+int qmlRegisterSingletonInstance(const char *uri, int versionMajor, int versionMinor, const char *typeName, QObject *cppObject)
+#else
template<typename T>
inline auto qmlRegisterSingletonInstance(const char *uri, int versionMajor, int versionMinor,
const char *typeName, T *cppObject) -> typename std::enable_if<std::is_base_of<QObject, T>::value, int>::type
+#endif
{
- QQmlPrivate::RegisterSingletonFunctor registrationFunctor;
+ QQmlPrivate::SingletonInstanceFunctor registrationFunctor;
registrationFunctor.m_object = cppObject;
return qmlRegisterSingletonType<T>(uri, versionMajor, versionMinor, typeName, registrationFunctor);
}
@@ -730,10 +745,10 @@ inline int qmlRegisterSingletonType(const QUrl &url, const char *uri, int versio
}
QQmlPrivate::RegisterCompositeSingletonType type = {
+ 0,
url,
uri,
- versionMajor,
- versionMinor,
+ QTypeRevision::fromVersion(versionMajor, versionMinor),
qmlName
};
@@ -749,59 +764,218 @@ inline int qmlRegisterType(const QUrl &url, const char *uri, int versionMajor, i
}
QQmlPrivate::RegisterCompositeType type = {
+ 0,
url,
uri,
- versionMajor,
- versionMinor,
+ QTypeRevision::fromVersion(versionMajor, versionMinor),
qmlName
};
return QQmlPrivate::qmlregister(QQmlPrivate::CompositeRegistration, &type);
}
-template<class T, class Resolved, class Extended, bool Singleton>
+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,
+ QTypeRevision::fromMajorVersion(versionMajor),
+ nullptr,
+ QMetaType::fromType<Container>(),
+ QMetaSequence::fromContainer<Container>(),
+ QTypeRevision::zero()
+ };
+
+ return QQmlPrivate::qmlregister(QQmlPrivate::SequentialContainerRegistration, &type);
+}
+
+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> {
- static void registerTypeAndRevisions(const char *uri, int versionMajor)
+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, &T::staticMetaObject);
+ uri, versionMajor, QQmlPrivate::StaticMetaObject<T>::staticMetaObject(),
+ qmlTypeIds, extension);
}
};
template<class T, class Resolved>
-struct QmlTypeAndRevisionsRegistration<T, Resolved, void, true> {
- static void registerTypeAndRevisions(const char *uri, int versionMajor)
+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);
+ }
+};
+
+template<class T, class Resolved, class Extended>
+struct QmlTypeAndRevisionsRegistration<T, Resolved, Extended, true, false, false, false> {
+ static void registerTypeAndRevisions(const char *uri, int versionMajor, QList<int> *qmlTypeIds,
+ const QMetaObject *extension)
{
- QQmlPrivate::qmlRegisterSingletonAndRevisions<Resolved>(
- uri, versionMajor, &T::staticMetaObject);
+#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<typename T = void, typename... Args>
-void qmlRegisterTypesAndRevisions(const char *uri, int versionMajor);
+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);
+ }
+};
+
+template<class T, class Resolved>
+struct QmlTypeAndRevisionsRegistration<T, Resolved, void, false, true, false, false> {
+ static void registerTypeAndRevisions(const char *uri, int versionMajor, QList<int> *qmlTypeIds,
+ const QMetaObject *)
+ {
+ const int id = qmlRegisterInterface<Resolved>(uri, versionMajor);
+ if (qmlTypeIds)
+ qmlTypeIds->append(id);
+ }
+};
-template<typename T, typename... Args>
-void qmlRegisterTypesAndRevisions(const char *uri, int versionMajor)
+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>
- ::registerTypeAndRevisions(uri, versionMajor);
- qmlRegisterTypesAndRevisions<Args...>(uri, versionMajor);
+ QQmlPrivate::QmlSingleton<T>::Value,
+ QQmlPrivate::QmlInterface<T>::Value,
+ QQmlPrivate::QmlSequence<T>::Value,
+ QQmlPrivate::QmlUncreatable<T>::Value || QQmlPrivate::QmlAnonymous<T>::Value>
+ ::registerTypeAndRevisions(uri, versionMajor, qmlTypeIds,
+ QQmlPrivate::QmlExtendedNamespace<T>::metaObject()), ...);
}
-template<>
-inline void qmlRegisterTypesAndRevisions<>(const char *, int) {}
+inline void qmlRegisterNamespaceAndRevisions(const QMetaObject *metaObject,
+ const char *uri, int versionMajor,
+ QList<int> *qmlTypeIds,
+ const QMetaObject *classInfoMetaObject,
+ const QMetaObject *extensionMetaObject)
+{
+ QQmlPrivate::RegisterTypeAndRevisions type = {
+ 3,
+ QMetaType(),
+ QMetaType(),
+ 0,
+ nullptr,
+ nullptr,
+ nullptr,
+
+ uri,
+ QTypeRevision::fromMajorVersion(versionMajor),
+
+ metaObject,
+ (classInfoMetaObject ? classInfoMetaObject : metaObject),
+
+ nullptr,
+ nullptr,
+
+ -1,
+ -1,
+ -1,
+
+ nullptr,
+ extensionMetaObject,
+
+ &qmlCreateCustomParser<void>,
+ 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
-QML_DECLARE_TYPE(QObject)
-Q_DECLARE_METATYPE(QVariant)
-
#endif // QQML_H
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 fc53be3e7b..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.flag2(); }
+ { return m_nextBinding.tag().testFlag(CanUseAccessor); }
+ void setCanUseAccessor(bool canUseAccessor)
+ { m_nextBinding.setTag(m_nextBinding.tag().setFlag(CanUseAccessor, canUseAccessor)); }
struct RefCount {
RefCount() {}
@@ -103,6 +81,20 @@ public:
};
RefCount ref;
+ enum TargetTag {
+ NoTargetTag = 0x0,
+ UpdatingBinding = 0x1,
+ BindingEnabled = 0x2
+ };
+ Q_DECLARE_FLAGS(TargetTags, TargetTag)
+
+ enum NextBindingTag {
+ NoBindingTag = 0x0,
+ AddedToObject = 0x1,
+ CanUseAccessor = 0x2
+ };
+ Q_DECLARE_FLAGS(NextBindingTags, NextBindingTag)
+
protected:
friend class QQmlData;
friend class QQmlValueTypeProxyBinding;
@@ -113,27 +105,35 @@ 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
- // flag1 is the updating flag
- // flag2 is the enabled flag
- QFlagPointer<QObject> m_target;
+ QTaggedPointer<QObject, TargetTags> m_target;
// Pointer to the next binding in the linked list of bindings.
- // flag1 is used for addedToObject
- // flag2 indicates if an accessor is can be used (i.e. there is no interceptor on the target)
- QFlagPointer<QQmlAbstractBinding> m_nextBinding;
+ QTaggedPointer<QQmlAbstractBinding, NextBindingTags> m_nextBinding;
};
+Q_DECLARE_OPERATORS_FOR_FLAGS(QQmlAbstractBinding::TargetTags)
+Q_DECLARE_OPERATORS_FOR_FLAGS(QQmlAbstractBinding::NextBindingTags)
+
void QQmlAbstractBinding::setAddedToObject(bool v)
{
- m_nextBinding.setFlagValue(v);
+ m_nextBinding.setTag(m_nextBinding.tag().setFlag(AddedToObject, v));
}
bool QQmlAbstractBinding::isAddedToObject() const
{
- return m_nextBinding.flag();
+ return m_nextBinding.tag().testFlag(AddedToObject);
}
QQmlAbstractBinding *QQmlAbstractBinding::nextBinding() const
@@ -150,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
new file mode 100644
index 0000000000..f432d2abae
--- /dev/null
+++ b/src/qml/qml/qqmlanybinding_p.h
@@ -0,0 +1,473 @@
+// 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
+
+//
+// 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 <qqmlproperty.h>
+#include <private/qqmlpropertybinding_p.h>
+#include <private/qqmlbinding_p.h>
+
+QT_BEGIN_NAMESPACE
+
+// Fully inline so that subsequent prop.isBindable check might get ellided.
+
+/*!
+ \internal
+ \brief QQmlAnyBinding is an abstraction over the various bindings in QML
+
+ QQmlAnyBinding can store both classical bindings (derived from QQmlAbstractBinding)
+ as well as new-style bindings (derived from QPropertyBindingPrivate). For both, it keeps
+ a strong reference to them, and knows how to delete them in case the reference count
+ becomes zero. In that sense it can be thought of as a union of QUntypedPropertyBinding
+ and QQmlAbstractBinding::Ptr.
+
+ It also offers methods to create bindings (from QV4::Function, from translation bindings
+ and from code strings). Moreover, it allows the retrieval, the removal and the
+ installation of bindings on a QQmlProperty.
+
+ Note that the class intentionally does not allow construction from QUntypedProperty and
+ QQmlAbstractBinding::Ptr. This is meant to catch code which doesn't handle bindable properties
+ yet when porting existing code.
+ */
+class QQmlAnyBinding {
+public:
+
+ 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.
+ The binding continues to be active and set on the property.
+ If there was no binding set, the returned QQmlAnyBinding is null.
+ */
+ static QQmlAnyBinding ofProperty(const QQmlProperty &prop) {
+ QQmlAnyBinding binding;
+ if (prop.isBindable()) {
+ QUntypedBindable bindable = prop.property().bindable(prop.object());
+ binding = bindable.binding();
+ } else {
+ binding = QQmlPropertyPrivate::binding(prop);
+ }
+ return binding;
+ }
+
+ /*!
+ \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.
+ */
+ static QQmlAnyBinding takeFrom(const QQmlProperty &prop)
+ {
+ QQmlAnyBinding binding;
+ if (prop.isBindable()) {
+ QUntypedBindable bindable = prop.property().bindable(prop.object());
+ binding = bindable.takeBinding();
+ } 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();
+ }
+ }
+ return binding;
+ }
+
+ /*!
+ \internal
+ Creates a binding for property \a prop from \a function.
+ \a obj is the scope object which shall be used for the function and \a scope 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 createFromFunction(const QQmlProperty &prop, QV4::Function *function,
+ QObject *obj, const QQmlRefPointer<QQmlContextData> &ctxt,
+ QV4::ExecutionContext *scope)
+ {
+ QQmlAnyBinding binding;
+ auto propPriv = QQmlPropertyPrivate::get(prop);
+ if (prop.isBindable()) {
+ auto index = QQmlPropertyIndex(propPriv->core.coreIndex(), -1);
+ binding = QQmlPropertyBinding::create(&propPriv->core,
+ function, obj, ctxt,
+ scope, prop.object(), index);
+ } else {
+ auto qmlBinding = QQmlBinding::create(&propPriv->core, function, obj, ctxt, scope);
+ qmlBinding->setTarget(prop);
+ binding = qmlBinding;
+ }
+ return binding;
+ }
+
+ /*!
+ \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)
+ {
+ if (prop.isBindable())
+ prop.property().bindable(prop.object()).takeBinding();
+ else
+ QQmlPropertyPrivate::removeBinding(prop);
+ }
+
+ /*!
+ \internal
+ Creates a binding for property \a prop from \a function.
+ \a obj is the scope object which shall be used for the function and \a scope 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 createFromCodeString(const QQmlProperty &prop, const QString& code, QObject *obj, const QQmlRefPointer<QQmlContextData> &ctxt, const QString &url, quint16 lineNumber) {
+ QQmlAnyBinding binding;
+ auto propPriv = QQmlPropertyPrivate::get(prop);
+ if (prop.isBindable()) {
+ auto index = QQmlPropertyIndex(propPriv->core.coreIndex(), -1);
+ binding = QQmlPropertyBinding::createFromCodeString(&propPriv->core,
+ code, obj, ctxt,
+ url, lineNumber,
+ prop.object(), index);
+ } else {
+ auto qmlBinding = QQmlBinding::create(&propPriv->core, code, obj, ctxt, url, lineNumber);
+ qmlBinding->setTarget(prop);
+ binding = qmlBinding;
+ }
+ return binding;
+ }
+
+ /*!
+ \internal
+ Creates a translattion binding for \a prop from \a compilationUnit and \a transationBinding.
+ \a obj is the context object, \a context the qml context.
+ */
+ static QQmlAnyBinding createTranslationBinding(const QQmlProperty &prop, const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit, const QV4::CompiledData::Binding *translationBinding, QObject *scopeObject=nullptr, QQmlRefPointer<QQmlContextData> context={})
+ {
+ QQmlAnyBinding binding;
+ auto propPriv = QQmlPropertyPrivate::get(prop);
+ if (prop.isBindable()) {
+ binding = QQmlTranslationPropertyBinding::create(&propPriv->core, compilationUnit, translationBinding);
+ } else {
+ auto qmlBinding = QQmlBinding::createTranslationBinding(compilationUnit, translationBinding, scopeObject, context);
+ binding = qmlBinding;
+ qmlBinding->setTarget(prop);
+ }
+ return binding;
+ }
+
+ /*!
+ \internal
+ Installs the binding referenced by this QQmlAnyBinding on the target.
+ If \a mode is set to RespectInterceptors, interceptors are honored, otherwise
+ writes and binding installation bypass them (the default).
+ Preconditions:
+ - The binding is non-null.
+ - If the binding is QQmlAbstractBinding derived, the target is non-bindable.
+ - If the binding is a QUntypedPropertyBinding, then the target is bindable.
+ */
+ enum InterceptorMode : bool {
+ IgnoreInterceptors,
+ RespectInterceptors
+ };
+
+ void installOn(const QQmlProperty &target, InterceptorMode mode = IgnoreInterceptors)
+ {
+ Q_ASSERT(!d.isNull());
+ if (isAbstractPropertyBinding()) {
+ auto abstractBinding = asAbstractBinding();
+ Q_ASSERT(abstractBinding->targetObject() == target.object() || QQmlPropertyPrivate::get(target)->core.isAlias());
+ Q_ASSERT(!target.isBindable());
+ if (mode == IgnoreInterceptors)
+ QQmlPropertyPrivate::setBinding(abstractBinding, QQmlPropertyPrivate::None, QQmlPropertyData::DontRemoveBinding | QQmlPropertyData::BypassInterceptor);
+ else
+ QQmlPropertyPrivate::setBinding(abstractBinding);
+ } else {
+ Q_ASSERT(target.isBindable());
+ 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)
+ {
+ clear();
+ return *this;
+ }
+
+ operator bool() const{
+ return !d.isNull();
+ }
+
+ /*!
+ \internal
+ Returns true if a binding derived from QQmlAbstractPropertyBinding is stored.
+ The binding migh still be null.
+ */
+ bool isAbstractPropertyBinding() const
+ { return d.isT1(); }
+
+ /*!
+ \internal
+ Returns true if a binding derived from QPropertyBindingPrivate is stored.
+ The binding might still be null.
+ */
+ bool isUntypedPropertyBinding() const
+ { return d.isT2(); }
+
+ /*!
+ \internal
+ Returns the stored QPropertyBindingPrivate as a QUntypedPropertyBinding.
+ If no such binding is currently stored, a null QUntypedPropertyBinding is returned.
+ */
+ QUntypedPropertyBinding asUntypedPropertyBinding() const
+ {
+ if (d.isT1() || d.isNull())
+ return {};
+ auto priv = d.asT2();
+ return QUntypedPropertyBinding {priv};
+ }
+
+ /*!
+ \internal
+ Returns the stored QQmlAbstractBinding.
+ If no such binding is currently stored, a null pointer is returned.
+ */
+ QQmlAbstractBinding *asAbstractBinding() const
+ {
+ if (d.isT2() || d.isNull())
+ return nullptr;
+ return d.asT1();
+ }
+
+ /*!
+ \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)
+ {
+ clear();
+ if (binding) {
+ d = binding;
+ binding->ref.ref();
+ }
+ return *this;
+ }
+
+ /*!
+ \internal
+ Stores the binding stored in \a binding and keeps a reference to it.
+ */
+ QQmlAnyBinding &operator=(const QQmlAbstractBinding::Ptr &binding)
+ {
+ clear();
+ if (binding) {
+ d = binding.data();
+ binding->ref.ref();
+ }
+ return *this;
+ }
+
+ /*!
+ \internal
+ Stores \a binding's binding, taking ownership from \a binding.
+ */
+ QQmlAnyBinding &operator=(QQmlAbstractBinding::Ptr &&binding)
+ {
+ clear();
+ if (binding) {
+ d = binding.take();
+ }
+ return *this;
+ }
+
+ /*!
+ \internal
+ Stores the binding stored in \a untypedBinding and keeps a reference to it.
+ */
+ QQmlAnyBinding &operator=(const QUntypedPropertyBinding &untypedBinding)
+ {
+ clear();
+ auto binding = QPropertyBindingPrivate::get(untypedBinding);
+ if (binding) {
+ d = binding;
+ binding->addRef();
+ }
+ return *this;
+ }
+
+ /*!
+ \internal
+ \overload
+ Stores the binding stored in \a untypedBinding, taking ownership from it.
+ */
+ QQmlAnyBinding &operator=(QUntypedPropertyBinding &&untypedBinding)
+ {
+ clear();
+ auto binding = QPropertyBindingPrivate::get(untypedBinding);
+ QPropertyBindingPrivatePtr ptr(binding);
+ if (binding) {
+ d = static_cast<QPropertyBindingPrivate *>(ptr.take());
+ }
+ return *this;
+ }
+
+ QQmlAnyBinding(QQmlAnyBinding &&other) noexcept
+ : d(std::exchange(other.d, QBiPointer<QQmlAbstractBinding, QPropertyBindingPrivate>()))
+ {}
+
+ 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) noexcept
+ {
+ clear();
+ if (auto abstractBinding = other.asAbstractBinding())
+ *this = abstractBinding;
+ else if (auto untypedBinding = other.asUntypedPropertyBinding(); !untypedBinding.isNull())
+ *this = untypedBinding;
+ return *this;
+ }
+
+ friend inline bool operator==(const QQmlAnyBinding &p1, const QQmlAnyBinding &p2)
+ {
+ return p1.d == p2.d;
+ }
+
+ friend inline bool operator!=(const QQmlAnyBinding &p1, const QQmlAnyBinding &p2)
+ {
+ return p1.d != p2.d;
+ }
+
+ ~QQmlAnyBinding() noexcept { clear(); }
+private:
+ void clear() noexcept {
+ if (d.isNull())
+ return;
+ if (d.isT1()) {
+ QQmlAbstractBinding *qqmlptr = d.asT1();
+ if (!qqmlptr->ref.deref())
+ delete qqmlptr;
+ } else if (d.isT2()) {
+ QPropertyBindingPrivate *priv = d.asT2();
+ if (!priv->deref())
+ QPropertyBindingPrivate::destroyAndFreeMemory(priv);
+ }
+ 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 adb036e2d0..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,23 +7,34 @@
#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
QQmlApplicationEnginePrivate::QQmlApplicationEnginePrivate(QQmlEngine *e)
: QQmlEnginePrivate(e)
{
+ uiLanguage = QLocale().bcp47Name();
}
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);
@@ -72,33 +47,41 @@ void QQmlApplicationEnginePrivate::init()
&QCoreApplication::quit, Qt::QueuedConnection);
q->connect(q, &QQmlApplicationEngine::exit, QCoreApplication::instance(),
&QCoreApplication::exit, Qt::QueuedConnection);
+ 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::location(QLibraryInfo::TranslationsPath), QLatin1String(".qm")))
+ if (qtTranslator->load(QLocale(), QLatin1String("qt"), QLatin1String("_"), QLibraryInfo::path(QLibraryInfo::TranslationsPath), QLatin1String(".qm")))
QCoreApplication::installTranslator(qtTranslator);
else
delete qtTranslator;
#endif
- new QQmlFileSelector(q,q);
+ auto *selector = new QQmlFileSelector(q,q);
+ selector->setExtraSelectors(extraFileSelectors);
QCoreApplication::instance()->setProperty("__qml_using_qqmlapplicationengine", QVariant(true));
}
-void QQmlApplicationEnginePrivate::loadTranslations(const QUrl &rootFile)
+void QQmlApplicationEnginePrivate::_q_loadTranslations()
{
#if QT_CONFIG(translation)
- if (rootFile.scheme() != QLatin1String("file") && rootFile.scheme() != QLatin1String("qrc"))
+ Q_Q(QQmlApplicationEngine);
+ if (translationsDirectory.isEmpty())
return;
- QFileInfo fi(QQmlFile::urlToLocalFileOrQrc(rootFile));
-
- Q_Q(QQmlApplicationEngine);
- QTranslator *translator = new QTranslator(q);
- if (translator->load(QLocale(), QLatin1String("qml"), QLatin1String("_"), fi.path() + QLatin1String("/i18n"), QLatin1String(".qm")))
- QCoreApplication::installTranslator(translator);
- else
- delete translator;
-#else
- Q_UNUSED(rootFile)
+ 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.get());
+ QCoreApplication::installTranslator(translator.get());
+ activeTranslator.swap(translator);
+ }
+ } else {
+ activeTranslator.reset();
+ }
+ q->retranslate();
#endif
}
@@ -106,7 +89,16 @@ void QQmlApplicationEnginePrivate::startLoad(const QUrl &url, const QByteArray &
{
Q_Q(QQmlApplicationEngine);
- loadTranslations(url); //Translations must be loaded before the QML file is
+ ensureInitialized();
+
+ if (url.scheme() == QLatin1String("file") || url.scheme() == QLatin1String("qrc")) {
+ QFileInfo fi(QQmlFile::urlToLocalFileOrQrc(url));
+ translationsDirectory = fi.path() + QLatin1String("/i18n");
+ } else {
+ translationsDirectory.clear();
+ }
+
+ _q_loadTranslations(); //Translations must be loaded before the QML file is
QQmlComponent *c = new QQmlComponent(q, q);
if (dataFlag)
@@ -114,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)
@@ -127,11 +148,21 @@ void QQmlApplicationEnginePrivate::finishLoad(QQmlComponent *c)
switch (c->status()) {
case QQmlComponent::Error:
qWarning() << "QQmlApplicationEngine failed to load component";
- qWarning() << qPrintable(c->errorString());
+ 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);
+
+ if (c->isError()) {
+ qWarning() << "QQmlApplicationEngine failed to create component";
+ warning(c->errors());
+ q->objectCreated(nullptr, c->url());
+ q->objectCreationFailed(c->url());
+ break;
+ }
+
objects << newObj;
QObject::connect(newObj, &QObject::destroyed, q, [&](QObject *obj) { objects.removeAll(obj); });
q->objectCreated(objects.constLast(), c->url());
@@ -145,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
@@ -181,6 +222,7 @@ void QQmlApplicationEnginePrivate::finishLoad(QQmlComponent *c)
\list
\li Translation files must have "qml_" prefix e.g. qml_ja_JP.qm.
\endlist
+ \li Translations are reloaded when the \c QJSEngine::uiLanguage / \c Qt.uiLanguage property is changed.
\li Automatically sets an incubation controller if the scene contains a QQuickWindow.
\li Automatically sets a \c QQmlFileSelector as the url interceptor, applying file selectors to all
QML files and assets.
@@ -204,14 +246,38 @@ 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.
*/
QQmlApplicationEngine::QQmlApplicationEngine(QObject *parent)
: QQmlEngine(*(new QQmlApplicationEnginePrivate(this)), parent)
{
- Q_D(QQmlApplicationEngine);
- d->init();
QJSEnginePrivate::addToDebugServer(this);
}
@@ -226,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
@@ -279,9 +359,50 @@ 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.
+ \code
+ QQmlApplicationEngine engine;
+
+ EventDatabase eventDatabase;
+ EventMonitor eventMonitor;
+
+ engine.setInitialProperties({
+ { "eventDatabase", QVariant::fromValue(&eventDatabase) },
+ { "eventMonitor", QVariant::fromValue(&eventMonitor) }
+ });
+ \endcode
\sa QQmlComponent::setInitialProperties
\sa QQmlApplicationEngine::load
@@ -295,6 +416,26 @@ void QQmlApplicationEngine::setInitialProperties(const QVariantMap &initialPrope
}
/*!
+ Sets the \a extraFileSelectors to be passed to the internal QQmlFileSelector
+ used for resolving URLs to local files. The \a extraFileSelectors are applied
+ when the first QML file is loaded. Setting them afterwards has no effect.
+
+ \sa QQmlFileSelector
+ \sa QFileSelector::setExtraSelectors
+ \since 6.0
+*/
+void QQmlApplicationEngine::setExtraFileSelectors(const QStringList &extraFileSelectors)
+{
+ Q_D(QQmlApplicationEngine);
+ if (d->isInitialized) {
+ qWarning() << "QQmlApplicationEngine::setExtraFileSelectors()"
+ << "called after loading QML files. This has no effect.";
+ } else {
+ d->extraFileSelectors = extraFileSelectors;
+ }
+}
+
+/*!
Loads the QML given in \a data. The object tree defined by \a data is
instantiated immediately.
@@ -323,17 +464,6 @@ QList<QObject *> QQmlApplicationEngine::rootObjects() const
return d->objects;
}
-#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
-/*!
- \overload
- \internal
-*/
-QList<QObject *> QQmlApplicationEngine::rootObjects()
-{
- return qAsConst(*this).rootObjects();
-}
-#endif // < Qt 6
-
QT_END_NAMESPACE
#include "moc_qqmlapplicationengine.cpp"
diff --git a/src/qml/qml/qqmlapplicationengine.h b/src/qml/qml/qqmlapplicationengine.h
index 2b4de91154..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,25 +19,28 @@ 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;
-#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
- QList<QObject*> rootObjects(); // ### Qt 6: remove
-#endif
QList<QObject*> rootObjects() const;
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)
+ Q_PRIVATE_SLOT(d_func(), void _q_loadTranslations())
Q_DECLARE_PRIVATE(QQmlApplicationEngine)
};
diff --git a/src/qml/qml/qqmlapplicationengine_p.h b/src/qml/qml/qqmlapplicationengine_p.h
index 1279e400e8..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,20 +24,29 @@
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 loadTranslations(const QUrl &rootFile);
+ 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)
+ std::unique_ptr<QTranslator> activeTranslator;
+#endif
+ bool isInitialized = false;
};
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlbinding.cpp b/src/qml/qml/qqmlbinding.cpp
index 112e5b558a..4dfee0a3c6 100644
--- a/src/qml/qml/qqmlbinding.cpp
+++ b/src/qml/qml/qqmlbinding.cpp
@@ -1,48 +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 "qqmlbinding_p.h"
-#include "qqml.h"
#include "qqmlcontext.h"
-#include "qqmlinfo.h"
#include "qqmldata_p.h"
+
+#include <private/qqmldebugserviceinterfaces_p.h>
+#include <private/qqmldebugconnector_p.h>
+
#include <private/qqmlprofiler_p.h>
#include <private/qqmlexpression_p.h>
#include <private/qqmlscriptstring_p.h>
@@ -53,6 +19,9 @@
#include <private/qv4qobjectwrapper_p.h>
#include <private/qv4variantobject_p.h>
#include <private/qv4jscall_p.h>
+#include <private/qjsvalue_p.h>
+
+#include <qtqml_tracepoints_p.h>
#include <QVariant>
#include <QtCore/qdebug.h>
@@ -60,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;
@@ -74,19 +46,19 @@ QQmlBinding *QQmlBinding::create(const QQmlPropertyData *property, const QQmlScr
QString url;
QV4::Function *runtimeFunction = nullptr;
- QQmlContextData *ctxtdata = QQmlContextData::get(scriptPrivate->context);
+ QQmlRefPointer<QQmlContextData> ctxtdata = QQmlContextData::get(scriptPrivate->context);
QQmlEnginePrivate *engine = QQmlEnginePrivate::get(scriptPrivate->context->engine());
- if (engine && ctxtdata && !ctxtdata->urlString().isEmpty() && ctxtdata->typeCompilationUnit) {
+ if (engine && ctxtdata && !ctxtdata->urlString().isEmpty() && ctxtdata->typeCompilationUnit()) {
url = ctxtdata->urlString();
if (scriptPrivate->bindingId != QQmlBinding::Invalid)
- runtimeFunction = ctxtdata->typeCompilationUnit->runtimeFunctions.at(scriptPrivate->bindingId);
+ runtimeFunction = ctxtdata->typeCompilationUnit()->runtimeFunctions.at(scriptPrivate->bindingId);
}
b->setNotifyOnValueChanged(true);
b->QQmlJavaScriptExpression::setContext(QQmlContextData::get(ctxt ? ctxt : scriptPrivate->context));
b->setScopeObject(obj ? obj : scriptPrivate->scope);
- QV4::ExecutionEngine *v4 = b->context()->engine->handle();
+ QV4::ExecutionEngine *v4 = b->engine()->handle();
if (runtimeFunction) {
QV4::Scope scope(v4);
QV4::Scoped<QV4::QmlContext> qmlContext(scope, QV4::QmlContext::create(v4->rootContext(), ctxtdata, b->scopeObject()));
@@ -114,10 +86,11 @@ void QQmlBinding::setSourceLocation(const QQmlSourceLocation &location)
}
-QQmlBinding *QQmlBinding::create(const QQmlPropertyData *property, const QString &str, QObject *obj,
- QQmlContextData *ctxt, const QString &url, quint16 lineNumber)
+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);
@@ -128,10 +101,18 @@ QQmlBinding *QQmlBinding::create(const QQmlPropertyData *property, const QString
return b;
}
-QQmlBinding *QQmlBinding::create(const QQmlPropertyData *property, QV4::Function *function,
- QObject *obj, QQmlContextData *ctxt, QV4::ExecutionContext *scope)
+QQmlBinding *QQmlBinding::create(
+ const QQmlPropertyData *property, QV4::Function *function, QObject *obj,
+ const QQmlRefPointer<QQmlContextData> &ctxt, QV4::ExecutionContext *scope)
+{
+ 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(QQmlEnginePrivate::get(ctxt), property);
+ QQmlBinding *b = newBinding(propertyType);
b->setNotifyOnValueChanged(true);
b->QQmlJavaScriptExpression::setContext(ctxt);
@@ -148,14 +129,9 @@ QQmlBinding::~QQmlBinding()
delete m_sourceLocation;
}
-void QQmlBinding::setNotifyOnValueChanged(bool v)
-{
- QQmlJavaScriptExpression::setNotifyOnValueChanged(v);
-}
-
void QQmlBinding::update(QQmlPropertyData::WriteFlags flags)
{
- if (!enabledFlag() || !context() || !context()->isValid())
+ if (!enabledFlag() || !hasValidContext())
return;
// Check that the target has not been deleted
@@ -164,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);
@@ -176,13 +152,15 @@ void QQmlBinding::update(QQmlPropertyData::WriteFlags flags)
DeleteWatcher watcher(this);
- QQmlEngine *engine = context()->engine;
- QV4::Scope scope(engine->handle());
+ QQmlEngine *qmlEngine = engine();
+ QV4::Scope scope(qmlEngine->handle());
if (canUseAccessor())
flags.setFlag(QQmlPropertyData::BypassInterceptor);
- QQmlBindingProfiler prof(QQmlEnginePrivate::get(engine)->profiler, function());
+ Q_TRACE_SCOPE(QQmlBinding, qmlEngine, function() ? function()->name()->toQString() : QString(),
+ sourceLocation().sourceFile, sourceLocation().line, sourceLocation().column);
+ QQmlBindingProfiler prof(QQmlEnginePrivate::get(qmlEngine)->profiler, function());
doUpdate(watcher, flags, scope);
if (!watcher.wasDeleted())
@@ -191,7 +169,7 @@ void QQmlBinding::update(QQmlPropertyData::WriteFlags flags)
QV4::ReturnedValue QQmlBinding::evaluate(bool *isUndefined)
{
- QV4::ExecutionEngine *v4 = context()->engine->handle();
+ QV4::ExecutionEngine *v4 = engine()->handle();
int argc = 0;
const QV4::Value *argv = nullptr;
const QV4::Value *thisObject = nullptr;
@@ -205,88 +183,51 @@ 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, &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);
+ const QQmlPropertyData *pd;
+ QQmlPropertyData vpd;
+ getPropertyData(&pd, &vpd);
+ Q_ASSERT(pd);
- if (!watcher.wasDeleted()) {
+ if (isUndefined || vpd.isValid())
+ return slowWrite(*pd, vpd, result, type, isUndefined, flags);
- if (error) {
- delayedError()->setErrorLocation(sourceLocation());
- delayedError()->setErrorObject(m_target.data());
- }
-
- if (hasError()) {
- if (!delayedError()->addError(ep)) ep->warning(this->error(context()->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);
int propertyType = StaticPropType; // If the binding is specialized to a type, the if and switch below will be constant-folded.
if (propertyType == QMetaType::UnknownType)
- propertyType = pd->propType();
+ propertyType = pd->propType().id();
if (Q_LIKELY(!isUndefined && !vpd.isValid())) {
switch (propertyType) {
@@ -299,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:
@@ -316,7 +257,7 @@ protected:
break;
default:
if (const QV4::QQmlValueTypeWrapper *vtw = result.as<const QV4::QQmlValueTypeWrapper>()) {
- if (vtw->d()->valueType()->metaType.id() == pd->propType()) {
+ if (vtw->d()->metaType() == pd->propType()) {
return vtw->write(m_target.data(), pd->coreIndex());
}
}
@@ -335,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
@@ -358,15 +299,15 @@ 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);
- if (pd->propType() == QMetaType::QString) {
+ if (pd->propType().id() == QMetaType::QString) {
doStore(result, pd, flags);
} else {
QV4::ScopedString value(scope, scope.engine->newString(result));
@@ -375,31 +316,163 @@ 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(const QQmlRefPointer<QV4::ExecutableCompilationUnit> &unit, const QV4::CompiledData::Binding *binding, QObject *obj, QQmlContextData *ctxt)
+QQmlBinding *QQmlBinding::createTranslationBinding(
+ const QQmlRefPointer<QV4::ExecutableCompilationUnit> &unit,
+ 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(
+ 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 *engine = context()->engine;
- QV4::ExecutionEngine *v4engine = engine->handle();
-
- int type = valueTypeData.isValid() ? valueTypeData.propType() : core.propType();
+ const QMetaType metaType = valueTypeData.isValid() ? valueTypeData.propType() : core.propType();
+ const int type = metaType.id();
QQmlJavaScriptExpression::DeleteWatcher watcher(this);
@@ -408,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() == qMetaTypeId<QList<QUrl> >()) {
- value = QQmlPropertyPrivate::resolvedUrlSequence(v4engine->toVariant(result, qMetaTypeId<QList<QUrl> >()), context());
- } 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()) {
@@ -431,28 +511,30 @@ 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."));
return false;
}
- QQmlPropertyPrivate::writeValueProperty(m_target.data(), core, valueTypeData, QVariant::fromValue(
- QJSValue(v4engine, result.asReturnedValue())),
- context(), flags);
+ QQmlPropertyPrivate::writeValueProperty(
+ m_target.data(), core, valueTypeData,
+ QVariant::fromValue(QJSValuePrivate::fromReturnedValue(result.asReturnedValue())),
+ context(), flags);
} else if (isUndefined) {
- const QLatin1String typeName(QMetaType::typeName(type)
- ? QMetaType::typeName(type)
- : "[unknown property type]");
+ const char *name = QMetaType(type).name();
+ const QLatin1String typeName(name ? name : "[unknown property type]");
delayedError()->setErrorDescription(QLatin1String("Unable to assign [undefined] to ")
+ typeName);
return false;
- } else if (const QV4::FunctionObject *f = result.as<QV4::FunctionObject>()) {
+ } else if (const QV4::FunctionObject *f = result.as<QV4::FunctionObject>();
+ f && !f->as<QV4::QQmlTypeWrapper>()) {
if (f->isBinding())
delayedError()->setErrorDescription(QLatin1String("Invalid use of Qt.binding() in a binding declaration."));
else
@@ -462,69 +544,61 @@ 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(engine), type);
- if (!propertyMetaObject.isNull())
- propertyType = propertyMetaObject.className();
- }
- } else if (userType != QVariant::Invalid) {
- if (userType == QMetaType::Nullptr || userType == QMetaType::VoidStar)
- valueType = "null";
- else
- valueType = QMetaType::typeName(userType);
+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::typeName(type);
- 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()
{
- QQmlEngine *engine = context()->engine;
- QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine);
+ QQmlEngine *qmlEngine = engine();
+ QQmlEnginePrivate *ep = QQmlEnginePrivate::get(qmlEngine);
ep->referenceScarceResources();
bool isUndefined = false;
- QV4::Scope scope(engine->handle());
+ QV4::Scope scope(qmlEngine->handle());
QV4::ScopedValue result(scope, QQmlJavaScriptExpression::evaluate(&isUndefined));
ep->dereferenceScarceResources();
- return scope.engine->toVariant(result, qMetaTypeId<QList<QObject*> >());
-}
-
-QString QQmlBinding::expressionIdentifier() const
-{
- if (auto f = function()) {
- QString url = f->sourceFile();
- uint lineNumber = f->compiledFunction->location.line;
- uint columnNumber = f->compiledFunction->location.column;
- return url + QString::asprintf(":%u:%u", lineNumber, columnNumber);
- }
-
- return QStringLiteral("[native code]");
+ return QV4::ExecutionEngine::toVariant(result, QMetaType::fromType<QList<QObject*> >());
}
void QQmlBinding::expressionChanged()
@@ -542,12 +616,7 @@ void QQmlBinding::setEnabled(bool e, QQmlPropertyData::WriteFlags flags)
const bool wasEnabled = enabledFlag();
setEnabledFlag(e);
setNotifyOnValueChanged(e);
-
- m_nextBinding.setFlag2(); // Always use accessors, only not when:
- if (auto interceptorMetaObject = QQmlInterceptorMetaObject::get(targetObject())) {
- if (!m_targetIndex.isValid() || interceptorMetaObject->intercepts(m_targetIndex))
- m_nextBinding.clearFlag2();
- }
+ updateCanUseAccessor();
if (e && !wasEnabled)
update(flags);
@@ -558,85 +627,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, true);
- if (!data->propertyCache) {
- data->propertyCache = QQmlEnginePrivate::get(context()->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, false);
- Q_ASSERT(data);
-
- if (Q_UNLIKELY(!data->propertyCache)) {
- data->propertyCache = QQmlEnginePrivate::get(context()->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 = QQmlValueTypeFactory::metaObjectForMetaType((*propertyData)->propType());
- Q_ASSERT(valueTypeMetaObject);
- QMetaProperty vtProp = valueTypeMetaObject->property(m_targetIndex.valueTypeIndex());
- valueTypeData->setFlags(QQmlPropertyData::flagsForProperty(vtProp));
- valueTypeData->setPropType(vtProp.userType());
- valueTypeData->setCoreIndex(m_targetIndex.valueTypeIndex());
- }
-}
-
QVector<QQmlProperty> QQmlBinding::dependencies() const
{
QVector<QQmlProperty> dependencies;
@@ -658,33 +648,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();
+ 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()))
@@ -706,9 +795,8 @@ protected:
resultMo = resultObject->metaObject();
}
} else if (auto variant = result.as<QV4::VariantObject>()) {
- QVariant value = variant->d()->data();
- QQmlEnginePrivate *ep = QQmlEnginePrivate::get(context());
- resultMo = QQmlPropertyPrivate::rawMetaObjectForType(ep, 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());
@@ -716,7 +804,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)) {
@@ -725,23 +824,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());
-
- const int type = (property && property->isFullyResolved()) ? property->propType() : 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 7f96b4df9f..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;
@@ -76,19 +37,36 @@ public:
typedef QExplicitlySharedDataPointer<QQmlBinding> Ptr;
static QQmlBinding *create(const QQmlPropertyData *, const QQmlScriptString &, QObject *, QQmlContext *);
- static QQmlBinding *create(const QQmlPropertyData *, const QString &, QObject *, QQmlContextData *,
- const QString &url = QString(), quint16 lineNumber = 0);
- static QQmlBinding *create(const QQmlPropertyData *property, QV4::Function *function,
- QObject *obj, QQmlContextData *ctxt, QV4::ExecutionContext *scope);
- static QQmlBinding *createTranslationBinding(const QQmlRefPointer<QV4::ExecutableCompilationUnit> &unit, const QV4::CompiledData::Binding *binding,
- QObject *obj, QQmlContextData *ctxt);
- ~QQmlBinding() override;
- void setTarget(const QQmlProperty &);
- bool setTarget(QObject *, const QQmlPropertyData &, const QQmlPropertyData *valueType);
+ static QQmlBinding *create(
+ const QQmlPropertyData *, const QString &, QObject *,
+ const QQmlRefPointer<QQmlContextData> &, const QString &url = QString(),
+ quint16 lineNumber = 0);
+
+ static QQmlBinding *create(
+ 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);
+
+ static QQmlBinding *
+ createTranslationBinding(const QQmlRefPointer<QV4::ExecutableCompilationUnit> &unit,
+ const QQmlRefPointer<QQmlContextData> &ctxt,
+ const QString &propertyName, const QQmlTranslation &translationData,
+ const QQmlSourceLocation &location, QObject *obj);
- void setNotifyOnValueChanged(bool);
+ 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;
@@ -101,8 +79,11 @@ public:
};
QVariant evaluate();
+ bool evaluate(void *result, QMetaType type)
+ {
+ return QQmlJavaScriptExpression::evaluate(&result, &type, 0);
+ }
- QString expressionIdentifier() const override;
void expressionChanged() override;
QQmlSourceLocation sourceLocation() const override;
@@ -110,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
@@ -119,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.flag();
-}
-
-void QQmlBinding::setUpdatingFlag(bool v)
-{
- m_target.setFlagValue(v);
-}
-
-bool QQmlBinding::enabledFlag() const
-{
- return m_target.flag2();
-}
-
-void QQmlBinding::setEnabledFlag(bool v)
-{
- m_target.setFlag2Value(v);
-}
-
QT_END_NAMESPACE
Q_DECLARE_METATYPE(QQmlBinding*)
diff --git a/src/qml/qml/qqmlboundsignal.cpp b/src/qml/qml/qqmlboundsignal.cpp
index ff01e737ca..0bac2f45a2 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>
@@ -60,14 +20,17 @@
#include <QtCore/qdebug.h>
+#include <qtqml_tracepoints_p.h>
QT_BEGIN_NAMESPACE
-QQmlBoundSignalExpression::QQmlBoundSignalExpression(QObject *target, int index,
- QQmlContextData *ctxt, QObject *scope, const QString &expression,
- const QString &fileName, quint16 line, quint16 column,
- const QString &handlerName,
- const QString &parameterString)
+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)
: QQmlJavaScriptExpression(),
m_index(index),
m_target(target)
@@ -99,13 +62,14 @@ QQmlBoundSignalExpression::QQmlBoundSignalExpression(QObject *target, int index,
function += QLatin1String(") { ") + expression + QLatin1String(" })");
QV4::Scope valueScope(v4);
- QV4::ScopedFunctionObject f(valueScope, evalFunction(context(), scopeObject(), function, fileName, line));
+ QV4::Scoped<QV4::JavaScriptFunctionObject> f(
+ valueScope, evalFunction(context(), scopeObject(), function, fileName, line));
QV4::ScopedContext context(valueScope, f->scope());
setupFunction(context, f->function());
}
-QQmlBoundSignalExpression::QQmlBoundSignalExpression(QObject *target, int index, QQmlContextData *ctxt, QObject *scopeObject,
- QV4::Function *function, QV4::ExecutionContext *scope)
+QQmlBoundSignalExpression::QQmlBoundSignalExpression(const QObject *target, int index, const QQmlRefPointer<QQmlContextData> &ctxt,
+ QObject *scopeObject, QV4::Function *function, QV4::ExecutionContext *scope)
: QQmlJavaScriptExpression(),
m_index(index),
m_target(target)
@@ -113,14 +77,9 @@ QQmlBoundSignalExpression::QQmlBoundSignalExpression(QObject *target, int index,
// It's important to call init first, because m_index gets remapped in case of cloned signals.
init(ctxt, scopeObject);
- QV4::ExecutionEngine *engine = ctxt->engine->handle();
+ 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;
@@ -137,10 +96,32 @@ QQmlBoundSignalExpression::QQmlBoundSignalExpression(QObject *target, int index,
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::Scoped<QV4::JavaScriptFunctionObject> 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(QQmlContextData *ctxt, QObject *scope)
+void QQmlBoundSignalExpression::init(const QQmlRefPointer<QQmlContextData> &ctxt, QObject *scope)
{
setNotifyOnValueChanged(false);
setContext(ctxt);
@@ -172,79 +153,53 @@ 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 (context() && engine());
-
if (!expressionFunctionValid())
return;
QQmlEngine *qmlengine = engine();
+
+ // If there is no engine, we have no way to evaluate anything.
+ // This can happen on destruction.
+ if (!qmlengine)
+ return;
+
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();
- int *argsTypes = QQmlMetaObject(m_target).methodParameterTypes(methodIndex, &storage, nullptr);
- int argCount = argsTypes ? *argsTypes : 0;
-
- QV4::JSCallData jsCall(scope, argCount);
- for (int ii = 0; ii < argCount; ++ii) {
- int type = argsTypes[ii + 1];
- //### ideally we would use metaTypeToJS, however it currently gives different results
- // for several cases (such as QVariant type and QObject-derived types)
- //args[ii] = engine->metaTypeToJS(type, a[ii + 1]);
- if (type == qMetaTypeId<QJSValue>()) {
- if (QV4::Value *v4Value = QJSValuePrivate::valueForData(reinterpret_cast<QJSValue *>(a[ii + 1]), &jsCall->args[ii]))
- jsCall->args[ii] = *v4Value;
- else
- jsCall->args[ii] = QV4::Encode::undefined();
- } else if (type == QMetaType::QVariant) {
- jsCall->args[ii] = scope.engine->fromVariant(*((QVariant *)a[ii + 1]));
- } else if (type == QMetaType::Int) {
- //### optimization. Can go away if we switch to metaTypeToJS, or be expanded otherwise
- jsCall->args[ii] = QV4::Value::fromInt32(*reinterpret_cast<const int*>(a[ii + 1]));
- } else if (ep->isQObject(type)) {
- if (!*reinterpret_cast<void* const *>(a[ii + 1]))
- jsCall->args[ii] = QV4::Value::nullValue();
+ 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
- jsCall->args[ii] = QV4::QObjectWrapper::wrap(v4, *reinterpret_cast<QObject* const *>(a[ii + 1]));
- } else {
- jsCall->args[ii] = scope.engine->fromVariant(QVariant(type, a[ii + 1]));
+ storage.append(type);
}
- }
-
- 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 (context() && engine());
-
- if (!expressionFunctionValid())
- return;
- QQmlEngine *qmlengine = engine();
- QQmlEnginePrivate *ep = QQmlEnginePrivate::get(qmlengine);
- QV4::Scope scope(qmlengine->handle());
-
- 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]);
+ QQmlJavaScriptExpression::evaluate(a, storage.constData(), argCount);
+ } else {
+ void *ignoredResult = nullptr;
+ QMetaType invalidType;
+ QQmlJavaScriptExpression::evaluate(&ignoredResult, &invalidType, 0);
}
- QQmlJavaScriptExpression::evaluate(jsCall.callData(), nullptr);
-
ep->dereferenceScarceResources(); // "release" scarce resources if top-level expression evaluation is complete.
}
@@ -259,7 +214,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);
@@ -301,13 +256,12 @@ void QQmlBoundSignal::removeFromObject()
}
}
-
/*!
Returns the signal expression.
*/
QQmlBoundSignalExpression *QQmlBoundSignal::expression() const
{
- return m_expression;
+ return m_expression.data();
}
/*!
@@ -317,7 +271,7 @@ QQmlBoundSignalExpression *QQmlBoundSignal::expression() const
*/
void QQmlBoundSignal::takeExpression(QQmlBoundSignalExpression *e)
{
- m_expression.take(e);
+ m_expression.adopt(e);
if (m_expression)
m_expression->setNotifyOnValueChanged(false);
}
@@ -352,7 +306,12 @@ void QQmlBoundSignal_callback(QQmlNotifierEndpoint *e, void **a)
QQmlEngine *engine;
if (s->m_expression && (engine = s->m_expression->engine())) {
- QQmlHandlingSignalProfiler prof(QQmlEnginePrivate::get(engine)->profiler, s->m_expression);
+ Q_TRACE_SCOPE(QQmlHandlingSignal, engine,
+ s->m_expression->function() ? s->m_expression->function()->name()->toQString() : QString(),
+ s->m_expression->sourceLocation().sourceFile, s->m_expression->sourceLocation().line,
+ s->m_expression->sourceLocation().column);
+ QQmlHandlingSignalProfiler prof(QQmlEnginePrivate::get(engine)->profiler,
+ s->m_expression.data());
s->m_expression->evaluate(a);
if (s->m_expression && s->m_expression->hasError()) {
QQmlEnginePrivate::warning(engine, s->m_expression->error(engine));
@@ -362,48 +321,13 @@ void QQmlBoundSignal_callback(QQmlNotifierEndpoint *e, void **a)
////////////////////////////////////////////////////////////////////////
-QQmlBoundSignalExpressionPointer::QQmlBoundSignalExpressionPointer(QQmlBoundSignalExpression *o)
-: o(o)
-{
- if (o) o->addref();
-}
-
-QQmlBoundSignalExpressionPointer::QQmlBoundSignalExpressionPointer(const QQmlBoundSignalExpressionPointer &other)
-: o(other.o)
-{
- if (o) o->addref();
-}
-
-QQmlBoundSignalExpressionPointer::~QQmlBoundSignalExpressionPointer()
-{
- if (o) o->release();
-}
-
-QQmlBoundSignalExpressionPointer &QQmlBoundSignalExpressionPointer::operator=(const QQmlBoundSignalExpressionPointer &other)
-{
- if (other.o) other.o->addref();
- if (o) o->release();
- o = other.o;
- return *this;
-}
-
-QQmlBoundSignalExpressionPointer &QQmlBoundSignalExpressionPointer::operator=(QQmlBoundSignalExpression *other)
-{
- if (other) other->addref();
- if (o) o->release();
- o = other;
- return *this;
-}
-
-/*!
-Takes ownership of \a other. take() does *not* add a reference, as it assumes ownership
-of the callers reference of other.
-*/
-QQmlBoundSignalExpressionPointer &QQmlBoundSignalExpressionPointer::take(QQmlBoundSignalExpression *other)
+QQmlPropertyObserver::QQmlPropertyObserver(QQmlBoundSignalExpression *expr)
+ : QPropertyObserver([](QPropertyObserver *self, QUntypedPropertyData *) {
+ auto This = static_cast<QQmlPropertyObserver*>(self);
+ This->expression->evaluate(nullptr);
+ })
{
- if (o) o->release();
- o = other;
- return *this;
+ expression.adopt(expr);
}
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlboundsignal_p.h b/src/qml/qml/qqmlboundsignal_p.h
index d1ec67210e..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
@@ -54,27 +18,26 @@
#include <QtCore/qmetaobject.h>
#include <private/qqmljavascriptexpression_p.h>
-#include <private/qqmlboundsignalexpressionpointer_p.h>
#include <private/qqmlnotifier_p.h>
-#include <private/qflagpointer_p.h>
#include <private/qqmlrefcount_p.h>
-#include <private/qqmlglobal_p.h>
-#include <private/qbitfield_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(QObject *target, int index,
- QQmlContextData *ctxt, QObject *scope, const QString &expression,
- const QString &fileName, quint16 line, quint16 column,
- const QString &handlerName = QString(),
- const QString &parameterString = QString());
+ 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 = QString(), const QString &parameterString = QString());
- QQmlBoundSignalExpression(QObject *target, int index,
- QQmlContextData *ctxt, QObject *scopeObject, QV4::Function *function,
- QV4::ExecutionContext *scope = nullptr);
+ QQmlBoundSignalExpression(
+ const QObject *target, int index, const QQmlRefPointer<QQmlContextData> &ctxt,
+ QObject *scopeObject, QV4::Function *function, QV4::ExecutionContext *scope = nullptr);
// inherited from QQmlJavaScriptExpression.
QString expressionIdentifier() const override;
@@ -82,25 +45,24 @@ public:
// evaluation of a bound signal expression doesn't return any value
void evaluate(void **a);
- void evaluate(const QList<QVariant> &args);
- QString expression() const;
- QObject *target() const { return m_target; }
+ bool mustCaptureBindableProperty() const final {return true;}
- QQmlEngine *engine() const { return context() ? context()->engine : nullptr; }
+ QString expression() const;
+ const QObject *target() const { return m_target; }
private:
~QQmlBoundSignalExpression() override;
- void init(QQmlContextData *ctxt, QObject *scope);
+ void init(const QQmlRefPointer<QQmlContextData> &ctxt, QObject *scope);
bool expressionFunctionValid() const { return function() != nullptr; }
int m_index;
- QObject *m_target;
+ 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);
@@ -126,7 +88,16 @@ private:
bool m_enabled;
- QQmlBoundSignalExpressionPointer m_expression;
+ QQmlRefPointer<QQmlBoundSignalExpression> m_expression;
+};
+
+class QQmlPropertyObserver : public QPropertyObserver
+{
+public:
+ QQmlPropertyObserver(QQmlBoundSignalExpression *expr);
+
+private:
+ QQmlRefPointer<QQmlBoundSignalExpression> expression;
};
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlboundsignalexpressionpointer_p.h b/src/qml/qml/qqmlboundsignalexpressionpointer_p.h
deleted file mode 100644
index eabe6666b4..0000000000
--- a/src/qml/qml/qqmlboundsignalexpressionpointer_p.h
+++ /dev/null
@@ -1,81 +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 QQMLBOUNDSIGNALEXPRESSIONPOINTER_P_H
-#define QQMLBOUNDSIGNALEXPRESSIONPOINTER_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/qtqmlglobal.h>
-
-QT_BEGIN_NAMESPACE
-
-class QQmlBoundSignalExpression;
-class Q_QML_PRIVATE_EXPORT QQmlBoundSignalExpressionPointer
-{
-public:
- inline QQmlBoundSignalExpressionPointer() {}
- QQmlBoundSignalExpressionPointer(QQmlBoundSignalExpression *);
- QQmlBoundSignalExpressionPointer(const QQmlBoundSignalExpressionPointer &);
- ~QQmlBoundSignalExpressionPointer();
-
- QQmlBoundSignalExpressionPointer &operator=(const QQmlBoundSignalExpressionPointer &o);
- QQmlBoundSignalExpressionPointer &operator=(QQmlBoundSignalExpression *);
-
- inline QQmlBoundSignalExpression* operator->() const { return o; }
- inline QQmlBoundSignalExpression& operator*() const { return *o; }
- inline operator QQmlBoundSignalExpression*() const { return o; }
-
- QQmlBoundSignalExpressionPointer &take(QQmlBoundSignalExpression *);
-
-private:
- QQmlBoundSignalExpression *o = nullptr;
-};
-
-QT_END_NAMESPACE
-
-#endif // QQMLBOUNDSIGNALEXPRESSIONPOINTER_P_H
diff --git a/src/qml/qml/v8/qqmlbuiltinfunctions.cpp b/src/qml/qml/qqmlbuiltinfunctions.cpp
index d634a48443..bc5d87881b 100644
--- a/src/qml/qml/v8/qqmlbuiltinfunctions.cpp
+++ b/src/qml/qml/qqmlbuiltinfunctions.cpp
@@ -1,245 +1,327 @@
-/****************************************************************************
-**
-** 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"
-#include <QtQml/qqmlcomponent.h>
-#include <QtQml/qqmlfile.h>
-#include <private/qqmlengine_p.h>
#include <private/qqmlcomponent_p.h>
-#include <private/qqmlloggingcategory_p.h>
-#include <private/qqmlstringconverters_p.h>
-#if QT_CONFIG(qml_locale)
-#include <private/qqmllocale_p.h>
-#endif
-#include <private/qqmldelayedcallqueue_p.h>
-#include <QFileInfo>
-
#include <private/qqmldebugconnector_p.h>
#include <private/qqmldebugserviceinterfaces_p.h>
-#include <private/qqmlglobal_p.h>
-
+#include <private/qqmldelayedcallqueue_p.h>
+#include <private/qqmlengine_p.h>
+#include <private/qqmlloggingcategorybase_p.h>
#include <private/qqmlplatform_p.h>
+#include <private/qqmlstringconverters_p.h>
+#include <private/qv4dateobject_p.h>
#include <private/qv4engine_p.h>
#include <private/qv4functionobject_p.h>
#include <private/qv4include_p.h>
-#include <private/qv4context_p.h>
-#include <private/qv4stringobject_p.h>
-#include <private/qv4dateobject_p.h>
#include <private/qv4mm_p.h>
-#include <private/qv4jsonobject_p.h>
-#include <private/qv4objectproto_p.h>
#include <private/qv4qobjectwrapper_p.h>
#include <private/qv4stackframe_p.h>
-#include <QtCore/qstring.h>
-#include <QtCore/qdatetime.h>
+#include <QtQml/qqmlfile.h>
+
+#include <QtCore/qcoreapplication.h>
#include <QtCore/qcryptographichash.h>
+#include <QtCore/qdatetime.h>
+#include <QtCore/qfileinfo.h>
+#include <QtCore/qloggingcategory.h>
+#include <QtCore/qpoint.h>
#include <QtCore/qrect.h>
#include <QtCore/qsize.h>
-#include <QtCore/qpoint.h>
+#include <QtCore/qstring.h>
#include <QtCore/qurl.h>
-#include <QtCore/qfile.h>
-#include <QtCore/qcoreapplication.h>
-#include <QtCore/qloggingcategory.h>
-
-#include <QDebug>
QT_BEGIN_NAMESPACE
-using namespace QV4;
+Q_LOGGING_CATEGORY(lcRootProperties, "qt.qml.rootObjectProperties");
+Q_LOGGING_CATEGORY(lcQml, "qml");
+Q_LOGGING_CATEGORY(lcJs, "js");
-DEFINE_OBJECT_VTABLE(QtObject);
+using namespace QV4;
#define THROW_TYPE_ERROR_WITH_MESSAGE(msg) \
do { \
return scope.engine->throwTypeError(QString::fromUtf8(msg)); \
} while (false)
-struct StaticQtMetaObject : public QObject
-{
- static const QMetaObject *get()
- { return &staticQtMetaObject; }
-};
+/*!
+\qmltype Qt
+\inqmlmodule QtQml
+//! \instantiates QQmlEnginePrivate
+\ingroup qml-utility-elements
+\keyword QmlGlobalQtObject
+\brief Provides a global object with useful enums and functions from Qt.
-void Heap::QtObject::init(QQmlEngine *qmlEngine)
-{
- Heap::Object::init();
- enumeratorIterator = 0;
- keyIterator = 0;
- Scope scope(internalClass->engine);
- ScopedObject o(scope, this);
+\c Qt is a singleton type that provides utility functions, properties, and
+enums. Here is an example showing how to use this type:
- {
- ScopedString str(scope);
- ScopedValue v(scope);
- o->put((str = scope.engine->newString(QStringLiteral("Asynchronous"))), (v = QV4::Value::fromInt32(0)));
- o->put((str = scope.engine->newString(QStringLiteral("Synchronous"))), (v = QV4::Value::fromInt32(1)));
- }
+\qml
+import QtQuick 2.0
- o->defineDefaultProperty(QStringLiteral("include"), QV4Include::method_include);
- o->defineDefaultProperty(QStringLiteral("isQtObject"), QV4::QtObject::method_isQtObject);
- o->defineDefaultProperty(QStringLiteral("rgba"), QV4::QtObject::method_rgba);
- o->defineDefaultProperty(QStringLiteral("hsla"), QV4::QtObject::method_hsla);
- o->defineDefaultProperty(QStringLiteral("hsva"), QV4::QtObject::method_hsva);
- o->defineDefaultProperty(QStringLiteral("colorEqual"), QV4::QtObject::method_colorEqual);
- o->defineDefaultProperty(QStringLiteral("rect"), QV4::QtObject::method_rect);
- o->defineDefaultProperty(QStringLiteral("point"), QV4::QtObject::method_point);
- o->defineDefaultProperty(QStringLiteral("size"), QV4::QtObject::method_size);
- o->defineDefaultProperty(QStringLiteral("font"), QV4::QtObject::method_font);
-
- o->defineDefaultProperty(QStringLiteral("vector2d"), QV4::QtObject::method_vector2d);
- o->defineDefaultProperty(QStringLiteral("vector3d"), QV4::QtObject::method_vector3d);
- o->defineDefaultProperty(QStringLiteral("vector4d"), QV4::QtObject::method_vector4d);
- o->defineDefaultProperty(QStringLiteral("quaternion"), QV4::QtObject::method_quaternion);
- o->defineDefaultProperty(QStringLiteral("matrix4x4"), QV4::QtObject::method_matrix4x4);
-
- o->defineDefaultProperty(QStringLiteral("formatDate"), QV4::QtObject::method_formatDate);
- o->defineDefaultProperty(QStringLiteral("formatTime"), QV4::QtObject::method_formatTime);
- o->defineDefaultProperty(QStringLiteral("formatDateTime"), QV4::QtObject::method_formatDateTime);
-
- o->defineDefaultProperty(QStringLiteral("openUrlExternally"), QV4::QtObject::method_openUrlExternally);
- o->defineDefaultProperty(QStringLiteral("fontFamilies"), QV4::QtObject::method_fontFamilies);
- o->defineDefaultProperty(QStringLiteral("md5"), QV4::QtObject::method_md5);
- o->defineDefaultProperty(QStringLiteral("btoa"), QV4::QtObject::method_btoa);
- o->defineDefaultProperty(QStringLiteral("atob"), QV4::QtObject::method_atob);
- o->defineDefaultProperty(QStringLiteral("resolvedUrl"), QV4::QtObject::method_resolvedUrl);
-#if QT_CONFIG(qml_locale)
- o->defineDefaultProperty(QStringLiteral("locale"), QV4::QtObject::method_locale);
-#endif
- o->defineDefaultProperty(QStringLiteral("binding"), QV4::QtObject::method_binding);
-
- if (qmlEngine) {
- o->defineDefaultProperty(QStringLiteral("lighter"), QV4::QtObject::method_lighter);
- o->defineDefaultProperty(QStringLiteral("darker"), QV4::QtObject::method_darker);
- o->defineDefaultProperty(QStringLiteral("tint"), QV4::QtObject::method_tint);
- o->defineDefaultProperty(QStringLiteral("quit"), QV4::QtObject::method_quit);
- o->defineDefaultProperty(QStringLiteral("exit"), QV4::QtObject::method_exit);
- o->defineDefaultProperty(QStringLiteral("createQmlObject"), QV4::QtObject::method_createQmlObject);
- o->defineDefaultProperty(QStringLiteral("createComponent"), QV4::QtObject::method_createComponent);
- }
+Text {
+ color: Qt.rgba(1, 0, 0, 1)
+ text: Qt.md5("hello, world")
+}
+\endqml
- o->defineAccessorProperty(QStringLiteral("platform"), QV4::QtObject::method_get_platform, nullptr);
- o->defineAccessorProperty(QStringLiteral("application"), QV4::QtObject::method_get_application, nullptr);
- o->defineAccessorProperty(QStringLiteral("inputMethod"), QV4::QtObject::method_get_inputMethod, nullptr);
- o->defineAccessorProperty(QStringLiteral("styleHints"), QV4::QtObject::method_get_styleHints, nullptr);
- o->defineDefaultProperty(QStringLiteral("callLater"), QV4::QtObject::method_callLater);
-}
+\section1 Enums
-void QtObject::addAll()
-{
- bool dummy = false;
- findAndAdd(nullptr, dummy);
-}
+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.
-ReturnedValue QtObject::findAndAdd(const QString *name, bool &foundProperty) const
-{
- Scope scope(engine());
- ScopedObject o(scope, this);
- ScopedString key(scope);
- ScopedValue value(scope);
- const QMetaObject *qtMetaObject = StaticQtMetaObject::get();
- for (int enumCount = qtMetaObject->enumeratorCount(); d()->enumeratorIterator < enumCount;
- ++d()->enumeratorIterator) {
- QMetaEnum enumerator = qtMetaObject->enumerator(d()->enumeratorIterator);
- for (int keyCount = enumerator.keyCount(); d()->keyIterator < keyCount; ++d()->keyIterator) {
- key = scope.engine->newString(QString::fromUtf8(enumerator.key(d()->keyIterator)));
- value = QV4::Value::fromInt32(enumerator.value(d()->keyIterator));
- o->put(key, value);
- if (name && key->toQString() == *name) {
- ++d()->keyIterator;
- foundProperty = true;
- return value->asReturnedValue();
- }
- }
- d()->keyIterator = 0;
- }
- d()->enumeratorIterator = Heap::QtObject::Finished;
- foundProperty = false;
- return Encode::undefined();
-}
+\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 "visionos" - visionOS
+ \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
+
+ \note The property's value on \macos is "osx", regardless of Apple naming convention.
+ The returned value will be updated to "macos" for Qt 7.
+
+ \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
+*/
-ReturnedValue QtObject::virtualGet(const Managed *m, PropertyKey id, const Value *receiver, bool *hasProperty)
+/*!
+ \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.
+
+\warning Using this function is strict mode does not actually put identifier into the
+current context.
+*/
+// Qt.include() is implemented in qv4include.cpp
+
+QtObject::QtObject(ExecutionEngine *engine)
+ : m_engine(engine)
{
- bool hasProp = false;
- if (hasProperty == nullptr) {
- hasProperty = &hasProp;
- }
+}
- ReturnedValue ret = QV4::Object::virtualGet(m, id, receiver, hasProperty);
- if (*hasProperty) {
- return ret;
- }
+QtObject::Contexts QtObject::getContexts() const
+{
+ QQmlEngine *engine = qmlEngine();
+ if (!engine)
+ return {};
- auto that = static_cast<const QtObject*>(m);
- if (!that->d()->isComplete()) {
- const QString key = id.toQString();
- ret = that->findAndAdd(&key, *hasProperty);
- }
+ QQmlRefPointer<QQmlContextData> context = v4Engine()->callingQmlContext();
+ if (!context)
+ context = QQmlContextData::get(QQmlEnginePrivate::get(engine)->rootContext);
- return ret;
+ Q_ASSERT(context);
+ QQmlRefPointer<QQmlContextData> effectiveContext
+ = context->isPragmaLibraryContext() ? nullptr : context;
+ return {context, effectiveContext};
}
-OwnPropertyKeyIterator *QtObject::virtualOwnPropertyKeys(const Object *m, Value *target)
+QtObject *QtObject::create(QQmlEngine *, QJSEngine *jsEngine)
{
- auto that = static_cast<const QtObject*>(m);
- if (!that->d()->isComplete())
- const_cast<QtObject *>(that)->addAll();
+ QV4::ExecutionEngine *v4 = jsEngine->handle();
+ QV4::Scope scope(v4);
+ ScopedObject globalObject(scope, v4->globalObject);
+ ScopedString qtName(scope, v4->newString(QStringLiteral("Qt")));
+ QV4::ScopedValue result(scope, globalObject->get(qtName->toPropertyKey()));
+ return qobject_cast<QtObject *>(result->as<QV4::QObjectWrapper>()->object());
+}
- return Object::virtualOwnPropertyKeys(m, target);
+QJSValue QtObject::include(const QString &url, const QJSValue &callback) const
+{
+ return QV4Include::method_include(v4Engine(), v4Engine()->resolvedUrl(url), callback);
}
+
/*!
\qmlmethod bool Qt::isQtObject(object)
Returns \c true if \a object is a valid reference to a Qt or QML object,
\c false otherwise.
*/
-ReturnedValue QtObject::method_isQtObject(const FunctionObject *, const Value *, const Value *argv, int argc)
+bool QtObject::isQtObject(const QJSValue &value) const
{
- if (argc == 0)
- RETURN_RESULT(QV4::Encode(false));
+ return qjsvalue_cast<QObject *>(value) != nullptr;
+}
+
+/*!
+ \qmlmethod color Qt::color(string name)
+
+ Returns the color corresponding to the given \a name (i.e. red or #ff0000).
+ If there is no such color, \c null is returned.
+*/
+QVariant QtObject::color(const QString &name) const
+{
+ bool ok = false;
+ const QVariant v = QQmlStringConverters::colorFromString(name, &ok);
+ if (ok)
+ return v;
- return QV4::Encode(argv[0].as<QV4::QObjectWrapper>() != nullptr);
+ v4Engine()->throwError(QStringLiteral("\"%1\" is not a valid color name").arg(name));
+ return QVariant::fromValue(nullptr);
}
/*!
@@ -248,17 +330,8 @@ ReturnedValue QtObject::method_isQtObject(const FunctionObject *, const Value *,
Returns a color with the specified \a red, \a green, \a blue, and \a alpha
components. All components should be in the range 0-1 (inclusive).
*/
-ReturnedValue QtObject::method_rgba(const FunctionObject *f, const Value *, const Value *argv, int argc)
+QVariant QtObject::rgba(double r, double g, double b, double a) const
{
- QV4::Scope scope(f);
- if (argc < 3 || argc > 4)
- THROW_GENERIC_ERROR("Qt.rgba(): Invalid arguments");
-
- double r = argv[0].toNumber();
- double g = argv[1].toNumber();
- double b = argv[2].toNumber();
- double a = (argc == 4) ? argv[3].toNumber() : 1;
-
if (r < 0.0) r=0.0;
if (r > 1.0) r=1.0;
if (g < 0.0) g=0.0;
@@ -268,7 +341,7 @@ ReturnedValue QtObject::method_rgba(const FunctionObject *f, const Value *, cons
if (a < 0.0) a=0.0;
if (a > 1.0) a=1.0;
- return scope.engine->fromVariant(QQml_colorProvider()->fromRgbF(r, g, b, a));
+ return QQml_colorProvider()->fromRgbF(r, g, b, a);
}
/*!
@@ -277,18 +350,8 @@ ReturnedValue QtObject::method_rgba(const FunctionObject *f, const Value *, cons
Returns a color with the specified \a hue, \a saturation, \a lightness, and \a alpha
components. All components should be in the range 0-1 (inclusive).
*/
-ReturnedValue QtObject::method_hsla(const FunctionObject *b, const Value *, const Value *argv, int argc)
+QVariant QtObject::hsla(double h, double s, double l, double a) const
{
- QV4::Scope scope(b);
- int argCount = argc;
- if (argCount < 3 || argCount > 4)
- THROW_GENERIC_ERROR("Qt.hsla(): Invalid arguments");
-
- double h = argv[0].toNumber();
- double s = argv[1].toNumber();
- double l = argv[2].toNumber();
- double a = (argCount == 4) ? argv[3].toNumber() : 1;
-
if (h < 0.0) h=0.0;
if (h > 1.0) h=1.0;
if (s < 0.0) s=0.0;
@@ -298,7 +361,7 @@ ReturnedValue QtObject::method_hsla(const FunctionObject *b, const Value *, cons
if (a < 0.0) a=0.0;
if (a > 1.0) a=1.0;
- return scope.engine->fromVariant(QQml_colorProvider()->fromHslF(h, s, l, a));
+ return QQml_colorProvider()->fromHslF(h, s, l, a);
}
/*!
@@ -309,24 +372,14 @@ ReturnedValue QtObject::method_hsla(const FunctionObject *b, const Value *, cons
components. All components should be in the range 0-1 (inclusive).
*/
-ReturnedValue QtObject::method_hsva(const FunctionObject *b, const Value *, const Value *argv, int argc)
+QVariant QtObject::hsva(double h, double s, double v, double a) const
{
- QV4::Scope scope(b);
- int argCount = argc;
- if (argCount < 3 || argCount > 4)
- THROW_GENERIC_ERROR("Qt.hsva(): Invalid arguments");
-
- double h = argv[0].toNumber();
- double s = argv[1].toNumber();
- double v = argv[2].toNumber();
- double a = (argCount == 4) ? argv[3].toNumber() : 1;
-
h = qBound(0.0, h, 1.0);
s = qBound(0.0, s, 1.0);
v = qBound(0.0, v, 1.0);
a = qBound(0.0, a, 1.0);
- return scope.engine->fromVariant(QQml_colorProvider()->fromHsvF(h, s, v, a));
+ return QQml_colorProvider()->fromHsvF(h, s, v, a);
}
/*!
@@ -335,91 +388,67 @@ ReturnedValue QtObject::method_hsva(const FunctionObject *b, const Value *, cons
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.
*/
-ReturnedValue QtObject::method_colorEqual(const FunctionObject *b, const Value *, const Value *argv, int argc)
+bool QtObject::colorEqual(const QVariant &lhs, const QVariant &rhs) const
{
- QV4::Scope scope(b);
- if (argc != 2)
- THROW_GENERIC_ERROR("Qt.colorEqual(): Invalid arguments");
-
bool ok = false;
- QVariant lhs = scope.engine->toVariant(argv[0], -1);
- if (lhs.userType() == QVariant::String) {
- lhs = QQmlStringConverters::colorFromString(lhs.toString(), &ok);
+ QVariant color1 = lhs;
+ if (color1.userType() == QMetaType::QString) {
+ color1 = QQmlStringConverters::colorFromString(color1.toString(), &ok);
if (!ok) {
- THROW_GENERIC_ERROR("Qt.colorEqual(): Invalid color name");
+ v4Engine()->throwError(QStringLiteral("Qt.colorEqual(): Invalid color name"));
+ return false;
}
- } else if (lhs.userType() != QVariant::Color) {
- THROW_GENERIC_ERROR("Qt.colorEqual(): Invalid arguments");
+ } else if (color1.userType() != QMetaType::QColor) {
+ v4Engine()->throwError(QStringLiteral("Qt.colorEqual(): Invalid arguments"));
+ return false;
}
- QVariant rhs = scope.engine->toVariant(argv[1], -1);
- if (rhs.userType() == QVariant::String) {
- rhs = QQmlStringConverters::colorFromString(rhs.toString(), &ok);
+ QVariant color2 = rhs;
+ if (color2.userType() == QMetaType::QString) {
+ color2 = QQmlStringConverters::colorFromString(color2.toString(), &ok);
if (!ok) {
- THROW_GENERIC_ERROR("Qt.colorEqual(): Invalid color name");
+ v4Engine()->throwError(QStringLiteral("Qt.colorEqual(): Invalid color name"));
+ return false;
}
- } else if (rhs.userType() != QVariant::Color) {
- THROW_GENERIC_ERROR("Qt.colorEqual(): Invalid arguments");
+ } else if (color2.userType() != QMetaType::QColor) {
+ v4Engine()->throwError(QStringLiteral("Qt.colorEqual(): Invalid arguments"));
+ return false;
}
- bool equal = (lhs == rhs);
- return QV4::Encode(equal);
+ return color1 == color2;
}
/*!
- \qmlmethod rect Qt::rect(int x, int y, int width, int height)
+ \qmlmethod rect Qt::rect(real x, real y, real width, real height)
Returns a rect with the top-left corner at \a x, \a y and the specified \a width and \a height.
*/
-ReturnedValue QtObject::method_rect(const FunctionObject *b, const Value *, const Value *argv, int argc)
+QRectF QtObject::rect(double x, double y, double width, double height) const
{
- QV4::Scope scope(b);
- if (argc != 4)
- THROW_GENERIC_ERROR("Qt.rect(): Invalid arguments");
-
- double x = argv[0].toNumber();
- double y = argv[1].toNumber();
- double w = argv[2].toNumber();
- double h = argv[3].toNumber();
-
- return scope.engine->fromVariant(QVariant::fromValue(QRectF(x, y, w, h)));
+ return QRectF(x, y, width, height);
}
/*!
- \qmlmethod point Qt::point(int x, int y)
+ \qmlmethod point Qt::point(real x, real y)
Returns a point with the specified \a x and \a y coordinates.
*/
-ReturnedValue QtObject::method_point(const FunctionObject *b, const Value *, const Value *argv, int argc)
+QPointF QtObject::point(double x, double y) const
{
- QV4::Scope scope(b);
- if (argc != 2)
- THROW_GENERIC_ERROR("Qt.point(): Invalid arguments");
-
- double x = argv[0].toNumber();
- double y = argv[1].toNumber();
-
- return scope.engine->fromVariant(QVariant::fromValue(QPointF(x, y)));
+ return QPointF(x, y);
}
/*!
- \qmlmethod size Qt::size(int width, int height)
+ \qmlmethod size Qt::size(real width, real height)
Returns a size with the specified \a width and \a height.
*/
-ReturnedValue QtObject::method_size(const FunctionObject *b, const Value *, const Value *argv, int argc)
+QSizeF QtObject::size(double w, double h) const
{
- QV4::Scope scope(b);
- if (argc != 2)
- THROW_GENERIC_ERROR("Qt.size(): Invalid arguments");
-
- double w = argv[0].toNumber();
- double h = argv[1].toNumber();
-
- return scope.engine->fromVariant(QVariant::fromValue(QSizeF(w, h)));
+ return QSizeF(w, h);
}
/*!
@@ -427,43 +456,67 @@ ReturnedValue QtObject::method_size(const FunctionObject *b, const Value *, cons
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.
*/
-ReturnedValue QtObject::method_font(const FunctionObject *b, const Value *, const Value *argv, int argc)
+QVariant QtObject::font(const QJSValue &fontSpecifier) const
{
- QV4::Scope scope(b);
- if (argc != 1 || !argv[0].isObject())
- THROW_GENERIC_ERROR("Qt.font(): Invalid arguments");
+ if (!fontSpecifier.isObject()) {
+ v4Engine()->throwError(QStringLiteral("Qt.font(): Invalid arguments"));
+ return QVariant();
+ }
- QV4::ExecutionEngine *v4 = scope.engine;
- bool ok = false;
- QVariant v = QQml_valueTypeProvider()->createVariantFromJsObject(QMetaType::QFont, argv[0], v4, &ok);
- if (!ok)
- THROW_GENERIC_ERROR("Qt.font(): Invalid argument: no valid font subproperties specified");
- return scope.engine->fromVariant(v);
+ {
+ const QVariant v = QQmlValueTypeProvider::createValueType(
+ fontSpecifier, QMetaType(QMetaType::QFont));
+ if (v.isValid())
+ return v;
+ }
+
+ v4Engine()->throwError(QStringLiteral("Qt.font(): Invalid argument: "
+ "no valid font subproperties specified"));
+ return QVariant();
}
+template<typename T>
+void addParameters(QJSEngine *e, QJSValue &result, int i, T parameter)
+{
+ result.setProperty(i, e->toScriptValue(parameter));
+}
+
+template<>
+void addParameters<double>(QJSEngine *, QJSValue &result, int i, double parameter)
+{
+ result.setProperty(i, QJSValue(parameter));
+}
+template<typename T, typename ...Others>
+void addParameters(QJSEngine *e, QJSValue &result, int i, T parameter, Others... others)
+{
+ addParameters<T>(e, result, i, parameter);
+ addParameters<Others...>(e, result, ++i, others...);
+}
+
+template<typename ...T>
+static QVariant constructFromJSValue(QJSEngine *e, QMetaType type, T... parameters)
+{
+ if (!e)
+ return QVariant();
+ QJSValue params = e->newArray(sizeof...(parameters));
+ addParameters(e, params, 0, parameters...);
+ const QVariant variant = QQmlValueTypeProvider::createValueType(params, type);
+ return variant.isValid() ? variant : QVariant(type);
+}
/*!
\qmlmethod vector2d Qt::vector2d(real x, real y)
Returns a vector2d with the specified \a x and \a y values.
*/
-ReturnedValue QtObject::method_vector2d(const FunctionObject *b, const Value *, const Value *argv, int argc)
+QVariant QtObject::vector2d(double x, double y) const
{
- QV4::Scope scope(b);
- if (argc != 2)
- THROW_GENERIC_ERROR("Qt.vector2d(): Invalid arguments");
-
- float xy[3]; // qvector2d uses float internally
- xy[0] = argv[0].toNumber();
- xy[1] = argv[1].toNumber();
-
- const void *params[] = { xy };
- return scope.engine->fromVariant(QQml_valueTypeProvider()->createValueType(QMetaType::QVector2D, 1, params));
+ return constructFromJSValue(jsEngine(), QMetaType(QMetaType::QVector2D), x, y);
}
/*!
@@ -471,19 +524,9 @@ ReturnedValue QtObject::method_vector2d(const FunctionObject *b, const Value *,
Returns a vector3d with the specified \a x, \a y, and \a z values.
*/
-ReturnedValue QtObject::method_vector3d(const FunctionObject *b, const Value *, const Value *argv, int argc)
+QVariant QtObject::vector3d(double x, double y, double z) const
{
- QV4::Scope scope(b);
- if (argc != 3)
- THROW_GENERIC_ERROR("Qt.vector3d(): Invalid arguments");
-
- float xyz[3]; // qvector3d uses float internally
- xyz[0] = argv[0].toNumber();
- xyz[1] = argv[1].toNumber();
- xyz[2] = argv[2].toNumber();
-
- const void *params[] = { xyz };
- return scope.engine->fromVariant(QQml_valueTypeProvider()->createValueType(QMetaType::QVector3D, 1, params));
+ return constructFromJSValue(jsEngine(), QMetaType(QMetaType::QVector3D), x, y, z);
}
/*!
@@ -491,20 +534,9 @@ ReturnedValue QtObject::method_vector3d(const FunctionObject *b, const Value *,
Returns a vector4d with the specified \a x, \a y, \a z, and \a w values.
*/
-ReturnedValue QtObject::method_vector4d(const FunctionObject *b, const Value *, const Value *argv, int argc)
+QVariant QtObject::vector4d(double x, double y, double z, double w) const
{
- QV4::Scope scope(b);
- if (argc != 4)
- THROW_GENERIC_ERROR("Qt.vector4d(): Invalid arguments");
-
- float xyzw[4]; // qvector4d uses float internally
- xyzw[0] = argv[0].toNumber();
- xyzw[1] = argv[1].toNumber();
- xyzw[2] = argv[2].toNumber();
- xyzw[3] = argv[3].toNumber();
-
- const void *params[] = { xyzw };
- return scope.engine->fromVariant(QQml_valueTypeProvider()->createValueType(QMetaType::QVector4D, 1, params));
+ return constructFromJSValue(jsEngine(), QMetaType(QMetaType::QVector4D), x, y, z, w);
}
/*!
@@ -512,20 +544,50 @@ ReturnedValue QtObject::method_vector4d(const FunctionObject *b, const Value *,
Returns a quaternion with the specified \a scalar, \a x, \a y, and \a z values.
*/
-ReturnedValue QtObject::method_quaternion(const FunctionObject *b, const Value *, const Value *argv, int argc)
+QVariant QtObject::quaternion(double scalar, double x, double y, double z) const
{
- QV4::Scope scope(b);
- if (argc != 4)
- THROW_GENERIC_ERROR("Qt.quaternion(): Invalid arguments");
+ return constructFromJSValue(jsEngine(), QMetaType(QMetaType::QQuaternion), scalar, x, y, z);
+}
+
+/*!
+ \qmlmethod matrix4x4 Qt::matrix4x4()
+
+ 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);
+}
+
+/*!
+ \qmlmethod matrix4x4 Qt::matrix4x4(var values)
- qreal sxyz[4]; // qquaternion uses qreal internally
- sxyz[0] = argv[0].toNumber();
- sxyz[1] = argv[1].toNumber();
- sxyz[2] = argv[2].toNumber();
- sxyz[3] = argv[3].toNumber();
+ Returns a matrix4x4 with the specified \a values. \a values is expected to
+ be a JavaScript array with 16 entries.
- const void *params[] = { sxyz };
- return scope.engine->fromVariant(QQml_valueTypeProvider()->createValueType(QMetaType::QQuaternion, 1, params));
+ The array indices correspond to positions in the matrix as follows:
+
+ \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 QJSValue &value) const
+{
+ if (value.isObject()) {
+ QVariant v = QQmlValueTypeProvider::createValueType(
+ value, QMetaType(QMetaType::QMatrix4x4));
+ if (v.isValid())
+ return v;
+ }
+
+ v4Engine()->throwError(QStringLiteral("Qt.matrix4x4(): Invalid argument: "
+ "not a valid matrix4x4 values array"));
+ return QVariant();
}
/*!
@@ -541,53 +603,34 @@ ReturnedValue QtObject::method_quaternion(const FunctionObject *b, const Value *
\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
-
- Alternatively, the function may be called with a single argument
- where that argument is a JavaScript array which contains the sixteen
- matrix values.
-
- Finally, the function may be called with no arguments and the resulting
- matrix will be the identity matrix.
*/
-ReturnedValue QtObject::method_matrix4x4(const FunctionObject *b, const Value *, const Value *argv, int argc)
+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
{
- QV4::Scope scope(b);
-
- if (argc == 0) {
- return scope.engine->fromVariant(QQml_valueTypeProvider()->createValueType(QMetaType::QMatrix4x4, 0, nullptr));
- }
+ return constructFromJSValue(jsEngine(), QMetaType(QMetaType::QMatrix4x4),
+ m11, m12, m13, m14, m21, m22, m23, m24,
+ m31, m32, m33, m34, m41, m42, m43, m44);
+}
- if (argc == 1 && argv[0].isObject()) {
- bool ok = false;
- QVariant v = QQml_valueTypeProvider()->createVariantFromJsObject(QMetaType::QMatrix4x4, argv[0], scope.engine, &ok);
- if (!ok)
- THROW_GENERIC_ERROR("Qt.matrix4x4(): Invalid argument: not a valid matrix4x4 values array");
- return scope.engine->fromVariant(v);
+static QVariant colorVariantFromJSValue(const QJSValue &color, bool *ok)
+{
+ QVariant v;
+ if (color.isString()) {
+ v = QQmlStringConverters::colorFromString(color.toString(), ok);
+ if (!(*ok))
+ return QVariant::fromValue(nullptr);
+ } else {
+ v = color.toVariant();
+ if (v.userType() != QMetaType::QColor) {
+ *ok = false;
+ return QVariant::fromValue(nullptr);
+ }
}
- if (argc != 16)
- THROW_GENERIC_ERROR("Qt.matrix4x4(): Invalid arguments");
-
- qreal vals[16]; // qmatrix4x4 uses qreal internally
- vals[0] = argv[0].toNumber();
- vals[1] = argv[1].toNumber();
- vals[2] = argv[2].toNumber();
- vals[3] = argv[3].toNumber();
- vals[4] = argv[4].toNumber();
- vals[5] = argv[5].toNumber();
- vals[6] = argv[6].toNumber();
- vals[7] = argv[7].toNumber();
- vals[8] = argv[8].toNumber();
- vals[9] = argv[9].toNumber();
- vals[10] = argv[10].toNumber();
- vals[11] = argv[11].toNumber();
- vals[12] = argv[12].toNumber();
- vals[13] = argv[13].toNumber();
- vals[14] = argv[14].toNumber();
- vals[15] = argv[15].toNumber();
-
- const void *params[] = { vals };
- return scope.engine->fromVariant(QQml_valueTypeProvider()->createValueType(QMetaType::QMatrix4x4, 1, params));
+ *ok = true;
+ return v;
}
/*!
@@ -605,28 +648,11 @@ ReturnedValue QtObject::method_matrix4x4(const FunctionObject *b, const Value *,
If \a factor is not supplied, returns a color that is 50% lighter than \a baseColor (factor 1.5).
*/
-ReturnedValue QtObject::method_lighter(const FunctionObject *b, const Value *, const Value *argv, int argc)
+QVariant QtObject::lighter(const QJSValue &color, double factor) const
{
- QV4::Scope scope(b);
- if (argc != 1 && argc != 2)
- THROW_GENERIC_ERROR("Qt.lighter(): Invalid arguments");
-
- QVariant v = scope.engine->toVariant(argv[0], -1);
- if (v.userType() == QVariant::String) {
- bool ok = false;
- v = QQmlStringConverters::colorFromString(v.toString(), &ok);
- if (!ok) {
- return QV4::Encode::null();
- }
- } else if (v.userType() != QVariant::Color) {
- return QV4::Encode::null();
- }
-
- qreal factor = 1.5;
- if (argc == 2)
- factor = argv[1].toNumber();
-
- return scope.engine->fromVariant(QQml_colorProvider()->lighter(v, factor));
+ bool ok;
+ const QVariant v = colorVariantFromJSValue(color, &ok);
+ return ok ? QQml_colorProvider()->lighter(v, factor) : v;
}
/*!
@@ -645,28 +671,25 @@ ReturnedValue QtObject::method_lighter(const FunctionObject *b, const Value *, c
If \a factor is not supplied, returns a color that is 50% darker than \a baseColor (factor 2.0).
*/
-ReturnedValue QtObject::method_darker(const FunctionObject *b, const Value *, const Value *argv, int argc)
+QVariant QtObject::darker(const QJSValue &color, double factor) const
{
- QV4::Scope scope(b);
- if (argc != 1 && argc != 2)
- THROW_GENERIC_ERROR("Qt.darker(): Invalid arguments");
+ bool ok;
+ const QVariant v = colorVariantFromJSValue(color, &ok);
+ return ok ? QQml_colorProvider()->darker(v, factor) : v;
+}
- QVariant v = scope.engine->toVariant(argv[0], -1);
- if (v.userType() == QVariant::String) {
- bool ok = false;
- v = QQmlStringConverters::colorFromString(v.toString(), &ok);
- if (!ok) {
- return QV4::Encode::null();
- }
- } else if (v.userType() != QVariant::Color) {
- return QV4::Encode::null();
- }
+/*!
+ \qmlmethod color Qt::alpha(color baseColor, real value)
- qreal factor = 2.0;
- if (argc == 2)
- factor = argv[1].toNumber();
+ Returns \a baseColor with an alpha value of \a value.
- return scope.engine->fromVariant(QQml_colorProvider()->darker(v, factor));
+ \a value is a real ranging from 0 (completely transparent) to 1 (completely opaque).
+*/
+QVariant QtObject::alpha(const QJSValue &baseColor, double value) const
+{
+ bool ok;
+ const QVariant v = colorVariantFromJSValue(baseColor, &ok);
+ return ok ? QQml_colorProvider()->alpha(v, value) : v;
}
/*!
@@ -695,151 +718,279 @@ ReturnedValue QtObject::method_darker(const FunctionObject *b, const Value *, co
Tint is most useful when a subtle change is intended to be conveyed due to some event;
you can then use tinting to more effectively tune the visible color.
*/
-ReturnedValue QtObject::method_tint(const FunctionObject *b, const Value *, const Value *argv, int argc)
+QVariant QtObject::tint(const QJSValue &baseColor, const QJSValue &tintColor) const
{
- QV4::Scope scope(b);
- if (argc != 2)
- THROW_GENERIC_ERROR("Qt.tint(): Invalid arguments");
+ bool ok;
// base color
- QVariant v1 = scope.engine->toVariant(argv[0], -1);
- if (v1.userType() == QVariant::String) {
- bool ok = false;
- v1 = QQmlStringConverters::colorFromString(v1.toString(), &ok);
- if (!ok) {
- return QV4::Encode::null();
- }
- } else if (v1.userType() != QVariant::Color) {
- return QV4::Encode::null();
- }
+ const QVariant v1 = colorVariantFromJSValue(baseColor, &ok);
+ if (!ok)
+ return v1;
// tint color
- QVariant v2 = scope.engine->toVariant(argv[1], -1);
- if (v2.userType() == QVariant::String) {
- bool ok = false;
- v2 = QQmlStringConverters::colorFromString(v2.toString(), &ok);
- if (!ok) {
- return QV4::Encode::null();
- }
- } else if (v2.userType() != QVariant::Color) {
- return QV4::Encode::null();
+ const QVariant v2 = colorVariantFromJSValue(tintColor, &ok);
+
+ return ok ? QQml_colorProvider()->tint(v1, v2) : v2;
+}
+
+namespace {
+template <typename T>
+QString formatDateTimeObjectUsingDateFormat(T formatThis, Qt::DateFormat format) {
+ switch (format) {
+ case Qt::TextDate:
+ case Qt::ISODate:
+ case Qt::RFC2822Date:
+ case Qt::ISODateWithMs:
+ return formatThis.toString(format);
+ default: // ### Qt 6: remove once qtbase has removed the rest of the enum !
+ break;
}
+ // Q_UNREACHABLE(); // ### Qt 6: restore once the default is gone
+ return QString();
+}
+}
- return scope.engine->fromVariant(QQml_colorProvider()->tint(v1, v2));
+static QTime dateTimeToTime(const QDateTime &dateTime)
+{
+ return dateTime.toLocalTime().time();
}
/*!
-\qmlmethod string Qt::formatDate(datetime date, variant format)
+\qmlmethod string Qt::formatDate(datetime date, variant format, variant localeFormatOption)
-Returns a string representation of \a date, optionally formatted according
-to \a format.
+Returns a string representation of \a date, optionally formatted using \a format.
The \a date parameter may be a JavaScript \c Date object, a \l{date}{date}
-property, a QDate, or QDateTime value. The \a format parameter may be any of
-the possible format values as described for
+property, a QDate, or QDateTime value. The \a format and \a localeFormatOption
+parameter may be any of the possible format values as described for
\l{QtQml::Qt::formatDateTime()}{Qt.formatDateTime()}.
If \a format is not specified, \a date is formatted using
-\l {Qt::DefaultLocaleShortDate}{Qt.DefaultLocaleShortDate}.
+\l {QLocale::FormatType}{Locale.ShortFormat} using the
+default locale.
\sa Locale
*/
-ReturnedValue QtObject::method_formatDate(const FunctionObject *b, const Value *, const Value *argv, int argc)
+static std::optional<QDate> dateFromString(const QString &string, QV4::ExecutionEngine *engine)
{
- QV4::Scope scope(b);
- if (argc < 1 || argc > 2)
- THROW_GENERIC_ERROR("Qt.formatDate(): Invalid arguments");
-
- Qt::DateFormat enumFormat = Qt::DefaultLocaleShortDate;
- QDate date = scope.engine->toVariant(argv[0], -1).toDateTime().date();
- QString formattedDate;
- if (argc == 2) {
- QV4::ScopedString s(scope, argv[1]);
- if (s) {
- QString format = s->toQString();
- formattedDate = date.toString(format);
- } else if (argv[1].isNumber()) {
- quint32 intFormat = argv[1].asDouble();
- Qt::DateFormat format = Qt::DateFormat(intFormat);
- formattedDate = date.toString(format);
- } else {
- THROW_GENERIC_ERROR("Qt.formatDate(): Invalid date format");
+ {
+ 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();
}
- } else {
- formattedDate = date.toString(enumFormat);
}
- return Encode(scope.engine->newString(formattedDate));
+ {
+ // 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(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(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
/*!
-\qmlmethod string Qt::formatTime(datetime time, variant format)
+\qmlmethod string Qt::formatTime(datetime time, variant format, variant localeFormatOption)
-Returns a string representation of \a time, optionally formatted according to
-\a format.
+Returns a string representation of \a time, optionally formatted using
+\a format, and, if provided, \a localeFormatOption.
The \a time parameter may be a JavaScript \c Date object, a QTime, or QDateTime
-value. The \a format parameter may be any of the possible format values as
-described for \l{QtQml::Qt::formatDateTime()}{Qt.formatDateTime()}.
+value. The \a format and \a localeFormatOption parameter may be any of the
+possible format values as described for
+\l{QtQml::Qt::formatDateTime()}{Qt.formatDateTime()}.
If \a format is not specified, \a time is formatted using
-\l {Qt::DefaultLocaleShortDate}{Qt.DefaultLocaleShortDate}.
+\l {QLocale::FormatType}{Locale.ShortFormat} using the default locale.
\sa Locale
*/
-ReturnedValue QtObject::method_formatTime(const FunctionObject *b, const Value *, const Value *argv, int argc)
+static std::optional<QTime> timeFromString(const QString &string, QV4::ExecutionEngine *engine)
{
- QV4::Scope scope(b);
- if (argc < 1 || argc > 2)
- THROW_GENERIC_ERROR("Qt.formatTime(): Invalid arguments");
-
- QVariant argVariant = scope.engine->toVariant(argv[0], -1);
- QTime time;
- if (argv[0].as<DateObject>() || (argVariant.type() == QVariant::String))
- time = argVariant.toDateTime().time();
- else // if (argVariant.type() == QVariant::Time), or invalid.
- time = argVariant.toTime();
-
- Qt::DateFormat enumFormat = Qt::DefaultLocaleShortDate;
- QString formattedTime;
- if (argc == 2) {
- QV4::ScopedString s(scope, argv[1]);
- if (s) {
- QString format = s->toQString();
- formattedTime = time.toString(format);
- } else if (argv[1].isNumber()) {
- quint32 intFormat = argv[1].asDouble();
- Qt::DateFormat format = Qt::DateFormat(intFormat);
- formattedTime = time.toString(format);
- } else {
- THROW_GENERIC_ERROR("Qt.formatTime(): Invalid time format");
+ {
+ const QTime time = QTime::fromString(string, Qt::ISODate);
+ if (time.isValid())
+ return time;
+ }
+
+ {
+ // For historical reasons, the string argument is parsed as datetime, not as only time
+ const QDateTime dateTime = QDateTime::fromString(string, Qt::ISODate);
+ if (dateTime.isValid()) {
+ qCWarning(lcRootProperties())
+ << string << "is a date/time string being passed to formatTime()."
+ << "You should only pass time strings to formatTime().";
+ return dateTime.time();
}
- } else {
- formattedTime = time.toString(enumFormat);
}
- return Encode(scope.engine->newString(formattedTime));
+ {
+ // 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(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
+{
+
+ if (auto qTime = timeFromString(time, v4Engine()))
+ return formatTime(qTime.value(), format);
+
+ return QString();
+}
+
+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()))
+ return formatTime(qTime.value(), format);
+
+ return QString();
+}
+
+#if QT_CONFIG(qml_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
+{
+ if (auto qTime = timeFromString(time, v4Engine()))
+ return locale.toString(qTime.value(), formatType);
+
+ return QString();
+}
+#endif
+
/*!
-\qmlmethod string Qt::formatDateTime(datetime dateTime, variant format)
+\qmlmethod string Qt::formatDateTime(datetime dateTime, variant format, variant localeFormatOption)
-Returns a string representation of \a dateTime, optionally formatted according to
-\a format.
+Returns a string representation of \a dateTime, optionally formatted using
+\a format and \a localeFormatOption.
The \a dateTime parameter may be a JavaScript \c Date object, a \l{date}{date}
property, a QDate, QTime, or QDateTime value.
If \a format is not provided, \a dateTime is formatted using
-\l {Qt::DefaultLocaleShortDate}{Qt.DefaultLocaleShortDate}. Otherwise,
-\a format should be either:
+\l {QLocale::FormatType}{Locale.ShortFormat} using the
+default locale. Otherwise, \a format should be either:
\list
\li One of the Qt::DateFormat enumeration values, such as
- \c Qt.DefaultLocaleShortDate or \c Qt.ISODate
+ \c Qt.RFC2822Date or \c Qt.ISODate.
\li A string that specifies the format of the returned string, as detailed below.
+\li A \c locale object.
\endlist
+If \a format specifies a locale object, \dateTime is formatted
+with \l{QLocale::toString}. In this case, \a localeFormatOption can hold a value
+of type \l {QLocale::FormatType} to further tune the formatting. If none is
+provided, \l {QLocale::FormatType}{Locale.ShortFormat} is used.
+
If \a format specifies a format string, it should use the following expressions
to specify the date:
@@ -913,33 +1064,70 @@ with the \a format values below to produce the following results:
\sa Locale
*/
-ReturnedValue QtObject::method_formatDateTime(const FunctionObject *b, const Value *, const Value *argv, int argc)
+static std::optional<QDateTime> dateTimeFromString(const QString &string, QV4::ExecutionEngine *engine)
{
- QV4::Scope scope(b);
- if (argc < 1 || argc > 2)
- THROW_GENERIC_ERROR("Qt.formatDateTime(): Invalid arguments");
-
- Qt::DateFormat enumFormat = Qt::DefaultLocaleShortDate;
- QDateTime dt = scope.engine->toVariant(argv[0], -1).toDateTime();
- QString formattedDt;
- if (argc == 2) {
- QV4::ScopedString s(scope, argv[1]);
- if (s) {
- QString format = s->toQString();
- formattedDt = dt.toString(format);
- } else if (argv[1].isNumber()) {
- quint32 intFormat = argv[1].asDouble();
- Qt::DateFormat format = Qt::DateFormat(intFormat);
- formattedDt = dt.toString(format);
- } else {
- THROW_GENERIC_ERROR("Qt.formatDateTime(): Invalid datetime format");
- }
- } else {
- formattedDt = dt.toString(enumFormat);
+ {
+ 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;
}
- return Encode(scope.engine->newString(formattedDt));
+ 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
/*!
\qmlmethod bool Qt::openUrlExternally(url target)
@@ -952,41 +1140,67 @@ ReturnedValue QtObject::method_formatDateTime(const FunctionObject *b, const Val
still fail to launch or fail to open the requested URL. This result will not be reported back
to the application.
*/
-ReturnedValue QtObject::method_openUrlExternally(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
+bool QtObject::openUrlExternally(const QUrl &url) const
{
- QV4::Scope scope(b);
- if (argc != 1)
- return QV4::Encode(false);
+ return QQml_guiProvider()->openUrlExternally(resolvedUrl(url));
+}
- ScopedValue result(scope, method_resolvedUrl(b, thisObject, argv, argc));
- QUrl url(result->toQStringNoThrow());
- return scope.engine->fromVariant(QQml_guiProvider()->openUrlExternally(url));
+/*!
+ \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()
*/
-ReturnedValue QtObject::method_resolvedUrl(const FunctionObject *b, const Value *, const Value *argv, int argc)
+QUrl QtObject::resolvedUrl(const QUrl &url) const
{
- QV4::Scope scope(b);
- if (argc != 1)
- return Encode::undefined();
-
- QUrl url = scope.engine->toVariant(argv[0], -1).toUrl();
- QQmlEngine *e = scope.engine->qmlEngine();
- QQmlEnginePrivate *p = nullptr;
- if (e) p = QQmlEnginePrivate::get(e);
- if (p) {
- QQmlContextData *ctxt = scope.engine->callingQmlContext();
- if (ctxt)
- return Encode(scope.engine->newString(ctxt->resolvedUrl(url).toString()));
- else
- return Encode(scope.engine->newString(url.toString()));
+ if (QQmlRefPointer<QQmlContextData> ctxt = v4Engine()->callingQmlContext())
+ return ctxt->resolvedUrl(url);
+ if (QQmlEngine *engine = qmlEngine())
+ return engine->baseUrl().resolved(url);
+ return url;
+}
+
+/*!
+ \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);
}
- return Encode(scope.engine->newString(e->baseUrl().resolved(url).toString()));
+ if (QQmlEngine *engine = qmlEngine())
+ return engine->baseUrl().resolved(url);
+ return url;
}
/*!
@@ -994,96 +1208,71 @@ ReturnedValue QtObject::method_resolvedUrl(const FunctionObject *b, const Value
Returns a list of the font families available to the application.
*/
-ReturnedValue QtObject::method_fontFamilies(const FunctionObject *b, const Value *, const Value *, int argc)
+QStringList QtObject::fontFamilies() const
{
- QV4::Scope scope(b);
- if (argc != 0)
- THROW_GENERIC_ERROR("Qt.fontFamilies(): Invalid arguments");
-
- return scope.engine->fromVariant(QVariant(QQml_guiProvider()->fontFamilies()));
+ return QQml_guiProvider()->fontFamilies();
}
/*!
\qmlmethod string Qt::md5(data)
Returns a hex string of the md5 hash of \a data.
*/
-ReturnedValue QtObject::method_md5(const FunctionObject *b, const Value *, const Value *argv, int argc)
+QString QtObject::md5(const QString &data) const
{
- QV4::Scope scope(b);
- if (argc != 1)
- THROW_GENERIC_ERROR("Qt.md5(): Invalid arguments");
-
- QByteArray data = argv[0].toQStringNoThrow().toUtf8();
- QByteArray result = QCryptographicHash::hash(data, QCryptographicHash::Md5);
- return Encode(scope.engine->newString(QLatin1String(result.toHex())));
+ return QLatin1String(QCryptographicHash::hash(data.toUtf8(), QCryptographicHash::Md5).toHex());
}
/*!
\qmlmethod string Qt::btoa(data)
Binary to ASCII - this function returns a base64 encoding of \a data.
*/
-ReturnedValue QtObject::method_btoa(const FunctionObject *b, const Value *, const Value *argv, int argc)
+QString QtObject::btoa(const QString &data) const
{
- QV4::Scope scope(b);
- if (argc != 1)
- THROW_GENERIC_ERROR("Qt.btoa(): Invalid arguments");
-
- QByteArray data = argv[0].toQStringNoThrow().toUtf8();
-
- return Encode(scope.engine->newString(QLatin1String(data.toBase64())));
+ return QLatin1String(data.toUtf8().toBase64());
}
/*!
\qmlmethod string Qt::atob(data)
ASCII to binary - this function decodes the base64 encoded \a data string and returns it.
*/
-ReturnedValue QtObject::method_atob(const FunctionObject *b, const Value *, const Value *argv, int argc)
+QString QtObject::atob(const QString &data) const
{
- QV4::Scope scope(b);
- if (argc != 1)
- THROW_GENERIC_ERROR("Qt.atob(): Invalid arguments");
-
- QByteArray data = argv[0].toQStringNoThrow().toLatin1();
-
- return Encode(scope.engine->newString(QString::fromUtf8(QByteArray::fromBase64(data))));
+ return QString::fromUtf8(QByteArray::fromBase64(data.toLatin1()));
}
/*!
-\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()
*/
-ReturnedValue QtObject::method_quit(const FunctionObject *b, const Value *, const Value *, int)
+void QtObject::quit() const
{
- QQmlEnginePrivate::get(b->engine()->qmlEngine())->sendQuit();
- return Encode::undefined();
+ if (QQmlEngine *engine = qmlEngine())
+ QQmlEnginePrivate::get(engine)->sendQuit();
}
/*!
\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.
\sa quit()
*/
-ReturnedValue QtObject::method_exit(const FunctionObject *b, const Value *, const Value *argv, int argc)
+void QtObject::exit(int retCode) const
{
- QV4::Scope scope(b);
- if (argc != 1)
- THROW_GENERIC_ERROR("Qt.exit(): Invalid arguments");
-
- int retCode = argv[0].toNumber();
-
- QQmlEnginePrivate::get(scope.engine->qmlEngine())->sendExit(retCode);
- return QV4::Encode::undefined();
+ if (QQmlEngine *engine = qmlEngine())
+ QQmlEnginePrivate::get(engine)->sendExit(retCode);
}
/*!
@@ -1098,23 +1287,31 @@ Example (where \c parentItem is the id of an existing QML item):
\snippet qml/createQmlObject.qml 0
-In the case of an error, a \l {Qt Script} Error object is thrown. This object has an additional property,
+In the case of an error, a QQmlError object is thrown. This object has an additional property,
\c qmlErrors, which is an array of the errors encountered.
Each object in this array has the members \c lineNumber, \c columnNumber, \c fileName and \c message.
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.
*/
-ReturnedValue QtObject::method_createQmlObject(const FunctionObject *b, const Value *, const Value *argv, int argc)
+QObject *QtObject::createQmlObject(const QString &qml, QObject *parent, const QUrl &url) const
{
- QV4::Scope scope(b);
- if (argc < 2 || argc > 3)
- THROW_GENERIC_ERROR("Qt.createQmlObject(): Invalid arguments");
+ QQmlEngine *engine = qmlEngine();
+ if (!engine) {
+ v4Engine()->throwError(QStringLiteral("Qt.createQmlObject(): "
+ "Can only be called on a QML engine."));
+ return nullptr;
+ }
struct Error {
static ReturnedValue create(QV4::ExecutionEngine *v4, const QList<QQmlError> &errors) {
@@ -1127,7 +1324,7 @@ ReturnedValue QtObject::method_createQmlObject(const FunctionObject *b, const Va
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();
@@ -1145,60 +1342,54 @@ ReturnedValue QtObject::method_createQmlObject(const FunctionObject *b, const Va
}
};
- QQmlEngine *engine = scope.engine->qmlEngine();
+ QQmlRefPointer<QQmlContextData> context = v4Engine()->callingQmlContext();
+ if (!context)
+ context = QQmlContextData::get(QQmlEnginePrivate::get(engine)->rootContext);
- QQmlContextData *context = scope.engine->callingQmlContext();
- if (!context) {
- QQmlEngine *qmlEngine = scope.engine->qmlEngine();
- if (qmlEngine)
- context = QQmlContextData::get(QQmlEnginePrivate::get(qmlEngine)->rootContext);
- }
Q_ASSERT(context);
QQmlContext *effectiveContext = nullptr;
- if (context->isPragmaLibraryContext)
+ if (context->isPragmaLibraryContext())
effectiveContext = engine->rootContext();
else
effectiveContext = context->asQQmlContext();
Q_ASSERT(effectiveContext);
- QString qml = argv[0].toQStringNoThrow();
if (qml.isEmpty())
- RETURN_RESULT(Encode::null());
-
- QUrl url;
- if (argc > 2)
- url = QUrl(argv[2].toQStringNoThrow());
- else
- url = QUrl(QLatin1String("inline"));
+ return nullptr;
+ QUrl resolvedUrl = url;
if (url.isValid() && url.isRelative())
- url = context->resolvedUrl(url);
+ resolvedUrl = context->resolvedUrl(url);
- QObject *parentArg = nullptr;
- QV4::Scoped<QV4::QObjectWrapper> qobjectWrapper(scope, argv[1]);
- if (!!qobjectWrapper)
- parentArg = qobjectWrapper->object();
- if (!parentArg)
- THROW_GENERIC_ERROR("Qt.createQmlObject(): Missing parent object");
+ if (!parent) {
+ v4Engine()->throwError(QStringLiteral("Qt.createQmlObject(): Missing parent object"));
+ return nullptr;
+ }
QQmlRefPointer<QQmlTypeData> typeData = QQmlEnginePrivate::get(engine)->typeLoader.getType(
- qml.toUtf8(), url, QQmlTypeLoader::Synchronous);
+ qml.toUtf8(), resolvedUrl, QQmlTypeLoader::Synchronous);
Q_ASSERT(typeData->isCompleteOrError());
QQmlComponent component(engine);
QQmlComponentPrivate *componentPrivate = QQmlComponentPrivate::get(&component);
componentPrivate->fromTypeData(typeData);
componentPrivate->progress = 1.0;
+ Scope scope(v4Engine());
if (component.isError()) {
ScopedValue v(scope, Error::create(scope.engine, component.errors()));
- RETURN_RESULT(scope.engine->throwError(v));
+ scope.engine->throwError(v);
+ return nullptr;
}
- if (!component.isReady())
- THROW_GENERIC_ERROR("Qt.createQmlObject(): Component is not ready");
+ if (!component.isReady()) {
+ v4Engine()->throwError(QStringLiteral("Qt.createQmlObject(): Component is not ready"));
+ return nullptr;
+ }
if (!effectiveContext->isValid()) {
- THROW_GENERIC_ERROR("Qt.createQmlObject(): Cannot create a component in an invalid context");
+ v4Engine()->throwError(QStringLiteral("Qt.createQmlObject(): Cannot create a component "
+ "in an invalid context"));
+ return nullptr;
}
QObject *obj = component.beginCreate(effectiveContext);
@@ -1206,12 +1397,11 @@ ReturnedValue QtObject::method_createQmlObject(const FunctionObject *b, const Va
QQmlData::get(obj, true)->explicitIndestructibleSet = false;
QQmlData::get(obj)->indestructible = false;
-
- obj->setParent(parentArg);
+ obj->setParent(parent);
QList<QQmlPrivate::AutoParentFunction> functions = QQmlMetaType::parentFunctions();
- for (int ii = 0; ii < functions.count(); ++ii) {
- if (QQmlPrivate::Parented == functions.at(ii)(obj, parentArg))
+ for (int ii = 0; ii < functions.size(); ++ii) {
+ if (QQmlPrivate::Parented == functions.at(ii)(obj, parent))
break;
}
}
@@ -1219,16 +1409,16 @@ ReturnedValue QtObject::method_createQmlObject(const FunctionObject *b, const Va
if (component.isError()) {
ScopedValue v(scope, Error::create(scope.engine, component.errors()));
- return scope.engine->throwError(v);
+ scope.engine->throwError(v);
+ return nullptr;
}
Q_ASSERT(obj);
-
- return QV4::QObjectWrapper::wrap(scope.engine, obj);
+ return obj;
}
/*!
-\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.
@@ -1271,73 +1461,121 @@ 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()}.
*/
-ReturnedValue QtObject::method_createComponent(const FunctionObject *b, const Value *, const Value *argv, int argc)
-{
- QV4::Scope scope(b);
- if (argc < 1 || argc > 3)
- THROW_GENERIC_ERROR("Qt.createComponent(): Invalid arguments");
- QQmlEngine *engine = scope.engine->qmlEngine();
+/*!
+\since 6.5
+\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 QtQml
+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);
+}
- QQmlContextData *context = scope.engine->callingQmlContext();
- if (!context) {
- QQmlEngine *qmlEngine = scope.engine->qmlEngine();
- if (qmlEngine)
- context = QQmlContextData::get(QQmlEnginePrivate::get(qmlEngine)->rootContext);
+QQmlComponent *QtObject::createComponent(const QUrl &url, QQmlComponent::CompilationMode mode,
+ QObject *parent) const
+{
+ if (mode != QQmlComponent::Asynchronous && mode != QQmlComponent::PreferSynchronous) {
+ v4Engine()->throwError(QStringLiteral("Invalid compilation mode %1").arg(mode));
+ return nullptr;
}
- Q_ASSERT(context);
- QQmlContextData *effectiveContext = context;
- if (context->isPragmaLibraryContext)
- effectiveContext = nullptr;
-
- QString arg = argv[0].toQStringNoThrow();
- if (arg.isEmpty())
- RETURN_RESULT(QV4::Encode::null());
-
- QQmlComponent::CompilationMode compileMode = QQmlComponent::PreferSynchronous;
- QObject *parentArg = nullptr;
-
- int consumedCount = 1;
- if (argc > 1) {
- ScopedValue lastArg(scope, argv[argc-1]);
-
- // The second argument could be the mode enum
- if (argv[1].isInteger()) {
- int mode = argv[1].integerValue();
- if (mode != int(QQmlComponent::PreferSynchronous) && mode != int(QQmlComponent::Asynchronous))
- THROW_GENERIC_ERROR("Qt.createComponent(): Invalid arguments");
- compileMode = QQmlComponent::CompilationMode(mode);
- consumedCount += 1;
- } else {
- // The second argument could be the parent only if there are exactly two args
- if ((argc != 2) || !(lastArg->isObject() || lastArg->isNull()))
- THROW_GENERIC_ERROR("Qt.createComponent(): Invalid arguments");
- }
- if (consumedCount < argc) {
- if (lastArg->isObject()) {
- Scoped<QObjectWrapper> qobjectWrapper(scope, lastArg);
- if (qobjectWrapper)
- parentArg = qobjectWrapper->object();
- if (!parentArg)
- THROW_GENERIC_ERROR("Qt.createComponent(): Invalid parent object");
- } else if (lastArg->isNull()) {
- parentArg = nullptr;
- } else {
- THROW_GENERIC_ERROR("Qt.createComponent(): Invalid parent object");
- }
- }
+ if (url.isEmpty())
+ return nullptr;
+
+ QQmlEngine *engine = qmlEngine();
+ if (!engine)
+ return nullptr;
+
+ auto [context, effectiveContext] = getContexts();
+ if (!context)
+ return nullptr;
+
+ QQmlComponent *c = new QQmlComponent(engine, context->resolvedUrl(url), mode, parent);
+ QQmlComponentPrivate::get(c)->creationContext = effectiveContext;
+ QQmlData::get(c, true)->explicitIndestructibleSet = false;
+ QQmlData::get(c)->indestructible = false;
+ 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;
}
- QUrl url = context->resolvedUrl(QUrl(arg));
- QQmlComponent *c = new QQmlComponent(engine, url, compileMode, parentArg);
+ 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;
+}
- return QV4::QObjectWrapper::wrap(scope.engine, c);
+#if QT_CONFIG(translation)
+QString QtObject::uiLanguage() const
+{
+ if (const QJSEngine *e = jsEngine())
+ return e->uiLanguage();
+ return QString();
}
+void QtObject::setUiLanguage(const QString &uiLanguage)
+{
+ if (QJSEngine *e = jsEngine())
+ e->setUiLanguage(uiLanguage);
+}
+
+QBindable<QString> QtObject::uiLanguageBindable()
+{
+ if (QJSEngine *e = jsEngine())
+ return QBindable<QString>(&QJSEnginePrivate::get(e)->uiLanguage);
+ return QBindable<QString>();
+}
+#endif
+
#if QT_CONFIG(qml_locale)
/*!
\qmlmethod Qt::locale(name)
@@ -1359,30 +1597,32 @@ ReturnedValue QtObject::method_createComponent(const FunctionObject *b, const Va
\sa Locale
*/
-ReturnedValue QtObject::method_locale(const FunctionObject *b, const Value *, const Value *argv, int argc)
+QLocale QtObject::locale() const
{
- QV4::Scope scope(b);
- QString code;
- if (argc > 1)
- THROW_GENERIC_ERROR("locale() requires 0 or 1 argument");
- if (argc == 1 && !argv[0].isString())
- THROW_TYPE_ERROR_WITH_MESSAGE("locale(): argument (locale code) must be a string");
-
- if (argc == 1)
- code = argv[0].toQStringNoThrow();
+ return QLocale();
+}
- return QQmlLocale::locale(scope.engine, code);
+QLocale QtObject::locale(const QString &name) const
+{
+ return QLocale(name);
}
#endif
-void Heap::QQmlBindingFunction::init(const QV4::FunctionObject *bindingFunction)
+void Heap::QQmlBindingFunction::init(const QV4::JavaScriptFunctionObject *bindingFunction)
{
Scope scope(bindingFunction->engine());
ScopedContext context(scope, bindingFunction->scope());
- FunctionObject::init(context, bindingFunction->function());
+ JavaScriptFunctionObject::init(context, bindingFunction->function());
this->bindingFunction.set(internalClass->engine, bindingFunction->d());
}
+ReturnedValue QQmlBindingFunction::virtualCall(
+ const FunctionObject *f, const Value *, const Value *, int)
+{
+ // Mark this as a callable object, so that we can perform the binding magic on it.
+ return f->engine()->throwTypeError(QStringLiteral("Bindings must not be called directly."));
+}
+
QQmlSourceLocation QQmlBindingFunction::currentLocation() const
{
QV4::CppStackFrame *frame = engine()->currentStackFrame;
@@ -1435,68 +1675,54 @@ DEFINE_OBJECT_VTABLE(QQmlBindingFunction);
\since 5.0
*/
-ReturnedValue QtObject::method_binding(const FunctionObject *b, const Value *, const Value *argv, int argc)
-{
- QV4::Scope scope(b);
- if (argc != 1)
- THROW_GENERIC_ERROR("binding() requires 1 argument");
- const QV4::FunctionObject *f = argv[0].as<FunctionObject>();
- if (!f)
- THROW_TYPE_ERROR_WITH_MESSAGE("binding(): argument (binding expression) must be a function");
+QJSValue QtObject::binding(const QJSValue &function) const
+{
+ const QV4::JavaScriptFunctionObject *f
+ = QJSValuePrivate::asManagedType<JavaScriptFunctionObject>(&function);
+ QV4::ExecutionEngine *e = v4Engine();
+ if (!f) {
+ return QJSValuePrivate::fromReturnedValue(
+ e->throwError(
+ QStringLiteral(
+ "binding(): argument (binding expression) must be a function")));
+ }
- return Encode(scope.engine->memoryManager->allocate<QQmlBindingFunction>(f));
+ return QJSValuePrivate::fromReturnedValue(
+ Encode(e->memoryManager->allocate<QQmlBindingFunction>(f)));
}
-
-ReturnedValue QtObject::method_get_platform(const FunctionObject *b, const Value *thisObject, const Value *, int)
+void QtObject::callLater(QQmlV4FunctionPtr args)
{
- QV4::Scope scope(b);
- // ### inefficient. Should be just a value based getter
- const Object *o = thisObject->as<Object>();
- if (!o)
- THROW_TYPE_ERROR();
- const QtObject *qt = o->as<QtObject>();
- if (!qt)
- THROW_TYPE_ERROR();
+ m_engine->delayedCallQueue()->addUniquelyAndExecuteLater(m_engine, args);
+}
- if (!qt->d()->platform)
- // Only allocate a platform object once
- qt->d()->platform = new QQmlPlatform(scope.engine->jsEngine());
- return QV4::QObjectWrapper::wrap(scope.engine, qt->d()->platform);
+QQmlPlatform *QtObject::platform()
+{
+ if (!m_platform)
+ m_platform = new QQmlPlatform(this);
+ return m_platform;
}
-ReturnedValue QtObject::method_get_application(const FunctionObject *b, const Value *thisObject, const Value *, int)
+QQmlApplication *QtObject::application()
{
- QV4::Scope scope(b);
- // ### inefficient. Should be just a value based getter
- const Object *o = thisObject->as<Object>();
- if (!o)
- THROW_TYPE_ERROR();
- const QtObject *qt = o->as<QtObject>();
- if (!qt)
- THROW_TYPE_ERROR();
-
- if (!qt->d()->application)
+ if (!m_application)
// Only allocate an application object once
- qt->d()->application = QQml_guiProvider()->application(scope.engine->jsEngine());
+ m_application = QQml_guiProvider()->application(this);
- return QV4::QObjectWrapper::wrap(scope.engine, qt->d()->application);
+ return m_application;
}
-ReturnedValue QtObject::method_get_inputMethod(const FunctionObject *b, const Value *, const Value *, int)
+QObject *QtObject::inputMethod() const
{
- QObject *o = QQml_guiProvider()->inputMethod();
- return QV4::QObjectWrapper::wrap(b->engine(), o);
+ return QQml_guiProvider()->inputMethod();
}
-ReturnedValue QtObject::method_get_styleHints(const FunctionObject *b, const Value *, const Value *, int)
+QObject *QtObject::styleHints() const
{
- QObject *o = QQml_guiProvider()->styleHints();
- return QV4::QObjectWrapper::wrap(b->engine(), o);
+ return QQml_guiProvider()->styleHints();
}
-
void QV4::Heap::ConsoleObject::init()
{
Object::init();
@@ -1530,21 +1756,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');
@@ -1553,11 +1780,12 @@ static QString jsStack(QV4::ExecutionEngine *engine) {
return stack;
}
-static QString serializeArray(Object *array, ExecutionEngine *v4) {
+static QString serializeArray(Object *array, ExecutionEngine *v4, QSet<QV4::Heap::Object *> &alreadySeen) {
Scope scope(v4);
ScopedValue val(scope);
QString result;
+ alreadySeen.insert(array->d());
result += QLatin1Char('[');
const uint length = array->getLength();
for (uint i = 0; i < length; ++i) {
@@ -1565,19 +1793,22 @@ static QString serializeArray(Object *array, ExecutionEngine *v4) {
result += QLatin1Char(',');
val = array->get(i);
if (val->isManaged() && val->managed()->isArrayLike())
- result += serializeArray(val->objectValue(), v4);
+ if (!alreadySeen.contains(val->objectValue()->d()))
+ result += serializeArray(val->objectValue(), v4, alreadySeen);
+ else
+ result += QLatin1String("[Circular]");
else
result += val->toQStringNoThrow();
}
result += QLatin1Char(']');
-
+ alreadySeen.remove(array->d());
return result;
};
-static ReturnedValue writeToConsole(const FunctionObject *b, const Value *, const Value *argv, int argc,
+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;
@@ -1585,7 +1816,8 @@ static ReturnedValue writeToConsole(const FunctionObject *b, const Value *, cons
int start = 0;
if (argc > 0) {
if (const QObjectWrapper* wrapper = argv[0].as<QObjectWrapper>()) {
- if (QQmlLoggingCategory* category = qobject_cast<QQmlLoggingCategory*>(wrapper->object())) {
+ if (QQmlLoggingCategoryBase *category
+ = qobject_cast<QQmlLoggingCategoryBase *>(wrapper->object())) {
if (category->category())
loggingCategory = category->category();
else
@@ -1600,8 +1832,9 @@ static ReturnedValue writeToConsole(const FunctionObject *b, const Value *, cons
if (i != start)
result.append(QLatin1Char(' '));
+ QSet<QV4::Heap::Object *> alreadySeenElements;
if (argv[i].isManaged() && argv[i].managed()->isArrayLike())
- result.append(serializeArray(argv[i].objectValue(), v4));
+ result.append(serializeArray(argv[i].objectValue(), v4, alreadySeenElements));
else
result.append(argv[i].toQStringNoThrow());
}
@@ -1609,15 +1842,13 @@ static ReturnedValue writeToConsole(const FunctionObject *b, const Value *, cons
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->source().toUtf8();
- const QByteArray baFunction = frame->function().toUtf8();
- QMessageLogger logger(baSource.constData(), frame->lineNumber(), baFunction.constData(), loggingCategory->categoryName());
+ const QByteArray baSource = frame ? frame->source().toUtf8() : QByteArray();
+ const QByteArray baFunction = frame ? frame->function().toUtf8() : QByteArray();
+ QMessageLogger logger(baSource.constData(), frame ? frame->lineNumber() : 0,
+ baFunction.constData(), loggingCategory->categoryName());
switch (logType) {
case Log:
@@ -1645,22 +1876,22 @@ static ReturnedValue writeToConsole(const FunctionObject *b, const Value *, cons
DEFINE_OBJECT_VTABLE(ConsoleObject);
-ReturnedValue ConsoleObject::method_error(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
+ReturnedValue ConsoleObject::method_error(const FunctionObject *b, const Value *, const Value *argv, int argc)
{
- return writeToConsole(b, thisObject, argv, argc, Error);
+ return writeToConsole(b, argv, argc, Error);
}
-ReturnedValue ConsoleObject::method_log(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
+ReturnedValue ConsoleObject::method_log(const FunctionObject *b, const Value *, const Value *argv, int argc)
{
//console.log
//console.debug
//print
- return writeToConsole(b, thisObject, argv, argc, Log);
+ return writeToConsole(b, argv, argc, Log);
}
-ReturnedValue ConsoleObject::method_info(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
+ReturnedValue ConsoleObject::method_info(const FunctionObject *b, const Value *, const Value *argv, int argc)
{
- return writeToConsole(b, thisObject, argv, argc, Info);
+ return writeToConsole(b, argv, argc, Info);
}
ReturnedValue ConsoleObject::method_profile(const FunctionObject *b, const Value *, const Value *, int)
@@ -1767,14 +1998,14 @@ 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();
}
-ReturnedValue ConsoleObject::method_warn(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
+ReturnedValue ConsoleObject::method_warn(const FunctionObject *b, const Value *, const Value *argv, int argc)
{
- return writeToConsole(b, thisObject, argv, argc, Warn);
+ return writeToConsole(b, argv, argc, Warn);
}
ReturnedValue ConsoleObject::method_assert(const FunctionObject *b, const Value *, const Value *argv, int argc)
@@ -1805,17 +2036,15 @@ ReturnedValue ConsoleObject::method_assert(const FunctionObject *b, const Value
return QV4::Encode::undefined();
}
-ReturnedValue ConsoleObject::method_exception(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
+ReturnedValue ConsoleObject::method_exception(const FunctionObject *b, const Value *, const Value *argv, int argc)
{
QV4::Scope scope(b);
if (argc == 0)
THROW_GENERIC_ERROR("console.exception(): Missing argument");
- return writeToConsole(b, thisObject, argv, argc, Error, true);
+ return writeToConsole(b, argv, argc, Error, true);
}
-
-
void QV4::GlobalExtensions::init(Object *globalObject, QJSEngine::Extensions extensions)
{
ExecutionEngine *v4 = globalObject->engine();
@@ -1830,6 +2059,12 @@ void QV4::GlobalExtensions::init(Object *globalObject, QJSEngine::Extensions ext
globalObject->defineDefaultProperty(QStringLiteral("qsTrId"), QV4::GlobalExtensions::method_qsTrId);
globalObject->defineDefaultProperty(QStringLiteral("QT_TRID_NOOP"), QV4::GlobalExtensions::method_qsTrIdNoOp);
+ // Initialize the Qt global object for the uiLanguage property
+ ScopedString qtName(scope, v4->newString(QStringLiteral("Qt")));
+ ScopedObject qt(scope, globalObject->get(qtName));
+ if (!qt)
+ v4->createQtObject();
+
// string prototype extension
scope.engine->stringPrototype()->defineDefaultProperty(QStringLiteral("arg"), QV4::GlobalExtensions::method_string_arg);
#endif
@@ -1865,7 +2100,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)
{
@@ -1907,7 +2142,7 @@ ReturnedValue GlobalExtensions::method_qsTranslate(const FunctionObject *b, cons
}
/*!
- \qmlmethod string Qt::qsTranslateNoOp(string context, string sourceText, string disambiguation)
+ \qmlmethod string Qt::QT_TRANSLATE_NOOP(string context, string sourceText, string disambiguation)
Marks \a sourceText for dynamic translation in the given \a context; i.e, the stored \a sourceText
will not be altered.
@@ -1926,7 +2161,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)
{
@@ -1937,6 +2172,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)
@@ -1952,7 +2227,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)
{
@@ -1966,43 +2241,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 (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)
@@ -2015,7 +2257,7 @@ ReturnedValue GlobalExtensions::method_qsTr(const FunctionObject *b, const Value
}
/*!
- \qmlmethod string Qt::qsTrNoOp(string sourceText, string disambiguation)
+ \qmlmethod string Qt::QT_TR_NOOP(string sourceText, string disambiguation)
Marks \a sourceText for dynamic translation; i.e, the stored \a sourceText
will not be altered.
@@ -2034,7 +2276,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)
{
@@ -2072,7 +2314,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)
{
@@ -2096,7 +2338,7 @@ ReturnedValue GlobalExtensions::method_qsTrId(const FunctionObject *b, const Val
}
/*!
- \qmlmethod string Qt::qsTrIdNoOp(string id)
+ \qmlmethod string Qt::QT_TRID_NOOP(string id)
Marks \a id for dynamic translation.
@@ -2109,7 +2351,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)
{
@@ -2120,16 +2362,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);
@@ -2169,10 +2418,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/qqmlbuiltinfunctions_p.h b/src/qml/qml/qqmlbuiltinfunctions_p.h
new file mode 100644
index 0000000000..c2732e1aff
--- /dev/null
+++ b/src/qml/qml/qqmlbuiltinfunctions_p.h
@@ -0,0 +1,267 @@
+// 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
+
+//
+// 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/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>
+
+QT_BEGIN_NAMESPACE
+
+class Q_QML_EXPORT QtObject : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(QQmlApplication *application READ application CONSTANT)
+ Q_PROPERTY(QQmlPlatform *platform READ platform CONSTANT)
+ Q_PROPERTY(QObject *inputMethod READ inputMethod CONSTANT)
+ Q_PROPERTY(QObject *styleHints READ styleHints CONSTANT)
+
+#if QT_CONFIG(translation)
+ Q_PROPERTY(QString uiLanguage READ uiLanguage WRITE setUiLanguage BINDABLE uiLanguageBindable)
+#endif
+
+ QML_NAMED_ELEMENT(Qt)
+ QML_SINGLETON
+ QML_EXTENDED_NAMESPACE(Qt)
+
+ Q_CLASSINFO("QML.StrictArguments", "true")
+
+public:
+ enum LoadingMode { Asynchronous = 0, Synchronous = 1 };
+ Q_ENUM(LoadingMode);
+
+ static QtObject *create(QQmlEngine *, QJSEngine *jsEngine);
+
+ Q_INVOKABLE QJSValue include(const QString &url, const QJSValue &callback = QJSValue()) const;
+ Q_INVOKABLE bool isQtObject(const QJSValue &value) const;
+
+ Q_INVOKABLE QVariant color(const QString &name) const;
+ Q_INVOKABLE QVariant rgba(double r, double g, double b, double a = 1) const;
+ Q_INVOKABLE QVariant hsla(double h, double s, double l, double a = 1) const;
+ Q_INVOKABLE QVariant hsva(double h, double s, double v, double a = 1) const;
+ Q_INVOKABLE bool colorEqual(const QVariant &lhs, const QVariant &rhs) const;
+
+ Q_INVOKABLE QRectF rect(double x, double y, double width, double height) const;
+ Q_INVOKABLE QPointF point(double x, double y) const;
+ Q_INVOKABLE QSizeF size(double width, double height) const;
+ Q_INVOKABLE QVariant vector2d(double x, double y) const;
+ Q_INVOKABLE QVariant vector3d(double x, double y, double z) const;
+ Q_INVOKABLE QVariant vector4d(double x, double y, double z, double w) const;
+ Q_INVOKABLE QVariant quaternion(double scalar, double x, double y, double z) const;
+
+ Q_INVOKABLE QVariant matrix4x4() const;
+ Q_INVOKABLE QVariant 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;
+ Q_INVOKABLE QVariant matrix4x4(const QJSValue &value) const;
+
+ Q_INVOKABLE QVariant lighter(const QJSValue &color, double factor = 1.5) const;
+ Q_INVOKABLE QVariant darker(const QJSValue &color, double factor = 2.0) const;
+ 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(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(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(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(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 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;
+ Q_INVOKABLE QStringList fontFamilies() const;
+
+ Q_INVOKABLE QString md5(const QString &data) const;
+ Q_INVOKABLE QString btoa(const QString &data) const;
+ Q_INVOKABLE QString atob(const QString &data) const;
+
+ Q_INVOKABLE void quit() const;
+ Q_INVOKABLE void exit(int retCode) const;
+
+ Q_INVOKABLE QObject *createQmlObject(const QString &qml, QObject *parent,
+ const QUrl &url = QUrl(QStringLiteral("inline"))) const;
+ Q_INVOKABLE QQmlComponent *createComponent(const QUrl &url, QObject *parent) const;
+ Q_INVOKABLE QQmlComponent *createComponent(
+ const QUrl &url, QQmlComponent::CompilationMode mode = QQmlComponent::PreferSynchronous,
+ QObject *parent = nullptr) 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;
+
+ Q_INVOKABLE QJSValue binding(const QJSValue &function) const;
+ Q_INVOKABLE void callLater(QQmlV4FunctionPtr args);
+
+#if QT_CONFIG(translation)
+ QString uiLanguage() const;
+ void setUiLanguage(const QString &uiLanguage);
+ QBindable<QString> uiLanguageBindable();
+#endif
+
+ // Not const because created on first use, and parented to this.
+ QQmlPlatform *platform();
+ QQmlApplication *application();
+
+ QObject *inputMethod() const;
+ QObject *styleHints() const;
+
+private:
+ friend struct QV4::ExecutionEngine;
+
+ QtObject(QV4::ExecutionEngine *engine);
+
+ QQmlEngine *qmlEngine() const { return m_engine->qmlEngine(); }
+ 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;
+};
+
+namespace QV4 {
+
+namespace Heap {
+
+struct ConsoleObject : Object {
+ void init();
+};
+
+#define QQmlBindingFunctionMembers(class, Member) \
+ Member(class, Pointer, JavaScriptFunctionObject *, bindingFunction)
+DECLARE_HEAP_OBJECT(QQmlBindingFunction, JavaScriptFunctionObject) {
+ DECLARE_MARKOBJECTS(QQmlBindingFunction)
+ void init(const QV4::JavaScriptFunctionObject *bindingFunction);
+};
+
+}
+
+struct ConsoleObject : Object
+{
+ V4_OBJECT2(ConsoleObject, Object)
+
+ static ReturnedValue method_error(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
+ static ReturnedValue method_log(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
+ static ReturnedValue method_info(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
+ static ReturnedValue method_profile(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
+ static ReturnedValue method_profileEnd(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
+ static ReturnedValue method_time(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
+ static ReturnedValue method_timeEnd(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
+ static ReturnedValue method_count(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
+ static ReturnedValue method_trace(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
+ static ReturnedValue method_warn(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
+ static ReturnedValue method_assert(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
+ static ReturnedValue method_exception(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
+
+};
+
+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);
+ static ReturnedValue method_qsTrNoOp(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
+ static ReturnedValue method_qsTrId(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
+ static ReturnedValue method_qsTrIdNoOp(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
+#endif
+ static ReturnedValue method_gc(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
+
+ // on String:prototype
+ static ReturnedValue method_string_arg(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
+
+};
+
+struct QQmlBindingFunction : public QV4::JavaScriptFunctionObject
+{
+ V4_OBJECT2(QQmlBindingFunction, JavaScriptFunctionObject)
+
+ static ReturnedValue virtualCall(
+ const FunctionObject *f, const Value *thisObject, const Value *argv, int argc);
+
+ Heap::JavaScriptFunctionObject *bindingFunction() const { return d()->bindingFunction; }
+ QQmlSourceLocation currentLocation() const; // from caller stack trace
+};
+
+inline bool FunctionObject::isBinding() const
+{
+ return d()->vtable() == QQmlBindingFunction::staticVTable();
+}
+
+}
+
+QT_END_NAMESPACE
+
+#endif // QQMLBUILTINFUNCTIONS_P_H
diff --git a/src/qml/qml/qqmlcleanup.cpp b/src/qml/qml/qqmlcleanup.cpp
deleted file mode 100644
index 0d57ef5fe8..0000000000
--- a/src/qml/qml/qqmlcleanup.cpp
+++ /dev/null
@@ -1,116 +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 "qqmlcleanup_p.h"
-
-#include "qqmlengine_p.h"
-
-QT_BEGIN_NAMESPACE
-
-/*!
-\internal
-\class QQmlCleanup
-\brief The QQmlCleanup provides a callback when a QQmlEngine is deleted.
-
-Any object that needs cleanup to occur before the QQmlEngine's V8 engine is
-destroyed should inherit from QQmlCleanup. The clear() virtual method will be
-called by QQmlEngine just before it destroys the context.
-*/
-
-
-/*
-Create a QQmlCleanup that is not associated with any engine.
-*/
-QQmlCleanup::QQmlCleanup()
-: prev(nullptr), next(nullptr), engine(nullptr)
-{
-}
-
-/*!
-Create a QQmlCleanup for \a engine
-*/
-QQmlCleanup::QQmlCleanup(QQmlEngine *engine)
-: prev(nullptr), next(nullptr), engine(nullptr)
-{
- if (!engine)
- return;
-
- addToEngine(engine);
-}
-
-/*!
-Adds this object to \a engine's cleanup list. hasEngine() must be false
-before calling this method.
-*/
-void QQmlCleanup::addToEngine(QQmlEngine *engine)
-{
- Q_ASSERT(engine);
- Q_ASSERT(QQmlEnginePrivate::isEngineThread(engine));
-
- this->engine = engine;
-
- QQmlEnginePrivate *p = QQmlEnginePrivate::get(engine);
-
- if (p->cleanup) next = p->cleanup;
- p->cleanup = this;
- prev = &p->cleanup;
- if (next) next->prev = &next;
-}
-
-/*!
-\fn bool QQmlCleanup::hasEngine() const
-
-Returns true if this QQmlCleanup is associated with an engine, otherwise false.
-*/
-
-/*!
-\internal
-*/
-QQmlCleanup::~QQmlCleanup()
-{
- Q_ASSERT(!prev || engine);
- Q_ASSERT(!prev || QQmlEnginePrivate::isEngineThread(engine));
-
- if (prev) *prev = next;
- if (next) next->prev = prev;
- prev = nullptr;
- next = nullptr;
-}
-
-QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlcleanup_p.h b/src/qml/qml/qqmlcleanup_p.h
deleted file mode 100644
index 0e15c28b9d..0000000000
--- a/src/qml/qml/qqmlcleanup_p.h
+++ /dev/null
@@ -1,84 +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 QQMLCLEANUP_P_H
-#define QQMLCLEANUP_P_H
-
-#include <private/qtqmlglobal_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.
-//
-
-QT_BEGIN_NAMESPACE
-
-class QQmlEngine;
-
-class Q_QML_PRIVATE_EXPORT QQmlCleanup
-{
-public:
- QQmlCleanup();
- QQmlCleanup(QQmlEngine *);
- virtual ~QQmlCleanup();
-
- bool hasEngine() const { return prev != nullptr; }
- void addToEngine(QQmlEngine *);
-protected:
- virtual void clear() = 0;
-
-private:
- friend class QQmlEnginePrivate;
- QQmlCleanup **prev;
- QQmlCleanup *next;
-
- // Only used for asserts
- QQmlEngine *engine;
-};
-
-QT_END_NAMESPACE
-
-#endif // QQMLCLEANUP_P_H
-
diff --git a/src/qml/qml/qqmlcomponent.cpp b/src/qml/qml/qqmlcomponent.cpp
index 1d5f974d5c..e063418de4 100644
--- a/src/qml/qml/qqmlcomponent.cpp
+++ b/src/qml/qml/qqmlcomponent.cpp
@@ -1,55 +1,18 @@
-/****************************************************************************
-**
-** 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>
+#include <private/qqmlsourcecoordinate_p.h>
#include <private/qv4functionobject_p.h>
#include <private/qv4script_p.h>
@@ -63,12 +26,18 @@
#include <QStringList>
#include <QThreadStorage>
#include <QtCore/qdebug.h>
+#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")
+
QT_BEGIN_NAMESPACE
class QQmlComponentExtension : public QV4::ExecutionEngine::Deletable
@@ -155,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()
@@ -248,9 +218,8 @@ V4_DEFINE_EXTENSION(QQmlComponentExtension, componentExtension);
execute script code at startup, once the full QML environment has been
established.
- The corresponding handler is \c onCompleted. It can be declared on
- any object. The order of running the \c onCompleted handlers is
- undefined.
+ The \c onCompleted signal handler can be declared on any object. The order
+ of running the handlers is undefined.
\qml
Rectangle {
@@ -269,9 +238,8 @@ V4_DEFINE_EXTENSION(QQmlComponentExtension, componentExtension);
work done in response to the \l {completed}{completed()} signal, or other
imperative code in your application.
- The corresponding handler is \c onDestruction. It can be declared on
- any object. The order of running the \c onDestruction handlers is
- undefined.
+ The \c onDestruction signal handler can be declared on any object. The
+ order of running the handlers is undefined.
\qml
Rectangle {
@@ -282,7 +250,7 @@ V4_DEFINE_EXTENSION(QQmlComponentExtension, componentExtension);
}
\endqml
- \sa {Qt QML}
+ \sa {Qt Qml}
*/
/*!
@@ -302,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.
*/
@@ -313,7 +281,7 @@ void QQmlComponentPrivate::typeDataReady(QQmlTypeData *)
Q_ASSERT(typeData);
fromTypeData(typeData);
- typeData = nullptr;
+ typeData.reset();
progress = 1.0;
emit q->statusChanged(q->status());
@@ -332,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)
@@ -372,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, nullptr)) {
+ 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;
+
}
/*!
@@ -401,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.
*/
/*!
@@ -444,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;
@@ -483,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).
@@ -522,6 +578,10 @@ QQmlComponent::QQmlComponent(QQmlEngine *engine, QObject *parent)
{
Q_D(QQmlComponent);
d->engine = engine;
+ QObject::connect(engine, &QObject::destroyed, this, [d]() {
+ d->state.clear();
+ d->engine = nullptr;
+ });
}
/*!
@@ -555,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.
@@ -578,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);
}
/*!
@@ -590,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;
@@ -636,7 +730,7 @@ void QQmlComponent::setData(const QByteArray &data, const QUrl &url)
QQmlContext *QQmlComponent::creationContext() const
{
Q_D(const QQmlComponent);
- if(d->creationContext)
+ if (!d->creationContext.isNull())
return d->creationContext->asQQmlContext();
return qmlContext(this);
@@ -700,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;
}
@@ -712,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()) {
@@ -736,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;
}
/*!
@@ -755,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
{
@@ -763,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');
@@ -796,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.
@@ -815,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
@@ -837,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.
@@ -875,22 +999,34 @@ 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);
- QQmlContextData *context = QQmlContextData::get(publicContext);
-
- return d->beginCreate(context);
+ Q_ASSERT(context);
+ return d->beginCreate(QQmlContextData::get(context));
}
-QObject *
-QQmlComponentPrivate::beginCreate(QQmlContextData *context)
+QObject *QQmlComponentPrivate::beginCreate(QQmlRefPointer<QQmlContextData> context)
{
Q_Q(QQmlComponent);
+ auto cleanup = qScopeGuard([this] {
+ if (!state.errors.isEmpty() && lcQmlComponentGeneral().isDebugEnabled()) {
+ for (const auto &e : std::as_const(state.errors)) {
+ qCDebug(lcQmlComponentGeneral) << "QQmlComponent: " << e.error.toString();
+ }
+ }
+ });
if (!context) {
qWarning("QQmlComponent: Cannot create a component in a null context");
return nullptr;
@@ -901,16 +1037,21 @@ QQmlComponentPrivate::beginCreate(QQmlContextData *context)
return nullptr;
}
- if (context->engine != engine) {
+ if (context->engine() != engine) {
qWarning("QQmlComponent: Must create component in context from the same QQmlEngine");
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;
@@ -918,7 +1059,7 @@ QQmlComponentPrivate::beginCreate(QQmlContextData *context)
// 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;
}
@@ -927,21 +1068,59 @@ QQmlComponentPrivate::beginCreate(QQmlContextData *context)
enginePriv->inProgressCreations++;
state.errors.clear();
- state.completePending = true;
+ state.setCompletePending(true);
- enginePriv->referenceScarceResources();
QObject *rv = nullptr;
- state.creator.reset(new QQmlObjectCreator(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;
@@ -956,38 +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);
- QQmlContextData *creationContext = nullptr;
- state->creator.reset(new QQmlObjectCreator(deferredData->context->parent, deferredData->compilationUnit, creationContext));
+ 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--;
@@ -1000,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());
@@ -1037,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;
@@ -1069,30 +1254,39 @@ 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;
}
}
QQmlComponentAttached::QQmlComponentAttached(QObject *parent)
-: QObject(parent), prev(nullptr), next(nullptr)
+: QObject(parent), m_prev(nullptr), m_next(nullptr)
{
}
QQmlComponentAttached::~QQmlComponentAttached()
{
- if (prev) *prev = next;
- if (next) next->prev = prev;
- prev = nullptr;
- next = nullptr;
+ if (m_prev) *m_prev = m_next;
+ if (m_next) m_next->m_prev = m_prev;
+ m_prev = nullptr;
+ m_next = nullptr;
}
/*!
@@ -1108,30 +1302,138 @@ QQmlComponentAttached *QQmlComponent::qmlAttachedProperties(QObject *obj)
QQmlEnginePrivate *p = QQmlEnginePrivate::get(engine);
if (p->activeObjectCreator) { // XXX should only be allowed during begin
- a->add(p->activeObjectCreator->componentAttachment());
+ a->insertIntoList(p->activeObjectCreator->componentAttachment());
} else {
QQmlData *d = QQmlData::get(obj);
Q_ASSERT(d);
Q_ASSERT(d->context);
- a->add(&d->context->componentAttached);
+ d->context->addComponentAttached(a);
}
return a;
}
/*!
+ 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.
@@ -1139,24 +1441,23 @@ QQmlComponentAttached *QQmlComponent::qmlAttachedProperties(QObject *obj)
\sa QQmlIncubator
*/
-void QQmlComponent::create(QQmlIncubator &incubator, QQmlContext *context,
- QQmlContext *forContext)
+void QQmlComponent::create(QQmlIncubator &incubator, QQmlContext *context, QQmlContext *forContext)
{
Q_D(QQmlComponent);
if (!context)
context = d->engine->rootContext();
- QQmlContextData *contextData = QQmlContextData::get(context);
- QQmlContextData *forContextData = contextData;
- if (forContext) forContextData = QQmlContextData::get(forContext);
+ QQmlRefPointer<QQmlContextData> contextData = QQmlContextData::get(context);
+ QQmlRefPointer<QQmlContextData> forContextData =
+ forContext ? QQmlContextData::get(forContext) : contextData;
if (!contextData->isValid()) {
qWarning("QQmlComponent: Cannot create a component in an invalid context");
return;
}
- if (contextData->engine != d->engine) {
+ if (contextData->engine() != d->engine) {
qWarning("QQmlComponent: Must create component in context from the same QQmlEngine");
return;
}
@@ -1169,6 +1470,14 @@ void QQmlComponent::create(QQmlIncubator &incubator, QQmlContext *context,
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;
@@ -1180,8 +1489,7 @@ void QQmlComponent::create(QQmlIncubator &incubator, QQmlContext *context,
}
/*!
- 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
@@ -1210,8 +1518,8 @@ void QQmlComponentPrivate::incubateObject(
QQmlIncubator *incubationTask,
QQmlComponent *component,
QQmlEngine *engine,
- QQmlContextData *context,
- QQmlContextData *forContext)
+ const QQmlRefPointer<QQmlContextData> &context,
+ const QQmlRefPointer<QQmlContextData> &forContext)
{
QQmlIncubatorPrivate *incubatorPriv = QQmlIncubatorPrivate::get(incubationTask);
QQmlEnginePrivate *enginePriv = QQmlEnginePrivate::get(engine);
@@ -1220,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);
@@ -1234,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, QQmlQPointer<QObject>, parent)
+ 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();
@@ -1261,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);
};
}
@@ -1302,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;
@@ -1312,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.
@@ -1346,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.
@@ -1359,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);
@@ -1370,7 +1688,8 @@ void QQmlComponentPrivate::setInitialProperties(QV4::ExecutionEngine *engine, QV
if (engine->hasException)
return;
- QV4::ScopedStackFrame frame(scope, qmlContext->d());
+ // js modules (mjs) have no qmlContext
+ QV4::ScopedStackFrame frame(scope, qmlContext ? qmlContext : engine->scriptContext());
while (1) {
name = it.nextPropertyNameAsString(val);
@@ -1379,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) {
- engine->hasException = false;
+ if (engine->hasException) {
+ qmlWarning(createdComponent, engine->catchExceptionAsQmlError());
+ continue;
+ }
+ 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;
}
- name = engine->newString(properties.last());
+ const QString lastProperty = properties.last();
+ name = engine->newString(lastProperty);
object->put(name, val);
if (engine->hasException) {
- engine->hasException = false;
+ 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;
@@ -1424,20 +1755,27 @@ QQmlError QQmlComponentPrivate::unsetRequiredPropertyToQQmlError(const RequiredP
}
error.setDescription(description);
error.setUrl(unsetRequiredProperty.fileUrl);
- error.setLine(unsetRequiredProperty.location.line);
- error.setColumn(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);
@@ -1476,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);
@@ -1497,9 +1837,28 @@ void QQmlComponent::createObject(QQmlV4Function *args)
args->setReturnValue(object->asReturnedValue());
}
+#endif
/*!
- \qmlmethod object Component::incubateObject(Item parent, object properties, enumeration mode)
+ \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(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.
@@ -1521,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.
@@ -1556,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);
@@ -1603,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;
@@ -1618,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);
@@ -1626,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)
@@ -1704,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);
@@ -1717,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();
@@ -1763,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 cb5d5a787c..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_ATTACHED(QQmlComponentAttached)
- Q_CLASSINFO("QML.Builtin", "QML")
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 a919eb45c0..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,17 +18,15 @@
#include "qqmlcomponent.h"
#include "qqmlengine_p.h"
-#include "qqmltypeloader_p.h"
-#include <private/qbitfield_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>
#include <QtCore/QString>
#include <QtCore/QStringList>
#include <QtCore/QList>
+#include <QtCore/qtclasshelpermacros.h>
#include <private/qobject_p.h>
@@ -74,28 +36,31 @@ 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(QQmlContextData *);
+ 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(
QQmlIncubator *incubationTask,
QQmlComponent *component,
QQmlEngine *engine,
- QQmlContextData *context,
- QQmlContextData *forContext);
+ const QQmlRefPointer<QQmlContextData> &context,
+ const QQmlRefPointer<QQmlContextData> &forContext);
QQmlRefPointer<QQmlTypeData> typeData;
void typeDataReady(QQmlTypeData *) override;
@@ -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..439c7d62d4
--- /dev/null
+++ b/src/qml/qml/qqmlcomponentandaliasresolver_p.h
@@ -0,0 +1,484 @@
+// 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.
+
+class QQmlComponentAndAliasResolverBase
+{
+ Q_DECLARE_TR_FUNCTIONS(QQmlComponentAndAliasResolverBase)
+};
+
+template<typename ObjectContainer>
+class QQmlComponentAndAliasResolver : public QQmlComponentAndAliasResolverBase
+{
+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, QQmlComponentAndAliasResolverBase::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, QQmlComponentAndAliasResolverBase::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, QQmlComponentAndAliasResolverBase::tr("Component objects cannot declare new functions."));
+ if (obj->propertyCount() > 0 || obj->aliasCount() > 0)
+ return error(obj, QQmlComponentAndAliasResolverBase::tr("Component objects cannot declare new properties."));
+ if (obj->signalCount() > 0)
+ return error(obj, QQmlComponentAndAliasResolverBase::tr("Component objects cannot declare new signals."));
+
+ if (obj->bindingCount() == 0)
+ return error(obj, QQmlComponentAndAliasResolverBase::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, QQmlComponentAndAliasResolverBase::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, QQmlComponentAndAliasResolverBase::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, QQmlComponentAndAliasResolverBase::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, QQmlComponentAndAliasResolverBase::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 8ecd9da17d..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,44 +16,53 @@
//
#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
public:
QQmlComponentAttached(QObject *parent = nullptr);
~QQmlComponentAttached();
- void add(QQmlComponentAttached **a) {
- prev = a; next = *a; *a = this;
- if (next) next->prev = &next;
+ void insertIntoList(QQmlComponentAttached **listHead)
+ {
+ m_prev = listHead;
+ m_next = *listHead;
+ *listHead = this;
+ if (m_next)
+ m_next->m_prev = &m_next;
}
- void rem() {
- if (next) next->prev = prev;
- *prev = next;
- next = nullptr; prev = nullptr;
+
+ void removeFromList()
+ {
+ *m_prev = m_next;
+ if (m_next)
+ m_next->m_prev = m_prev;
+ m_next = nullptr;
+ m_prev = nullptr;
}
- QQmlComponentAttached **prev;
- QQmlComponentAttached *next;
+
+ QQmlComponentAttached *next() const { return m_next; }
Q_SIGNALS:
void completed();
void destruction();
private:
- friend class QQmlContextData;
+ QQmlComponentAttached **m_prev;
+ QQmlComponentAttached *m_next;
};
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 254b6cc3db..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"
@@ -55,40 +18,49 @@
QT_BEGIN_NAMESPACE
-QQmlContextPrivate::QQmlContextPrivate()
-: data(nullptr), notifyIndex(-1)
-{
-}
-
/*!
\class QQmlContext
\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
@@ -97,59 +69,17 @@ QQmlContextPrivate::QQmlContextPrivate()
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);
+ 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.
- context1->setContextProperty("a", 12);
- context1->setContextProperty("b", 12);
-
- context2->setContextProperty("b", 15);
- \endcode
-
- 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}
@@ -157,13 +87,8 @@ QQmlContextPrivate::QQmlContextPrivate()
/*! \internal */
QQmlContext::QQmlContext(QQmlEngine *e, bool)
-: QObject(*(new QQmlContextPrivate))
+ : QObject(*(new QQmlContextPrivate(this, QQmlRefPointer<QQmlContextData>(), e)))
{
- Q_D(QQmlContext);
- d->data = new QQmlContextData(this);
- ++d->data->refCount;
-
- d->data->engine = e;
}
/*!
@@ -171,13 +96,10 @@ QQmlContext::QQmlContext(QQmlEngine *e, bool)
QObject \a parent.
*/
QQmlContext::QQmlContext(QQmlEngine *engine, QObject *parent)
-: QObject(*(new QQmlContextPrivate), parent)
+ : QObject(*(new QQmlContextPrivate(this, engine
+ ? QQmlContextData::get(engine->rootContext())
+ : QQmlRefPointer<QQmlContextData>())), parent)
{
- Q_D(QQmlContext);
- d->data = new QQmlContextData(this);
- ++d->data->refCount;
-
- d->data->setParent(engine?QQmlContextData::get(engine->rootContext()):nullptr);
}
/*!
@@ -185,24 +107,18 @@ QQmlContext::QQmlContext(QQmlEngine *engine, QObject *parent)
QObject \a parent.
*/
QQmlContext::QQmlContext(QQmlContext *parentContext, QObject *parent)
-: QObject(*(new QQmlContextPrivate), parent)
+ : QObject(*(new QQmlContextPrivate(this, parentContext
+ ? QQmlContextData::get(parentContext)
+ : QQmlRefPointer<QQmlContextData>())), parent)
{
- Q_D(QQmlContext);
- d->data = new QQmlContextData(this);
- ++d->data->refCount;
-
- d->data->setParent(parentContext?QQmlContextData::get(parentContext):nullptr);
}
/*!
\internal
*/
-QQmlContext::QQmlContext(QQmlContextData *data)
-: QObject(*(new QQmlContextPrivate), nullptr)
+QQmlContext::QQmlContext(QQmlContextPrivate &dd, QObject *parent)
+ : QObject(dd, parent)
{
- Q_D(QQmlContext);
- d->data = data;
- // don't add a refcount here, as the data owns this context
}
/*!
@@ -215,10 +131,7 @@ QQmlContext::QQmlContext(QQmlContextData *data)
QQmlContext::~QQmlContext()
{
Q_D(QQmlContext);
-
- d->data->publicContext = nullptr;
- if (!--d->data->refCount)
- d->data->destroy();
+ d->m_data->clearPublicContext();
}
/*!
@@ -230,92 +143,104 @@ QQmlContext::~QQmlContext()
bool QQmlContext::isValid() const
{
Q_D(const QQmlContext);
- return d->data && d->data->isValid();
+ return d->m_data->isValid();
}
/*!
- 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
{
Q_D(const QQmlContext);
- return d->data->engine;
+ return d->m_data->engine();
}
/*!
- 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
{
Q_D(const QQmlContext);
- return d->data->parent?d->data->parent->asQQmlContext():nullptr;
+
+ if (QQmlRefPointer<QQmlContextData> parent = d->m_data->parent())
+ return parent->asQQmlContext();
+ return nullptr;
}
/*!
- 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
{
Q_D(const QQmlContext);
- return d->data->contextObject;
+ return d->m_data->contextObject();
}
/*!
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)
{
Q_D(QQmlContext);
- QQmlContextData *data = d->data;
+ QQmlRefPointer<QQmlContextData> data = d->m_data;
- if (data->isInternal) {
+ if (data->isInternal()) {
qWarning("QQmlContext: Cannot set context object for internal context.");
return;
}
- if (!isValid()) {
+ if (!data->isValid()) {
qWarning("QQmlContext: Cannot set context object on invalid context.");
return;
}
- data->contextObject = object;
+ data->setContextObject(object);
data->refreshExpressions();
}
/*!
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)
{
Q_D(QQmlContext);
- if (d->notifyIndex == -1)
- d->notifyIndex = QMetaObjectPrivate::absoluteSignalCount(&QQmlContext::staticMetaObject);
+ if (d->notifyIndex() == -1)
+ d->setNotifyIndex(QMetaObjectPrivate::absoluteSignalCount(&QQmlContext::staticMetaObject));
- QQmlContextData *data = d->data;
+ QQmlRefPointer<QQmlContextData> data = d->m_data;
- if (data->isInternal) {
+ if (data->isInternal()) {
qWarning("QQmlContext: Cannot set property on internal context.");
return;
}
- if (!isValid()) {
+ if (!data->isValid()) {
qWarning("QQmlContext: Cannot set property on invalid context.");
return;
}
- QV4::IdentifierHash &properties = data->detachedPropertyNames();
- int idx = properties.value(name);
- if (idx == -1) {
- properties.add(name, data->idValueCount + d->propertyValues.count());
- d->propertyValues.append(value);
+ 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) {
+ data->addPropertyNameAndIndex(name, data->numIdValues() + d->numPropertyValues());
+ d->appendPropertyValue(value);
data->refreshExpressions();
} else {
- d->propertyValues[idx] = value;
- QMetaObject::activate(this, d->notifyIndex, idx, nullptr);
+ d->setPropertyValue(idx, value);
+ QMetaObject::activate(this, d->notifyIndex(), idx, nullptr);
}
if (auto *obj = qvariant_cast<QObject *>(value)) {
@@ -329,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)
{
@@ -344,26 +272,24 @@ 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 QVector<PropertyPair> &properties)
+void QQmlContext::setContextProperties(const QList<PropertyPair> &properties)
{
Q_D(const QQmlContext);
- QQmlContextData *data = d->data;
-
- QQmlJavaScriptExpression *expressions = data->expressions;
- QQmlContextData *childContexts = data->childContexts;
-
- data->expressions = nullptr;
- data->childContexts = nullptr;
+ QQmlRefPointer<QQmlContextData> data = d->m_data;
+ QQmlJavaScriptExpression *expressions = data->takeExpressions();
+ QQmlRefPointer<QQmlContextData> childContexts = data->takeChildContexts();
for (const auto &property : properties)
setContextProperty(property.name, property.value);
- data->expressions = expressions;
- data->childContexts = childContexts;
-
+ data->setExpressions(expressions);
+ data->setChildContexts(childContexts);
data->refreshExpressions();
}
@@ -379,97 +305,121 @@ void QQmlContext::setContextProperties(const QVector<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;
-
- QQmlContextData *data = d->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 (data->contextObject) {
- 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);
+ if (QObject *obj = data->contextObject()) {
+ 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->propertyValues.count())
- value = QVariant::fromValue(data->idValues[idx - d->propertyValues.count()].data());
+ if (idx >= d->numPropertyValues())
+ return QVariant::fromValue(data->idValue(idx - d->numPropertyValues()));
else
- value = d->propertyValues[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.
+
+ 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.
-If the object has multiple names, the first is returned.
+ \sa contextProperty(), objectForName()
*/
-QString QQmlContext::nameForObject(QObject *object) const
+QString QQmlContext::nameForObject(const QObject *object) const
{
Q_D(const QQmlContext);
- return d->data->findObjectId(object);
+ return d->m_data->findObjectId(object);
}
/*!
- Resolves the URL \a src relative to the URL of the
- containing component.
+ \since 6.2
- \sa QQmlEngine::baseUrl(), setBaseUrl()
+ 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()
*/
-QUrl QQmlContext::resolvedUrl(const QUrl &src)
+QObject *QQmlContext::objectForName(const QString &name) const
{
- Q_D(QQmlContext);
- return d->data->resolvedUrl(src);
-}
+ Q_D(const QQmlContext);
-QUrl QQmlContextData::resolvedUrl(const QUrl &src)
-{
- QUrl resolved;
- if (src.isRelative() && !src.isEmpty()) {
- QQmlContextData *ctxt = this;
- do {
- if (ctxt->url().isValid())
- break;
- else
- ctxt = ctxt->parent;
- } while (ctxt);
-
- if (ctxt)
- resolved = ctxt->url().resolved(src);
- else if (engine)
- resolved = engine->baseUrl().resolved(src);
- } else {
- resolved = src;
+ 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 (resolved.isEmpty()) //relative but no ctxt
- return resolved;
+ if (QObject *obj = data->contextObject()) {
+ QVariant result;
+ if (readObjectProperty(data, obj, name, &result))
+ return qvariant_cast<QObject *>(result);
+ }
- if (engine && engine->urlInterceptor())
- resolved = engine->urlInterceptor()->intercept(resolved, QQmlAbstractUrlInterceptor::UrlString);
- return resolved;
+ return nullptr;
}
+/*!
+ Resolves the URL \a src relative to the URL of the
+ containing component.
+
+ \sa QQmlEngine::baseUrl(), setBaseUrl()
+*/
+QUrl QQmlContext::resolvedUrl(const QUrl &src) const
+{
+ Q_D(const QQmlContext);
+ return d->m_data->resolvedUrl(src);
+}
/*!
Explicitly sets the url resolvedUrl() will use for relative references to \a baseUrl.
@@ -482,9 +432,8 @@ QUrl QQmlContextData::resolvedUrl(const QUrl &src)
void QQmlContext::setBaseUrl(const QUrl &baseUrl)
{
Q_D(QQmlContext);
-
- d->data->baseUrl = baseUrl;
- d->data->baseUrlString = baseUrl.toString();
+ d->m_data->setBaseUrl(baseUrl);
+ d->m_data->setBaseUrlString(baseUrl.toString());
}
/*!
@@ -494,410 +443,76 @@ void QQmlContext::setBaseUrl(const QUrl &baseUrl)
QUrl QQmlContext::baseUrl() const
{
Q_D(const QQmlContext);
- const QQmlContextData* data = d->data;
- while (data && data->url().isEmpty())
- data = data->parent;
+ return d->m_data->baseUrl();
+}
- if (data)
- return data->url();
- else
- return QUrl();
+/*!
+ * \internal
+ */
+QJSValue QQmlContext::importedScript(const QString &name) const
+{
+ Q_D(const QQmlContext);
+
+ 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))
+ : QJSValue(QJSValue::UndefinedValue);
}
-int QQmlContextPrivate::context_count(QQmlListProperty<QObject> *prop)
+qsizetype QQmlContextPrivate::context_count(QQmlListProperty<QObject> *prop)
{
QQmlContext *context = static_cast<QQmlContext*>(prop->object);
QQmlContextPrivate *d = QQmlContextPrivate::get(context);
int contextProperty = (int)(quintptr)prop->data;
- if (d->propertyValues.at(contextProperty).userType() != qMetaTypeId<QList<QObject*> >()) {
+ if (d->propertyValue(contextProperty).userType() != qMetaTypeId<QList<QObject*> >())
return 0;
- } else {
- return ((const QList<QObject> *)d->propertyValues.at(contextProperty).constData())->count();
- }
+ else
+ return ((const QList<QObject> *)d->propertyValue(contextProperty).constData())->size();
}
-QObject *QQmlContextPrivate::context_at(QQmlListProperty<QObject> *prop, int index)
+QObject *QQmlContextPrivate::context_at(QQmlListProperty<QObject> *prop, qsizetype index)
{
QQmlContext *context = static_cast<QQmlContext*>(prop->object);
QQmlContextPrivate *d = QQmlContextPrivate::get(context);
int contextProperty = (int)(quintptr)prop->data;
- if (d->propertyValues.at(contextProperty).userType() != qMetaTypeId<QList<QObject*> >()) {
+ if (d->propertyValue(contextProperty).userType() != qMetaTypeId<QList<QObject*> >())
return nullptr;
- } else {
- return ((const QList<QObject*> *)d->propertyValues.at(contextProperty).constData())->at(index);
- }
+ else
+ return ((const QList<QObject*> *)d->propertyValue(contextProperty).constData())->at(index);
}
void QQmlContextPrivate::dropDestroyedQObject(const QString &name, QObject *destroyed)
{
- const int idx = data->propertyNames().value(name);
- Q_ASSERT(idx >= 0);
- if (qvariant_cast<QObject *>(propertyValues[idx]) != destroyed)
+ if (!m_data->isValid())
return;
- propertyValues[idx] = QVariant::fromValue<QObject *>(nullptr);
- QMetaObject::activate(q_func(), notifyIndex, idx, nullptr);
-}
-
-
-QQmlContextData::QQmlContextData()
- : QQmlContextData(nullptr)
-{
-}
-
-QQmlContextData::QQmlContextData(QQmlContext *ctxt)
- : engine(nullptr), isInternal(false), isJSContext(false),
- isPragmaLibraryContext(false), unresolvedNames(false), hasEmittedDestruction(false), isRootObjectInCreation(false),
- stronglyReferencedByParent(false), hasExtraObject(false), publicContext(ctxt), incubator(nullptr), componentObjectIndex(-1),
- contextObject(nullptr), nextChild(nullptr), prevChild(nullptr),
- expressions(nullptr), contextObjects(nullptr), idValues(nullptr), idValueCount(0),
- componentAttached(nullptr)
-{
-}
-
-void QQmlContextData::emitDestruction()
-{
- if (!hasEmittedDestruction) {
- hasEmittedDestruction = true;
-
- // Emit the destruction signal - must be emitted before invalidate so that the
- // context is still valid if bindings or resultant expression evaluation requires it
- if (engine) {
- while (componentAttached) {
- QQmlComponentAttached *a = componentAttached;
- componentAttached = a->next;
- if (componentAttached) componentAttached->prev = &componentAttached;
-
- a->next = nullptr;
- a->prev = nullptr;
-
- emit a->destruction();
- }
-
- QQmlContextData * child = childContexts;
- while (child) {
- child->emitDestruction();
- child = child->nextChild;
- }
- }
- }
-}
-
-void QQmlContextData::invalidate()
-{
- emitDestruction();
-
- while (childContexts) {
- Q_ASSERT(childContexts != this);
- if (childContexts->stronglyReferencedByParent && !--childContexts->refCount)
- childContexts->destroy();
- else
- childContexts->invalidate();
- }
-
- if (prevChild) {
- *prevChild = nextChild;
- if (nextChild) nextChild->prevChild = prevChild;
- nextChild = nullptr;
- prevChild = nullptr;
- }
-
- importedScripts.clear();
-
- engine = nullptr;
- parent = nullptr;
-}
-
-void QQmlContextData::clearContextRecursively()
-{
- clearContext();
-
- for (auto ctxIt = childContexts; ctxIt; ctxIt = ctxIt->nextChild)
- ctxIt->clearContextRecursively();
-}
-
-void QQmlContextData::clearContext()
-{
- emitDestruction();
-
- QQmlJavaScriptExpression *expression = expressions;
- while (expression) {
- QQmlJavaScriptExpression *nextExpression = expression->m_nextExpression;
-
- expression->m_prevExpression = nullptr;
- expression->m_nextExpression = nullptr;
-
- expression->setContext(nullptr);
-
- expression = nextExpression;
- }
- expressions = nullptr;
-}
-
-void QQmlContextData::destroy()
-{
- Q_ASSERT(refCount == 0);
- linkedContext = nullptr;
-
- // avoid recursion
- ++refCount;
- if (engine)
- invalidate();
-
- Q_ASSERT(refCount == 1);
- clearContext();
- Q_ASSERT(refCount == 1);
-
- while (contextObjects) {
- QQmlData *co = contextObjects;
- contextObjects = contextObjects->nextContextObject;
-
- if (co->context == this)
- co->context = nullptr;
- co->outerContext = nullptr;
- co->nextContextObject = nullptr;
- co->prevContextObject = nullptr;
- }
- Q_ASSERT(refCount == 1);
-
- QQmlGuardedContextData *contextGuard = contextGuards;
- while (contextGuard) {
- QQmlGuardedContextData *next = contextGuard->m_next;
- contextGuard->m_next = nullptr;
- contextGuard->m_prev = nullptr;
- contextGuard->m_contextData = nullptr;
- contextGuard = next;
- }
- contextGuards = nullptr;
- Q_ASSERT(refCount == 1);
-
- delete [] idValues;
- idValues = nullptr;
-
- Q_ASSERT(refCount == 1);
- if (publicContext) {
- // the QQmlContext destructor will remove one ref again
- ++refCount;
- delete publicContext;
- }
-
- Q_ASSERT(refCount == 1);
- --refCount;
- Q_ASSERT(refCount == 0);
-
- delete this;
-}
-
-void QQmlContextData::setParent(QQmlContextData *p, bool stronglyReferencedByParent)
-{
- if (p == parent)
+ const int idx = m_data->propertyIndex(name);
+ Q_ASSERT(idx >= 0);
+ if (qvariant_cast<QObject *>(propertyValue(idx)) != destroyed)
return;
- if (p) {
- Q_ASSERT(!parent);
- parent = p;
- this->stronglyReferencedByParent = stronglyReferencedByParent;
- if (stronglyReferencedByParent)
- ++refCount; // balanced in QQmlContextData::invalidate()
- engine = p->engine;
- nextChild = p->childContexts;
- if (nextChild) nextChild->prevChild = &nextChild;
- prevChild = &p->childContexts;
- p->childContexts = this;
- }
-}
-
-void QQmlContextData::refreshExpressionsRecursive(QQmlJavaScriptExpression *expression)
-{
- QQmlJavaScriptExpression::DeleteWatcher w(expression);
-
- if (expression->m_nextExpression)
- refreshExpressionsRecursive(expression->m_nextExpression);
-
- if (!w.wasDeleted())
- expression->refresh();
-}
-
-QQmlContextData::~QQmlContextData()
-{
-}
-
-static inline bool expressions_to_run(QQmlContextData *ctxt, bool isGlobalRefresh)
-{
- return ctxt->expressions && (!isGlobalRefresh || ctxt->unresolvedNames);
-}
-
-void QQmlContextData::refreshExpressionsRecursive(bool isGlobal)
-{
- // For efficiency, we try and minimize the number of guards we have to create
- if (expressions_to_run(this, isGlobal) && (nextChild || childContexts)) {
- QQmlGuardedContextData guard(this);
-
- if (childContexts)
- childContexts->refreshExpressionsRecursive(isGlobal);
-
- if (guard.isNull()) return;
-
- if (nextChild)
- nextChild->refreshExpressionsRecursive(isGlobal);
-
- if (guard.isNull()) return;
-
- if (expressions_to_run(this, isGlobal))
- refreshExpressionsRecursive(expressions);
-
- } else if (expressions_to_run(this, isGlobal)) {
-
- refreshExpressionsRecursive(expressions);
-
- } else if (nextChild && childContexts) {
- QQmlGuardedContextData guard(this);
-
- childContexts->refreshExpressionsRecursive(isGlobal);
-
- if (!guard.isNull() && nextChild)
- nextChild->refreshExpressionsRecursive(isGlobal);
-
- } else if (nextChild) {
-
- nextChild->refreshExpressionsRecursive(isGlobal);
-
- } else if (childContexts) {
-
- childContexts->refreshExpressionsRecursive(isGlobal);
-
- }
-}
-
-// Refreshes all expressions that could possibly depend on this context. Refreshing flushes all
-// context-tree dependent caches in the expressions, and should occur every time the context tree
-// *structure* (not values) changes.
-void QQmlContextData::refreshExpressions()
-{
- bool isGlobal = (parent == nullptr);
-
- // For efficiency, we try and minimize the number of guards we have to create
- if (expressions_to_run(this, isGlobal) && childContexts) {
- QQmlGuardedContextData guard(this);
-
- childContexts->refreshExpressionsRecursive(isGlobal);
-
- if (!guard.isNull() && expressions_to_run(this, isGlobal))
- refreshExpressionsRecursive(expressions);
-
- } else if (expressions_to_run(this, isGlobal)) {
-
- refreshExpressionsRecursive(expressions);
-
- } else if (childContexts) {
-
- childContexts->refreshExpressionsRecursive(isGlobal);
-
- }
-}
-
-void QQmlContextData::addObject(QQmlData *data)
-{
- if (data->outerContext) {
- if (data->nextContextObject)
- data->nextContextObject->prevContextObject = data->prevContextObject;
- if (data->prevContextObject)
- *data->prevContextObject = data->nextContextObject;
- else if (data->outerContext->contextObjects == data)
- data->outerContext->contextObjects = data->nextContextObject;
- }
-
- data->outerContext = this;
-
- data->nextContextObject = contextObjects;
- if (data->nextContextObject)
- data->nextContextObject->prevContextObject = &data->nextContextObject;
- data->prevContextObject = &contextObjects;
- contextObjects = data;
-}
-
-void QQmlContextData::setIdProperty(int idx, QObject *obj)
-{
- idValues[idx] = obj;
- idValues[idx].context = this;
-}
-
-QString QQmlContextData::findObjectId(const QObject *obj) const
-{
- const QV4::IdentifierHash &properties = propertyNames();
- if (propertyNameCache.isEmpty())
- return QString();
-
- for (int ii = 0; ii < idValueCount; ii++) {
- if (idValues[ii] == obj)
- return properties.findId(ii);
- }
-
- if (publicContext) {
- QQmlContextPrivate *p = QQmlContextPrivate::get(publicContext);
- for (int ii = 0; ii < p->propertyValues.count(); ++ii)
- if (p->propertyValues.at(ii) == QVariant::fromValue(const_cast<QObject *>(obj)))
- return properties.findId(ii);
- }
-
- if (linkedContext)
- return linkedContext->findObjectId(obj);
- return QString();
-}
-
-QQmlContext *QQmlContextData::asQQmlContext()
-{
- if (!publicContext)
- publicContext = new QQmlContext(this);
- return publicContext;
-}
-
-QQmlContextPrivate *QQmlContextData::asQQmlContextPrivate()
-{
- return QQmlContextPrivate::get(asQQmlContext());
-}
-
-void QQmlContextData::initFromTypeCompilationUnit(const QQmlRefPointer<QV4::ExecutableCompilationUnit> &unit, int subComponentIndex)
-{
- typeCompilationUnit = unit;
- componentObjectIndex = subComponentIndex == -1 ? /*root object*/0 : subComponentIndex;
- Q_ASSERT(!idValues);
- idValueCount = typeCompilationUnit->objectAt(componentObjectIndex)->nNamedObjectsInComponent;
- idValues = new ContextGuard[idValueCount];
-}
-
-const QV4::IdentifierHash &QQmlContextData::propertyNames() const
-{
- if (propertyNameCache.isEmpty()) {
- if (typeCompilationUnit)
- propertyNameCache = typeCompilationUnit->namedObjectsPerComponent(componentObjectIndex);
- else
- propertyNameCache = QV4::IdentifierHash(engine->handle());
- }
- return propertyNameCache;
-}
-
-QV4::IdentifierHash &QQmlContextData::detachedPropertyNames()
-{
- propertyNames();
- propertyNameCache.detach();
- return propertyNameCache;
+ setPropertyValue(idx, QVariant::fromValue<QObject *>(nullptr));
+ QMetaObject::activate(q_func(), notifyIndex(), idx, nullptr);
}
-QUrl QQmlContextData::url() const
+void QQmlContextPrivate::emitDestruction()
{
- if (typeCompilationUnit)
- return typeCompilationUnit->finalUrl();
- return baseUrl;
+ m_data->emitDestruction();
}
-QString QQmlContextData::urlString() const
+// m_data is owned by the public context. When the public context is reset to nullptr, it will be
+// deref'd. It's OK to pass a half-created publicContext here. We will not dereference it during
+// construction.
+QQmlContextPrivate::QQmlContextPrivate(
+ QQmlContext *publicContext, const QQmlRefPointer<QQmlContextData> &parent,
+ QQmlEngine *engine) :
+ m_data(new QQmlContextData(QQmlContextData::OwnedByPublicContext, publicContext,
+ parent, engine))
{
- if (typeCompilationUnit)
- return typeCompilationUnit->finalUrlString();
- return baseUrlString;
+ Q_ASSERT(publicContext != nullptr);
}
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlcontext.h b/src/qml/qml/qqmlcontext.h
index 7ed70c7619..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;
@@ -81,16 +44,18 @@ public:
QVariant contextProperty(const QString &) const;
void setContextProperty(const QString &, QObject *);
void setContextProperty(const QString &, const QVariant &);
- void setContextProperties(const QVector<PropertyPair> &properties);
+ void setContextProperties(const QList<PropertyPair> &properties);
- // ### Qt 6: no need for a mutable object, this should become a const QObject pointer
- QString nameForObject(QObject *) const;
+ QString nameForObject(const QObject *) const;
+ QObject *objectForName(const QString &) const;
- QUrl resolvedUrl(const QUrl &);
+ QUrl resolvedUrl(const QUrl &) const;
void setBaseUrl(const QUrl &);
QUrl baseUrl() const;
+ QJSValue importedScript(const QString &name) const;
+
private:
friend class QQmlEngine;
friend class QQmlEnginePrivate;
@@ -100,12 +65,10 @@ private:
friend class QQmlComponentPrivate;
friend class QQmlScriptPrivate;
friend class QQmlContextData;
- QQmlContext(QQmlContextData *);
+ QQmlContext(QQmlContextPrivate &dd, QObject *parent = nullptr);
QQmlContext(QQmlEngine *, bool);
Q_DISABLE_COPY(QQmlContext)
};
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 f93393a11b..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
@@ -51,342 +15,78 @@
// We mean it.
//
-#include "qqmlcontext.h"
+#include <QtCore/qlist.h>
+#include <QtCore/qstring.h>
+#include <QtCore/qvariant.h>
+#include <QtCore/qpointer.h>
+#include <QtQml/qqmlcontext.h>
+#include <QtQml/qqmllist.h>
-#include "qqmldata_p.h"
-#include "qqmltypenamecache_p.h"
-#include "qqmlnotifier_p.h"
-#include "qqmllist.h"
-
-#include <QtCore/qhash.h>
-#include <QtQml/qjsvalue.h>
-#include <QtCore/qset.h>
-
-#include <private/qobject_p.h>
-#include <private/qflagpointer_p.h>
-#include <private/qqmlguard_p.h>
-
-#include <private/qv4executablecompilationunit_p.h>
-#include <private/qv4identifier_p.h>
+#include <QtCore/private/qobject_p.h>
+#include <QtCore/qtaggedpointer.h>
+#include <QtQml/private/qqmlrefcount_p.h>
QT_BEGIN_NAMESPACE
-class QQmlContext;
-class QQmlExpression;
-class QQmlEngine;
-class QQmlExpression;
-class QQmlExpressionPrivate;
-class QQmlJavaScriptExpression;
class QQmlContextData;
-class QQmlGuardedContextData;
-class QQmlIncubatorPrivate;
class QQmlContextPrivate : public QObjectPrivate
{
Q_DECLARE_PUBLIC(QQmlContext)
public:
- QQmlContextPrivate();
-
- QQmlContextData *data;
-
- QList<QVariant> propertyValues;
- int notifyIndex;
-
static QQmlContextPrivate *get(QQmlContext *context) {
return static_cast<QQmlContextPrivate *>(QObjectPrivate::get(context));
}
+
static QQmlContext *get(QQmlContextPrivate *context) {
return static_cast<QQmlContext *>(context->q_func());
}
- // Only used for debugging
- QList<QPointer<QObject> > instances;
-
- static int context_count(QQmlListProperty<QObject> *);
- static QObject *context_at(QQmlListProperty<QObject> *, int);
+ static qsizetype context_count(QQmlListProperty<QObject> *);
+ static QObject *context_at(QQmlListProperty<QObject> *, qsizetype);
void dropDestroyedQObject(const QString &name, QObject *destroyed);
-};
-
-class QQmlComponentAttached;
-class Q_QML_PRIVATE_EXPORT QQmlContextData
-{
-public:
- QQmlContextData();
- QQmlContextData(QQmlContext *);
- void emitDestruction();
- void clearContext();
- void clearContextRecursively();
- void invalidate();
+ int notifyIndex() const { return m_notifyIndex; }
+ void setNotifyIndex(int notifyIndex) { m_notifyIndex = notifyIndex; }
- inline bool isValid() const {
- return engine && (!isInternal || !contextObject || !QObjectPrivate::get(contextObject)->wasDeleted);
+ 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]; }
- // My parent context and engine
- QQmlContextData *parent = nullptr;
- QQmlEngine *engine;
-
- void setParent(QQmlContextData *, bool stronglyReferencedByParent = false);
- void refreshExpressions();
-
- void addObject(QQmlData *data);
-
- QUrl resolvedUrl(const QUrl &);
-
- // My containing QQmlContext. If isInternal is true this owns publicContext.
- // If internal is false publicContext owns this.
- QQmlContext *asQQmlContext();
- QQmlContextPrivate *asQQmlContextPrivate();
- quint32 refCount = 0;
- quint32 isInternal:1;
- quint32 isJSContext:1;
- quint32 isPragmaLibraryContext:1;
- quint32 unresolvedNames:1; // True if expressions in this context failed to resolve a toplevel name
- quint32 hasEmittedDestruction:1;
- quint32 isRootObjectInCreation:1;
- quint32 stronglyReferencedByParent:1;
- quint32 hasExtraObject:1; // used in QQmlDelegateModelItem::dataForObject to find the corresponding QQmlDelegateModelItem of an object
- quint32 dummy:24;
- QQmlContext *publicContext;
-
- union {
- // The incubator that is constructing this context if any
- QQmlIncubatorPrivate *incubator;
- // a pointer to extra data, currently only used in QQmlDelegateModel
- QObject *extraObject;
- };
-
- // Compilation unit for contexts that belong to a compiled type.
- QQmlRefPointer<QV4::ExecutableCompilationUnit> typeCompilationUnit;
-
- // object index in CompiledData::Unit to component that created this context
- int componentObjectIndex;
-
- void initFromTypeCompilationUnit(const QQmlRefPointer<QV4::ExecutableCompilationUnit> &unit, int subComponentIndex);
-
- // flag indicates whether the context owns the cache (after mutation) or not.
- mutable QV4::IdentifierHash propertyNameCache;
- const QV4::IdentifierHash &propertyNames() const;
- QV4::IdentifierHash &detachedPropertyNames();
-
- // Context object
- QObject *contextObject;
-
- // Any script blocks that exist on this context
- QV4::PersistentValue importedScripts; // This is a JS Array
-
- QUrl baseUrl;
- QString baseUrlString;
-
- QUrl url() const;
- QString urlString() const;
-
- // List of imports that apply to this context
- QQmlRefPointer<QQmlTypeNameCache> imports;
-
- // My children
- QQmlContextData *childContexts = nullptr;
-
- // My peers in parent's childContexts list
- QQmlContextData *nextChild;
- QQmlContextData **prevChild;
-
- // Expressions that use this context
- QQmlJavaScriptExpression *expressions;
-
- // Doubly-linked list of objects that are owned by this context
- QQmlData *contextObjects;
-
- // Doubly-linked list of context guards (XXX merge with contextObjects)
- QQmlGuardedContextData *contextGuards = nullptr;
-
- // id guards
- struct ContextGuard : public QQmlGuard<QObject>
+ QList<QPointer<QObject>> instances() const { return m_instances; }
+ void appendInstance(QObject *instance) { m_instances.append(instance); }
+ void cleanInstances()
{
- inline ContextGuard();
- inline ContextGuard &operator=(QObject *obj);
- inline void objectDestroyed(QObject *) override;
-
- inline bool wasSet() const;
-
- QFlagPointer<QQmlContextData> context;
- QQmlNotifier bindings;
- };
- ContextGuard *idValues;
- int idValueCount;
- void setIdProperty(int, QObject *);
-
- // Linked contexts. this owns linkedContext.
- QQmlContextDataRef linkedContext;
-
- // Linked list of uses of the Component attached property in this
- // context
- QQmlComponentAttached *componentAttached;
-
- // Return the outermost id for obj, if any.
- QString findObjectId(const QObject *obj) const;
-
- static QQmlContextData *get(QQmlContext *context) {
- return QQmlContextPrivate::get(context)->data;
+ for (auto it = m_instances.begin(); it != m_instances.end();
+ it->isNull() ? (it = m_instances.erase(it)) : ++it) {}
}
-private:
- friend class QQmlContextDataRef;
- friend class QQmlContext; // needs to do manual refcounting :/
- void refreshExpressionsRecursive(bool isGlobal);
- void refreshExpressionsRecursive(QQmlJavaScriptExpression *);
- ~QQmlContextData();
- void destroy();
-};
-
-
-class QQmlGuardedContextData
-{
-public:
- inline QQmlGuardedContextData() = default;
- inline QQmlGuardedContextData(QQmlContextData *data)
- { setContextData(data); }
- inline ~QQmlGuardedContextData()
- { clear(); }
-
- inline QQmlContextData *contextData() const
- { return m_contextData; }
- inline void setContextData(QQmlContextData *);
-
- inline bool isNull() const { return !m_contextData; }
-
- inline operator QQmlContextData*() const { return m_contextData; }
- inline QQmlContextData* operator->() const { return m_contextData; }
- inline QQmlGuardedContextData &operator=(QQmlContextData *d) {
- setContextData(d); return *this;
- }
+ void emitDestruction();
private:
- QQmlGuardedContextData &operator=(const QQmlGuardedContextData &) = delete;
- QQmlGuardedContextData(const QQmlGuardedContextData &) = delete;
friend class QQmlContextData;
- inline void clear();
-
- QQmlContextData *m_contextData = nullptr;
- QQmlGuardedContextData *m_next = nullptr;
- QQmlGuardedContextData **m_prev = nullptr;
-};
-
-
-void QQmlGuardedContextData::setContextData(QQmlContextData *contextData)
- {
- if (m_contextData == contextData)
- return;
- clear();
+ QQmlContextPrivate(QQmlContextData *data) : m_data(data) {}
+ QQmlContextPrivate(QQmlContext *publicContext, const QQmlRefPointer<QQmlContextData> &parent,
+ QQmlEngine *engine = nullptr);
- if (contextData) {
- m_contextData = contextData;
- m_next = contextData->contextGuards;
- if (m_next) m_next->m_prev = &m_next;
- m_prev = &contextData->contextGuards;
- contextData->contextGuards = this;
- }
-}
-
-void QQmlGuardedContextData::clear()
-{
- if (m_prev) {
- *m_prev = m_next;
- if (m_next) m_next->m_prev = m_prev;
- m_contextData = nullptr;
- m_next = nullptr;
- m_prev = nullptr;
- }
-}
-
-QQmlContextDataRef::QQmlContextDataRef()
- : m_contextData(nullptr)
-{
-}
+ // Intentionally a bare pointer. QQmlContextData knows whether it owns QQmlContext or vice
+ // versa. If QQmlContext is the owner, QQmlContextData keeps an extra ref for its publicContext.
+ // The publicContext ref is released when doing QQmlContextData::setPublicContext(nullptr).
+ QQmlContextData *m_data;
-QQmlContextDataRef::QQmlContextDataRef(const QQmlContextDataRef &other)
- : m_contextData(other.m_contextData)
-{
- if (m_contextData)
- ++m_contextData->refCount;
-}
-
-QQmlContextDataRef::QQmlContextDataRef(QQmlContextData *data)
- : m_contextData(data)
-{
- if (m_contextData)
- ++m_contextData->refCount;
-}
-
-QQmlContextDataRef::~QQmlContextDataRef()
-{
- clear();
-}
+ QList<QVariant> m_propertyValues;
+ int m_notifyIndex = -1;
-void QQmlContextDataRef::setContextData(QQmlContextData *contextData)
-{
- if (m_contextData == contextData)
- return;
- clear();
-
- if (contextData) {
- m_contextData = contextData;
- ++m_contextData->refCount;
- }
-}
-
-QQmlContextData *QQmlContextDataRef::contextData() const
-{
- return m_contextData;
-}
-
-void QQmlContextDataRef::clear()
-{
- if (m_contextData && !--m_contextData->refCount)
- m_contextData->destroy();
- m_contextData = nullptr;
-}
-
-QQmlContextDataRef &
-QQmlContextDataRef::operator=(QQmlContextData *d)
-{
- setContextData(d);
- return *this;
-}
-
-QQmlContextDataRef &
-QQmlContextDataRef::operator=(const QQmlContextDataRef &other)
-{
- setContextData(other.m_contextData);
- return *this;
-}
-
-QQmlContextData::ContextGuard::ContextGuard()
-: context(nullptr)
-{
-}
-
-QQmlContextData::ContextGuard &QQmlContextData::ContextGuard::operator=(QObject *obj)
-{
- QQmlGuard<QObject>::operator=(obj);
- context.setFlag();
- bindings.notify(); // For alias connections
- return *this;
-}
-
-void QQmlContextData::ContextGuard::objectDestroyed(QObject *)
-{
- if (context->contextObject && !QObjectPrivate::get(context->contextObject)->wasDeleted)
- bindings.notify();
-}
-
-bool QQmlContextData::ContextGuard::wasSet() const
-{
- return context.flag();
-}
+ // Only used for debugging
+ QList<QPointer<QObject>> m_instances;
+};
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlcontextdata.cpp b/src/qml/qml/qqmlcontextdata.cpp
new file mode 100644
index 0000000000..8667a1ce81
--- /dev/null
+++ b/src/qml/qml/qqmlcontextdata.cpp
@@ -0,0 +1,346 @@
+// 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"
+
+#include <QtQml/qqmlengine.h>
+#include <QtQml/private/qqmlcomponentattached_p.h>
+#include <QtQml/private/qqmljavascriptexpression_p.h>
+#include <QtQml/private/qqmlguardedcontextdata_p.h>
+
+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;
+ if (src.isRelative() && !src.isEmpty()) {
+ const QUrl ownUrl = url();
+ if (ownUrl.isValid()) {
+ resolved = ownUrl.resolved(src);
+ } else {
+ for (QQmlRefPointer<QQmlContextData> ctxt = parent(); ctxt; ctxt = ctxt->parent()) {
+ const QUrl ctxtUrl = ctxt->url();
+ if (ctxtUrl.isValid()) {
+ resolved = ctxtUrl.resolved(src);
+ break;
+ }
+ }
+
+ if (m_engine && resolved.isEmpty())
+ resolved = m_engine->baseUrl().resolved(src);
+ }
+ } else {
+ resolved = src;
+ }
+
+ if (resolved.isEmpty()) //relative but no ctxt
+ return resolved;
+
+ return m_engine ? m_engine->interceptUrl(resolved, QQmlAbstractUrlInterceptor::UrlString)
+ : resolved;
+}
+
+void QQmlContextData::emitDestruction()
+{
+ if (!m_hasEmittedDestruction) {
+ m_hasEmittedDestruction = true;
+
+ // Emit the destruction signal - must be emitted before invalidate so that the
+ // context is still valid if bindings or resultant expression evaluation requires it
+ if (m_engine) {
+ while (m_componentAttacheds) {
+ QQmlComponentAttached *attached = m_componentAttacheds;
+ attached->removeFromList();
+ emit attached->destruction();
+ }
+
+ for (QQmlRefPointer<QQmlContextData> child = m_childContexts; !child.isNull(); child = child->m_nextChild)
+ child->emitDestruction();
+ }
+ }
+}
+
+void QQmlContextData::invalidate()
+{
+ emitDestruction();
+
+ while (m_childContexts) {
+ Q_ASSERT(m_childContexts != this);
+ m_childContexts->invalidate();
+ }
+
+ if (m_prevChild) {
+ *m_prevChild = m_nextChild;
+ if (m_nextChild) m_nextChild->m_prevChild = m_prevChild;
+ m_nextChild = nullptr;
+ m_prevChild = nullptr;
+ }
+
+ m_importedScripts.clear();
+
+ m_engine = nullptr;
+ clearParent();
+}
+
+void QQmlContextData::clearContextRecursively()
+{
+ clearContext();
+
+ for (auto ctxIt = m_childContexts; ctxIt; ctxIt = ctxIt->m_nextChild)
+ ctxIt->clearContextRecursively();
+}
+
+void QQmlContextData::clearContext()
+{
+ emitDestruction();
+
+ QQmlJavaScriptExpression *expression = m_expressions;
+ while (expression) {
+ QQmlJavaScriptExpression *nextExpression = expression->m_nextExpression;
+
+ expression->m_prevExpression = nullptr;
+ expression->m_nextExpression = nullptr;
+
+ expression->setContext(nullptr);
+
+ expression = nextExpression;
+ }
+ m_expressions = nullptr;
+}
+
+QQmlContextData::~QQmlContextData()
+{
+ Q_ASSERT(refCount() == 0);
+
+ // avoid recursion
+ addref();
+ if (m_engine)
+ invalidate();
+ m_linkedContext.reset();
+
+ Q_ASSERT(refCount() == 1);
+ clearContext();
+ Q_ASSERT(refCount() == 1);
+
+ while (m_ownedObjects) {
+ QQmlData *co = m_ownedObjects;
+ m_ownedObjects = m_ownedObjects->nextContextObject;
+
+ if (co->context == this)
+ co->context = nullptr;
+ co->outerContext = nullptr;
+ co->nextContextObject = nullptr;
+ co->prevContextObject = nullptr;
+ }
+ Q_ASSERT(refCount() == 1);
+
+ QQmlGuardedContextData *contextGuard = m_contextGuards;
+ while (contextGuard) {
+ // TODO: Is this dead code? Why?
+ QQmlGuardedContextData *next = contextGuard->next();
+ contextGuard->setContextData({});
+ contextGuard = next;
+ }
+ m_contextGuards = nullptr;
+ Q_ASSERT(refCount() == 1);
+
+ delete [] m_idValues;
+ m_idValues = nullptr;
+
+ Q_ASSERT(refCount() == 1);
+ if (m_publicContext)
+ delete m_publicContext;
+
+ Q_ASSERT(refCount() == 1);
+}
+
+void QQmlContextData::refreshExpressionsRecursive(QQmlJavaScriptExpression *expression)
+{
+ QQmlJavaScriptExpression::DeleteWatcher w(expression);
+
+ if (expression->m_nextExpression)
+ refreshExpressionsRecursive(expression->m_nextExpression);
+
+ if (!w.wasDeleted())
+ expression->refresh();
+}
+
+void QQmlContextData::refreshExpressionsRecursive(bool isGlobal)
+{
+ // For efficiency, we try and minimize the number of guards we have to create
+ if (hasExpressionsToRun(isGlobal) && (m_nextChild || m_childContexts)) {
+ QQmlGuardedContextData guard(this);
+
+ if (m_childContexts)
+ m_childContexts->refreshExpressionsRecursive(isGlobal);
+
+ if (guard.isNull()) return;
+
+ if (m_nextChild)
+ m_nextChild->refreshExpressionsRecursive(isGlobal);
+
+ if (guard.isNull()) return;
+
+ if (hasExpressionsToRun(isGlobal))
+ refreshExpressionsRecursive(m_expressions);
+
+ } else if (hasExpressionsToRun(isGlobal)) {
+ refreshExpressionsRecursive(m_expressions);
+ } else if (m_nextChild && m_childContexts) {
+ QQmlGuardedContextData guard(this);
+ m_childContexts->refreshExpressionsRecursive(isGlobal);
+ if (!guard.isNull() && m_nextChild)
+ m_nextChild->refreshExpressionsRecursive(isGlobal);
+ } else if (m_nextChild) {
+ m_nextChild->refreshExpressionsRecursive(isGlobal);
+ } else if (m_childContexts) {
+ m_childContexts->refreshExpressionsRecursive(isGlobal);
+ }
+}
+
+// Refreshes all expressions that could possibly depend on this context. Refreshing flushes all
+// context-tree dependent caches in the expressions, and should occur every time the context tree
+// *structure* (not values) changes.
+void QQmlContextData::refreshExpressions()
+{
+ bool isGlobal = (m_parent == nullptr);
+
+ // For efficiency, we try and minimize the number of guards we have to create
+ if (hasExpressionsToRun(isGlobal) && m_childContexts) {
+ QQmlGuardedContextData guard(this);
+ m_childContexts->refreshExpressionsRecursive(isGlobal);
+ if (!guard.isNull() && hasExpressionsToRun(isGlobal))
+ refreshExpressionsRecursive(m_expressions);
+ } else if (hasExpressionsToRun(isGlobal)) {
+ refreshExpressionsRecursive(m_expressions);
+ } else if (m_childContexts) {
+ m_childContexts->refreshExpressionsRecursive(isGlobal);
+ }
+}
+
+void QQmlContextData::addOwnedObject(QQmlData *data)
+{
+ if (data->outerContext) {
+ if (data->nextContextObject)
+ data->nextContextObject->prevContextObject = data->prevContextObject;
+ if (data->prevContextObject)
+ *data->prevContextObject = data->nextContextObject;
+ else if (data->outerContext->m_ownedObjects == data)
+ data->outerContext->m_ownedObjects = data->nextContextObject;
+ }
+
+ data->outerContext = this;
+
+ data->nextContextObject = m_ownedObjects;
+ if (data->nextContextObject)
+ data->nextContextObject->prevContextObject = &data->nextContextObject;
+ data->prevContextObject = &m_ownedObjects;
+ m_ownedObjects = data;
+}
+
+void QQmlContextData::setIdValue(int idx, QObject *obj)
+{
+ m_idValues[idx] = obj;
+ m_idValues[idx].setContext(this);
+}
+
+QString QQmlContextData::findObjectId(const QObject *obj) const
+{
+ for (int ii = 0; ii < m_idValueCount; ii++) {
+ if (m_idValues[ii] == obj)
+ 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) == objVariant)
+ return propertyName(ii);
+ }
+
+ 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());
+ }
+ }
+ }
+ }
+
+ return QString();
+}
+
+void QQmlContextData::initFromTypeCompilationUnit(const QQmlRefPointer<QV4::ExecutableCompilationUnit> &unit, int subComponentIndex)
+{
+ m_typeCompilationUnit = unit;
+ m_componentObjectIndex = subComponentIndex == -1 ? /*root object*/0 : subComponentIndex;
+ Q_ASSERT(!m_idValues);
+ m_idValueCount = m_typeCompilationUnit->objectAt(m_componentObjectIndex)
+ ->nNamedObjectsInComponent;
+ m_idValues = new ContextGuard[m_idValueCount];
+}
+
+void QQmlContextData::addComponentAttached(QQmlComponentAttached *attached)
+{
+ attached->insertIntoList(&m_componentAttacheds);
+}
+
+void QQmlContextData::addExpression(QQmlJavaScriptExpression *expression)
+{
+ expression->insertIntoList(&m_expressions);
+}
+
+void QQmlContextData::initPropertyNames() const
+{
+ 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
+{
+ if (m_typeCompilationUnit)
+ return m_typeCompilationUnit->finalUrl();
+ return m_baseUrl;
+}
+
+QString QQmlContextData::urlString() const
+{
+ if (m_typeCompilationUnit)
+ return m_typeCompilationUnit->finalUrlString();
+ return m_baseUrlString;
+}
+
+QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlcontextdata_p.h b/src/qml/qml/qqmlcontextdata_p.h
new file mode 100644
index 0000000000..3aeabf72fa
--- /dev/null
+++ b/src/qml/qml/qqmlcontextdata_p.h
@@ -0,0 +1,472 @@
+// 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
+
+//
+// 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 <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>
+
+QT_BEGIN_NAMESPACE
+
+class QQmlComponentAttached;
+class QQmlGuardedContextData;
+class QQmlJavaScriptExpression;
+class QQmlIncubatorPrivate;
+
+class Q_QML_EXPORT QQmlContextData
+{
+public:
+ static QQmlRefPointer<QQmlContextData> createRefCounted(
+ const QQmlRefPointer<QQmlContextData> &parent)
+ {
+ return QQmlRefPointer<QQmlContextData>(new QQmlContextData(RefCounted, nullptr, parent),
+ QQmlRefPointer<QQmlContextData>::Adopt);
+ }
+
+ // Owned by the parent. When the parent is reset to nullptr, it will be deref'd.
+ static QQmlRefPointer<QQmlContextData> createChild(
+ const QQmlRefPointer<QQmlContextData> &parent)
+ {
+ Q_ASSERT(!parent.isNull());
+ return QQmlRefPointer<QQmlContextData>(new QQmlContextData(OwnedByParent, nullptr, parent));
+ }
+
+ void addref() const { ++m_refCount; }
+ void release() const { if (--m_refCount == 0) delete this; }
+ int count() const { return m_refCount; }
+ int refCount() const { return m_refCount; }
+
+ QQmlRefPointer<QV4::ExecutableCompilationUnit> typeCompilationUnit() const
+ {
+ return m_typeCompilationUnit;
+ }
+ void initFromTypeCompilationUnit(const QQmlRefPointer<QV4::ExecutableCompilationUnit> &unit,
+ int subComponentIndex);
+
+ static QQmlRefPointer<QQmlContextData> get(QQmlContext *context) {
+ return QQmlContextPrivate::get(context)->m_data;
+ }
+
+ void emitDestruction();
+ void clearContext();
+ void clearContextRecursively();
+ void invalidate();
+
+ bool isValid() const
+ {
+ return m_engine && (!m_isInternal || !m_contextObject
+ || !QObjectPrivate::get(m_contextObject)->wasDeleted);
+ }
+
+ bool isInternal() const { return m_isInternal; }
+ void setInternal(bool isInternal) { m_isInternal = isInternal; }
+
+ bool isJSContext() const { return m_isJSContext; }
+ void setJSContext(bool isJSContext) { m_isJSContext = isJSContext; }
+
+ bool isPragmaLibraryContext() const { return m_isPragmaLibraryContext; }
+ void setPragmaLibraryContext(bool library) { m_isPragmaLibraryContext = library; }
+
+ QQmlRefPointer<QQmlContextData> parent() const { return m_parent; }
+ void clearParent()
+ {
+ if (!m_parent)
+ return;
+
+ m_parent = nullptr;
+ if (m_ownedByParent) {
+ m_ownedByParent = false;
+ release();
+ }
+ }
+
+ void refreshExpressions();
+
+ void addOwnedObject(QQmlData *ownedObject);
+ 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()
+ {
+ 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; }
+
+ QQmlContext *publicContext() const { return m_publicContext; }
+ void clearPublicContext()
+ {
+ if (!m_publicContext)
+ return;
+
+ m_publicContext = nullptr;
+ if (m_ownedByPublicContext) {
+ m_ownedByPublicContext = false;
+ release();
+ }
+ }
+
+ 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()
+ {
+ QQmlJavaScriptExpression *expressions = m_expressions;
+ m_expressions = nullptr;
+ return expressions;
+ }
+
+ void setChildContexts(const QQmlRefPointer<QQmlContextData> &childContexts)
+ {
+ m_childContexts = childContexts.data();
+ }
+ QQmlRefPointer<QQmlContextData> childContexts() const { return m_childContexts; }
+ QQmlRefPointer<QQmlContextData> takeChildContexts()
+ {
+ QQmlRefPointer<QQmlContextData> childContexts = m_childContexts;
+ m_childContexts = nullptr;
+ return childContexts;
+ }
+ QQmlRefPointer<QQmlContextData> nextChild() const { return m_nextChild; }
+
+ int numIdValues() const { return m_idValueCount; }
+ void setIdValue(int index, QObject *idValue);
+ bool isIdValueSet(int index) const { return m_idValues[index].wasSet(); }
+ QQmlNotifier *idValueBindings(int index) const { return m_idValues[index].bindings(); }
+ QObject *idValue(int index) const { return m_idValues[index].data(); }
+
+ // Return the outermost id for obj, if any.
+ QString findObjectId(const QObject *obj) const;
+
+ // url() and urlString() prefer the CU's URL over explicitly set baseUrls. They
+ // don't search the context hierarchy.
+ // baseUrl() and baseUrlString() search the context hierarchy and prefer explicit
+ // base URLs over CU Urls.
+
+ QUrl url() const;
+ QString urlString() const;
+
+ void setBaseUrlString(const QString &baseUrlString) { m_baseUrlString = baseUrlString; }
+ QString baseUrlString() const
+ {
+ for (const QQmlContextData *data = this; data; data = data->m_parent) {
+ if (!data->m_baseUrlString.isEmpty())
+ return data->m_baseUrlString;
+ if (data->m_typeCompilationUnit)
+ return data->m_typeCompilationUnit->finalUrlString();
+ }
+ return QString();
+ }
+
+ void setBaseUrl(const QUrl &baseUrl) { m_baseUrl = baseUrl; }
+ QUrl baseUrl() const
+ {
+ for (const QQmlContextData *data = this; data; data = data->m_parent) {
+ if (!data->m_baseUrl.isEmpty())
+ return data->m_baseUrl;
+ if (data->m_typeCompilationUnit)
+ return data->m_typeCompilationUnit->finalUrl();
+ }
+ return QUrl();
+ }
+
+ QQmlRefPointer<QQmlTypeNameCache> imports() const { return m_imports; }
+ void setImports(const QQmlRefPointer<QQmlTypeNameCache> &imports) { m_imports = imports; }
+
+ QQmlIncubatorPrivate *incubator() const { return m_hasExtraObject ? nullptr : m_incubator; }
+ void setIncubator(QQmlIncubatorPrivate *incubator)
+ {
+ Q_ASSERT(!m_hasExtraObject || m_extraObject == nullptr);
+ m_hasExtraObject = false;
+ m_incubator = incubator;
+ }
+
+ QObject *extraObject() const { return m_hasExtraObject ? m_extraObject : nullptr; }
+ void setExtraObject(QObject *extraObject)
+ {
+ Q_ASSERT(m_hasExtraObject || m_incubator == nullptr);
+ m_hasExtraObject = true;
+ m_extraObject = extraObject;
+ }
+
+ bool isRootObjectInCreation() const { return m_isRootObjectInCreation; }
+ void setRootObjectInCreation(bool rootInCreation) { m_isRootObjectInCreation = rootInCreation; }
+
+ QV4::PersistentValue importedScripts() const { return m_importedScripts; }
+ void setImportedScripts(const QV4::PersistentValue &scripts) { m_importedScripts = scripts; }
+
+ QQmlRefPointer<QQmlContextData> linkedContext() const { return m_linkedContext; }
+ void setLinkedContext(const QQmlRefPointer<QQmlContextData> &context) { m_linkedContext = context; }
+
+ bool hasUnresolvedNames() const { return m_unresolvedNames; }
+ void setUnresolvedNames(bool hasUnresolvedNames) { m_unresolvedNames = hasUnresolvedNames; }
+
+ QQmlComponentAttached *componentAttacheds() const { return m_componentAttacheds; }
+ void addComponentAttached(QQmlComponentAttached *attached);
+
+ void addExpression(QQmlJavaScriptExpression *expression);
+
+ bool valueTypesAreAddressable() const {
+ return m_typeCompilationUnit && m_typeCompilationUnit->valueTypesAreAddressable();
+ }
+
+ bool valueTypesAreAssertable() const {
+ return m_typeCompilationUnit && m_typeCompilationUnit->valueTypesAreAssertable();
+ }
+
+private:
+ friend class QQmlGuardedContextData;
+ friend class QQmlContextPrivate;
+
+ enum Ownership {
+ RefCounted,
+ OwnedByParent,
+ OwnedByPublicContext
+ };
+
+ // id guards
+ struct ContextGuard : public QQmlGuard<QObject>
+ {
+ enum Tag {
+ NoTag,
+ ObjectWasSet
+ };
+
+ inline ContextGuard() : QQmlGuard<QObject>(&ContextGuard::objectDestroyedImpl, nullptr), m_context(nullptr) {}
+ inline ContextGuard &operator=(QObject *obj);
+
+ inline bool wasSet() const;
+
+ QQmlNotifier *bindings() { return &m_bindings; }
+ void setContext(const QQmlRefPointer<QQmlContextData> &context)
+ {
+ m_context = context.data();
+ }
+
+ private:
+ inline static void objectDestroyedImpl(QQmlGuardImpl *);
+ // Not refcounted, as it always belongs to the QQmlContextData.
+ QTaggedPointer<QQmlContextData, Tag> m_context;
+ QQmlNotifier m_bindings;
+ };
+
+ // It's OK to pass a half-created publicContext here. We will not dereference it during
+ // construction.
+ QQmlContextData(
+ Ownership ownership, QQmlContext *publicContext,
+ const QQmlRefPointer<QQmlContextData> &parent, QQmlEngine *engine = nullptr)
+ : m_parent(parent.data()),
+ m_engine(engine ? engine : (parent.isNull() ? nullptr : parent->engine())),
+ m_isInternal(false), m_isJSContext(false), m_isPragmaLibraryContext(false),
+ m_unresolvedNames(false), m_hasEmittedDestruction(false), m_isRootObjectInCreation(false),
+ m_ownedByParent(ownership == OwnedByParent),
+ m_ownedByPublicContext(ownership == OwnedByPublicContext), m_hasExtraObject(false),
+ m_dummy(0), m_publicContext(publicContext), m_incubator(nullptr)
+ {
+ Q_ASSERT(!m_ownedByParent || !m_ownedByPublicContext);
+ if (!m_parent)
+ return;
+
+ m_nextChild = m_parent->m_childContexts;
+ if (m_nextChild)
+ m_nextChild->m_prevChild = &m_nextChild;
+ m_prevChild = &m_parent->m_childContexts;
+ m_parent->m_childContexts = this;
+ }
+
+ ~QQmlContextData();
+
+ bool hasExpressionsToRun(bool isGlobalRefresh) const
+ {
+ return m_expressions && (!isGlobalRefresh || m_unresolvedNames);
+ }
+
+ 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;
+ QQmlEngine *m_engine = nullptr;
+
+ mutable quint32 m_refCount = 1;
+ quint32 m_isInternal:1;
+ quint32 m_isJSContext:1;
+ quint32 m_isPragmaLibraryContext:1;
+ quint32 m_unresolvedNames:1; // True if expressions in this context failed to resolve a toplevel name
+ quint32 m_hasEmittedDestruction:1;
+ quint32 m_isRootObjectInCreation:1;
+ quint32 m_ownedByParent:1;
+ quint32 m_ownedByPublicContext:1;
+ quint32 m_hasExtraObject:1; // used in QQmlDelegateModelItem::dataForObject to find the corresponding QQmlDelegateModelItem of an object
+ Q_DECL_UNUSED_MEMBER quint32 m_dummy:23;
+ QQmlContext *m_publicContext = nullptr;
+
+ union {
+ // The incubator that is constructing this context if any
+ QQmlIncubatorPrivate *m_incubator;
+ // a pointer to extra data, currently only used in QQmlDelegateModel
+ QObject *m_extraObject;
+ };
+
+ // Compilation unit for contexts that belong to a compiled type.
+ QQmlRefPointer<QV4::ExecutableCompilationUnit> m_typeCompilationUnit;
+
+ // object index in CompiledData::Unit to component that created this context
+ int m_componentObjectIndex = -1;
+
+ // flag indicates whether the context owns the cache (after mutation) or not.
+ mutable QV4::IdentifierHash m_propertyNameCache;
+
+ // Context object
+ QObject *m_contextObject = nullptr;
+
+ // Any script blocks that exist on this context
+ QV4::PersistentValue m_importedScripts; // This is a JS Array
+
+ QUrl m_baseUrl;
+ QString m_baseUrlString;
+
+ // List of imports that apply to this context
+ QQmlRefPointer<QQmlTypeNameCache> m_imports;
+
+ // My children, not refcounted as that would create cyclic references
+ QQmlContextData *m_childContexts = nullptr;
+
+ // My peers in parent's childContexts list; not refcounted
+ QQmlContextData *m_nextChild = nullptr;
+ QQmlContextData **m_prevChild = nullptr;
+
+ // Expressions that use this context
+ QQmlJavaScriptExpression *m_expressions = nullptr;
+
+ // Doubly-linked list of objects that are owned by this context
+ QQmlData *m_ownedObjects = nullptr;
+
+ // Doubly-linked list of context guards (XXX merge with contextObjects)
+ QQmlGuardedContextData *m_contextGuards = nullptr;
+
+ ContextGuard *m_idValues = nullptr;
+ int m_idValueCount = 0;
+
+ // Linked contexts. this owns linkedContext.
+ QQmlRefPointer<QQmlContextData> m_linkedContext;
+
+ // Linked list of uses of the Component attached property in this context
+ QQmlComponentAttached *m_componentAttacheds = nullptr;
+};
+
+QQmlContextData::ContextGuard &QQmlContextData::ContextGuard::operator=(QObject *obj)
+{
+ QQmlGuard<QObject>::operator=(obj);
+ m_context.setTag(ObjectWasSet);
+ m_bindings.notify(); // For alias connections
+ return *this;
+}
+
+ void QQmlContextData::ContextGuard::objectDestroyedImpl(QQmlGuardImpl *impl)
+{
+ auto This = static_cast<QQmlContextData::ContextGuard *>(impl);
+ if (QObject *contextObject = This->m_context->contextObject()) {
+ if (!QObjectPrivate::get(contextObject)->wasDeleted)
+ This->m_bindings.notify();
+ }
+}
+
+bool QQmlContextData::ContextGuard::wasSet() const
+{
+ return m_context.tag() == ObjectWasSet;
+}
+
+QT_END_NAMESPACE
+
+#endif // QQMLCONTEXTDATA_P_H
diff --git a/src/qml/qml/qqmlcustomparser.cpp b/src/qml/qml/qqmlcustomparser.cpp
index a5f34dafdf..bd632d25a6 100644
--- a/src/qml/qml/qqmlcustomparser.cpp
+++ b/src/qml/qml/qqmlcustomparser.cpp
@@ -1,45 +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 "qml/qqmlpropertyvalidator_p.h"
#include "qqmlcustomparser_p.h"
#include <private/qv4compileddata_p.h>
+#include <private/qqmlsourcecoordinate_p.h>
#include <QtCore/qdebug.h>
@@ -100,20 +66,14 @@ void QQmlCustomParser::clearErrors()
*/
void QQmlCustomParser::error(const QV4::CompiledData::Location &location, const QString &description)
{
- QQmlJS::DiagnosticMessage error;
- error.line = location.line;
- error.column = location.column;
- error.message = description;
+ QQmlError error;
+ error.setLine(qmlConvertSourceCoordinate<quint32, int>(location.line()));
+ error.setColumn(qmlConvertSourceCoordinate<quint32, int>(location.column()));
+ error.setDescription(description);
exceptions << error;
}
-struct StaticQtMetaObject : public QObject
-{
- static const QMetaObject *get()
- { return &staticQtMetaObject; }
-};
-
/*!
If \a script is a simple enumeration expression (eg. Text.AlignLeft),
returns the integer equivalent (eg. 1), and sets \a ok to true.
@@ -122,7 +82,7 @@ struct StaticQtMetaObject : public QObject
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;
@@ -131,43 +91,104 @@ int QQmlCustomParser::evaluateEnum(const QByteArray& script, bool *ok) const
// * <TypeName>.<EnumValue>
// * <TypeName>.<ScopedEnumName>.<EnumValue>
- int dot = script.indexOf('.');
- if (dot == -1 || dot == script.length()-1)
+ auto nextDot = [&](int dot) {
+ 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()) {
- imports.asT1()->resolveType(scope, &type, nullptr, nullptr, nullptr);
+ QQmlImportNamespace *ns = nullptr;
+
+ // 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(
+ typeLoader, script.left(dot), &type, nullptr, nullptr, nullptr,
+ QQmlType::AnyRegistrationType, &recursionDetected)) {
+ return -1;
+ }
+ }
} else {
- QQmlTypeNameCache::Result result = imports.asT2()->query(scope);
- if (result.isValid())
+ // 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<QQmlImport::AllowRecursion>(
+ script.left(dot), typeLoader).type;
+ }
+ }
}
if (!type.isValid())
return -1;
- int dot2 = script.indexOf('.', dot+1);
- const bool dot2Valid = dot2 != -1 && dot2 != script.length()-1;
- QByteArray enumValue = script.mid(dot2Valid ? dot2 + 1 : dot + 1);
- QByteArray scopedEnumName = (dot2Valid ? script.mid(dot + 1, dot2 - dot - 1) : QByteArray());
+ const int dot2 = nextDot(dot);
+ const bool dot2Valid = (dot2 != -1);
+ 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 QMetaObject *mo = StaticQtMetaObject::get();
+ 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;
}
@@ -180,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 df8cbc9072..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 {
@@ -83,7 +46,7 @@ public:
virtual void verifyBindings(const QQmlRefPointer<QV4::ExecutableCompilationUnit> &, const QList<const QV4::CompiledData::Binding *> &) = 0;
virtual void applyBindings(QObject *, const QQmlRefPointer<QV4::ExecutableCompilationUnit> &, const QList<const QV4::CompiledData::Binding *> &) = 0;
- QVector<QQmlJS::DiagnosticMessage> errors() const { return exceptions; }
+ QVector<QQmlError> errors() const { return exceptions; }
protected:
void error(const QV4::CompiledData::Binding *binding, const QString& description)
@@ -92,12 +55,12 @@ 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;
private:
- QVector<QQmlJS::DiagnosticMessage> exceptions;
+ QVector<QQmlError> exceptions;
QQmlEnginePrivate *engine;
const QQmlPropertyValidator *validator;
Flags m_flags;
@@ -107,11 +70,6 @@ private:
};
Q_DECLARE_OPERATORS_FOR_FLAGS(QQmlCustomParser::Flags)
-#if 0
-#define QML_REGISTER_CUSTOM_TYPE(URI, VERSION_MAJ, VERSION_MIN, NAME, TYPE, CUSTOMTYPE) \
- qmlRegisterCustomType<TYPE>(#URI, VERSION_MAJ, VERSION_MIN, #NAME, #TYPE, new CUSTOMTYPE)
-#endif
-
QT_END_NAMESPACE
#endif
diff --git a/src/qml/qml/qqmldata_p.h b/src/qml/qml/qqmldata_p.h
index 299476f5c8..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>
@@ -74,6 +39,7 @@ class QQmlContextData;
class QQmlNotifier;
class QQmlDataExtended;
class QQmlNotifierEndpoint;
+class QQmlPropertyObserver;
namespace QV4 {
class ExecutableCompilationUnit;
@@ -82,42 +48,16 @@ struct Binding;
}
}
-// This is declared here because QQmlData below needs it and this file
-// in turn is included from qqmlcontext_p.h.
-class QQmlContextData;
-class Q_QML_PRIVATE_EXPORT QQmlContextDataRef
-{
-public:
- inline QQmlContextDataRef();
- inline QQmlContextDataRef(QQmlContextData *);
- inline QQmlContextDataRef(const QQmlContextDataRef &);
- inline ~QQmlContextDataRef();
-
- inline QQmlContextData *contextData() const;
- inline void setContextData(QQmlContextData *);
-
- inline bool isNull() const { return !m_contextData; }
-
- inline operator QQmlContextData*() const { return m_contextData; }
- inline QQmlContextData* operator->() const { return m_contextData; }
- inline QQmlContextDataRef &operator=(QQmlContextData *d);
- inline QQmlContextDataRef &operator=(const QQmlContextDataRef &other);
-
-private:
-
- inline void clear();
-
- QQmlContextData *m_contextData;
-};
-
// This class is structured in such a way, that simply zero'ing it is the
// 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() {
@@ -125,7 +65,6 @@ public:
if (!initialized) {
initialized = true;
QAbstractDeclarativeData::destroyed = destroyed;
- QAbstractDeclarativeData::parentChanged = parentChanged;
QAbstractDeclarativeData::signalEmitted = signalEmitted;
QAbstractDeclarativeData::receivers = receivers;
QAbstractDeclarativeData::isSignalConnected = isSignalConnected;
@@ -133,33 +72,42 @@ public:
}
static void destroyed(QAbstractDeclarativeData *, QObject *);
- static void parentChanged(QAbstractDeclarativeData *, QObject *, QObject *);
static void signalEmitted(QAbstractDeclarativeData *, QObject *, int, void **);
static int receivers(QAbstractDeclarativeData *, const QObject *, int);
static bool isSignalConnected(QAbstractDeclarativeData *, const QObject *, int);
void destroyed(QObject *);
- void parentChanged(QObject *, QObject *);
void setImplicitDestructible() {
if (!explicitIndestructibleSet) indestructible = false;
}
- quint32 ownedByQml1:1; // This bit is shared with QML1's QDeclarativeData.
+ // If ownMemomry is true, the QQmlData was normally allocated. Otherwise it was allocated
+ // with placement new and QQmlData::destroyed is not allowed to free the memory
quint32 ownMemory:1;
+ // indestructible is set if and only if the object has CppOwnership
+ // This can be explicitly set with QJSEngine::setObjectOwnership
+ // Top level objects generally have CppOwnership (see QQmlcCmponentprivate::beginCreate),
+ // unless created by special methods like the QML component.createObject() function
quint32 indestructible:1;
+ // indestructible was explicitly set with setObjectOwnership
+ // or the object is a top-level object
quint32 explicitIndestructibleSet:1;
+ // set when one QObject has been wrapped into QObjectWrapper in multiple engines
+ // at the same time - a rather rare case
quint32 hasTaintedV4Object:1;
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 parentFrozen:1;
- quint32 dummy:6;
+ // 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
@@ -176,37 +124,38 @@ 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();
- // The context that created the C++ object
+ enum class DeleteNotifyList { Yes, No };
+ void disconnectNotifiers(DeleteNotifyList doDelete);
+
+ // The context that created the C++ object; not refcounted to prevent cycles
QQmlContextData *context = nullptr;
- // The outermost context in which this object lives
+ // The outermost context in which this object lives; not refcounted to prevent cycles
QQmlContextData *outerContext = nullptr;
- QQmlContextDataRef ownContext;
+ 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);
@@ -216,34 +165,38 @@ 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();
~DeferredData();
unsigned int deferredIdx;
QMultiHash<int, const QV4::CompiledData::Binding *> bindings;
- QQmlRefPointer<QV4::ExecutableCompilationUnit> compilationUnit;//Not always the same as the other compilation unit
- QQmlContextData *context;//Could be either context or outerContext
+
+ // Not always the same as the other compilation unit
+ QQmlRefPointer<QV4::ExecutableCompilationUnit> compilationUnit;
+
+ // Could be either context or outerContext
+ QQmlRefPointer<QQmlContextData> context;
Q_DISABLE_COPY(DeferredData);
};
QQmlRefPointer<QV4::ExecutableCompilationUnit> compilationUnit;
QVector<DeferredData *> deferredData;
- void deferData(int objectIndex, const QQmlRefPointer<QV4::ExecutableCompilationUnit> &, QQmlContextData *);
+ void deferData(int objectIndex, const QQmlRefPointer<QV4::ExecutableCompilationUnit> &,
+ const QQmlRefPointer<QQmlContextData> &);
void releaseDeferredData();
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) {
@@ -258,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)
@@ -269,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; }
@@ -289,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
{
@@ -326,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)
- 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;
}
/*
@@ -367,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
@@ -414,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 750fc6de50..6b354c337f 100644
--- a/src/qml/qml/qqmldatablob.cpp
+++ b/src/qml/qml/qqmldatablob.cpp
@@ -1,50 +1,17 @@
-/****************************************************************************
-**
-** 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>
#include <private/qqmlprofiler_p.h>
#include <private/qqmltypeloader_p.h>
#include <private/qqmltypeloaderthread_p.h>
+#include <private/qqmlsourcecoordinate_p.h>
#include <QtQml/qqmlengine.h>
+#include <qtqml_tracepoints_p.h>
+
#ifdef DATABLOB_DEBUG
#define ASSERT_CALLBACK() do { if (!m_typeLoader || !m_typeLoader->m_thread->isThisThread()) qFatal("QQmlDataBlob: An API call was made outside a callback"); } while (false)
#else
@@ -53,6 +20,8 @@
DEFINE_BOOL_CONFIG_OPTION(dumpErrors, QML_DUMP_ERRORS);
+Q_DECLARE_LOGGING_CATEGORY(lcCycle)
+
QT_BEGIN_NAMESPACE
/*!
@@ -70,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.
*/
/*!
@@ -87,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
*/
/*!
@@ -102,9 +67,8 @@ QQmlDataBlob::QQmlDataBlob(const QUrl &url, Type type, QQmlTypeLoader *manager)
m_inCallback(false), m_isDone(false)
{
//Set here because we need to get the engine from the manager
- if (m_typeLoader->engine() && m_typeLoader->engine()->urlInterceptor())
- m_url = m_typeLoader->engine()->urlInterceptor()->intercept(m_url,
- (QQmlAbstractUrlInterceptor::DataType)m_type);
+ if (const QQmlEngine *qmlEngine = m_typeLoader->engine())
+ m_url = qmlEngine->interceptUrl(m_url, (QQmlAbstractUrlInterceptor::DataType)m_type);
}
/*! \internal */
@@ -287,12 +251,23 @@ void QQmlDataBlob::setError(const QList<QQmlError> &errors)
Q_ASSERT(status() != Error);
Q_ASSERT(m_errors.isEmpty());
- m_errors = errors; // Must be set before the m_data fence
+ // m_errors must be set before the m_data fence
+ m_errors.reserve(errors.size());
+ for (const QQmlError &error : errors) {
+ if (error.url().isEmpty()) {
+ QQmlError mutableError = error;
+ mutableError.setUrl(url());
+ m_errors.append(mutableError);
+ } else {
+ m_errors.append(error);
+ }
+ }
+
m_data.setStatus(Error);
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();
@@ -304,28 +279,13 @@ void QQmlDataBlob::setError(const QList<QQmlError> &errors)
void QQmlDataBlob::setError(const QQmlJS::DiagnosticMessage &error)
{
QQmlError e;
- e.setColumn(error.column);
- e.setLine(error.line);
+ e.setColumn(qmlConvertSourceCoordinate<quint32, int>(error.loc.startColumn));
+ e.setLine(qmlConvertSourceCoordinate<quint32, int>(error.loc.startLine));
e.setDescription(error.message);
e.setUrl(url());
setError(e);
}
-void QQmlDataBlob::setError(const QVector<QQmlJS::DiagnosticMessage> &errors)
-{
- QList<QQmlError> finalErrors;
- finalErrors.reserve(errors.count());
- for (const auto &error : errors) {
- QQmlError e;
- e.setColumn(error.column);
- e.setLine(error.line);
- e.setDescription(error.message);
- e.setUrl(url());
- finalErrors << e;
- }
- setError(finalErrors);
-}
-
void QQmlDataBlob::setError(const QString &description)
{
QQmlError e;
@@ -351,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;
@@ -359,6 +319,13 @@ void QQmlDataBlob::addDependency(QQmlDataBlob *blob)
m_waitingFor.append(blob);
blob->m_waitingOnMe.append(this);
+
+ // Check circular dependency
+ if (m_waitingOnMe.indexOf(blob) >= 0) {
+ qCWarning(lcCycle) << "Cyclic dependency detected between" << this->url().toString()
+ << "and" << blob->url().toString();
+ m_data.setStatus(Error);
+ }
}
/*!
@@ -535,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));
@@ -546,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(),
@@ -559,12 +526,13 @@ void QQmlDataBlob::notifyAllWaitingOnMe()
void QQmlDataBlob::notifyComplete(QQmlDataBlob *blob)
{
Q_ASSERT(blob->status() == Error || blob->status() == Complete);
+ Q_TRACE_SCOPE(QQmlCompiling, blob->url());
QQmlCompilingProfiler prof(typeLoader()->profiler(), 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;
@@ -607,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 0450e94c02..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,14 +17,15 @@
#include <private/qqmlrefcount_p.h>
#include <private/qqmljsdiagnosticmessage_p.h>
-#include <private/qv4compileddata_p.h>
#if QT_CONFIG(qml_network)
#include <QtNetwork/qnetworkreply.h>
#endif
+#include <QtQml/qqmlprivate.h>
#include <QtQml/qqmlerror.h>
#include <QtQml/qqmlabstracturlinterceptor.h>
+#include <QtQml/qqmlprivate.h>
#include <QtCore/qdatetime.h>
#include <QtCore/qfileinfo.h>
@@ -69,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
@@ -88,7 +55,7 @@ public:
};
QQmlDataBlob(const QUrl &, Type, QQmlTypeLoader* manager);
- ~QQmlDataBlob() override;
+ virtual ~QQmlDataBlob();
void startLoading();
@@ -119,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;
@@ -132,13 +104,12 @@ protected:
void setError(const QQmlError &);
void setError(const QList<QQmlError> &errors);
void setError(const QQmlJS::DiagnosticMessage &error);
- void setError(const QVector<QQmlJS::DiagnosticMessage> &errors);
void setError(const QString &description);
void addDependency(QQmlDataBlob *);
// Callbacks made in load thread
virtual void dataReceived(const SourceCodeData &) = 0;
- virtual void initializeFromCachedUnit(const QV4::CompiledData::Unit*) = 0;
+ virtual void initializeFromCachedUnit(const QQmlPrivate::CachedQmlUnit *) = 0;
virtual void done();
#if QT_CONFIG(qml_network)
virtual void networkError(QNetworkReply::NetworkError);
@@ -209,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 02fde97b3d..ead8a717f5 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,25 +70,28 @@ 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::Scope scope(b);
- if (argc == 0)
+ QQmlDelayedCallQueue *self = engine->delayedCallQueue();
+
+ 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) {
// This is a QObject function wrapper
- iter = m_delayedFunctionCalls.begin();
- while (iter != m_delayedFunctionCalls.end()) {
+ iter = self->m_delayedFunctionCalls.begin();
+ while (iter != self->m_delayedFunctionCalls.end()) {
DelayedFunctionCall& dfc = *iter;
QPair<QObject *, int> storedFunctionData = QV4::QObjectMethod::extractQtMethod(dfc.m_function.as<QV4::FunctionObject>());
if (storedFunctionData == functionData) {
@@ -134,50 +101,51 @@ QV4::ReturnedValue QQmlDelayedCallQueue::addUniquelyAndExecuteLater(const QV4::F
}
} else {
// This is a JavaScript function (dynamic slot on VMEMO)
- iter = m_delayedFunctionCalls.begin();
- while (iter != m_delayedFunctionCalls.end()) {
+ 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;
}
}
- const bool functionAlreadyStored = (iter != m_delayedFunctionCalls.end());
+ const bool functionAlreadyStored = (iter != self->m_delayedFunctionCalls.end());
if (functionAlreadyStored) {
DelayedFunctionCall dfc = *iter;
- m_delayedFunctionCalls.erase(iter);
- m_delayedFunctionCalls.append(dfc);
+ self->m_delayedFunctionCalls.erase(iter);
+ self->m_delayedFunctionCalls.append(dfc);
} else {
- m_delayedFunctionCalls.append(QV4::PersistentValue(m_engine, arg0));
+ self->m_delayedFunctionCalls.append(QV4::PersistentValue(engine, firstArgument));
}
- DelayedFunctionCall& dfc = m_delayedFunctionCalls.last();
+ DelayedFunctionCall& dfc = self->m_delayedFunctionCalls.last();
if (dfc.m_objectGuard.isNull()) {
if (functionData.second != -1) {
// if it's a qobject function wrapper, guard against qobject deletion
dfc.m_objectGuard = QQmlGuard<QObject>(functionData.first);
dfc.m_guarded = true;
- } else if (func->scope()->type == QV4::Heap::ExecutionContext::Type_QmlContext) {
- QV4::QmlContext::Data *g = static_cast<QV4::QmlContext::Data *>(func->scope());
+ } else if (const auto *js = func->as<QV4::JavaScriptFunctionObject>();
+ js && js->scope()->type == QV4::Heap::ExecutionContext::Type_QmlContext) {
+ QV4::QmlContext::Data *g = static_cast<QV4::QmlContext::Data *>(js->scope());
Q_ASSERT(g->qml()->scopeObject);
dfc.m_objectGuard = QQmlGuard<QObject>(g->qml()->scopeObject);
dfc.m_guarded = true;
}
}
- storeAnyArguments(dfc, argv, argc, 1, m_engine);
+ self->storeAnyArguments(dfc, args, 1, engine);
- if (!m_callbackOutstanding) {
- m_tickedMethod.invoke(this, Qt::QueuedConnection);
- m_callbackOutstanding = true;
+ if (!self->m_callbackOutstanding) {
+ self->m_tickedMethod.invoke(self, Qt::QueuedConnection);
+ self->m_callbackOutstanding = true;
}
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;
@@ -185,8 +153,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 7962318561..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,7 +33,8 @@ public:
void init(QV4::ExecutionEngine *);
- 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();
@@ -89,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 de74dfdf9b..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)
@@ -87,7 +39,7 @@ void QQmlQmldirData::dataReceived(const SourceCodeData &data)
}
}
-void QQmlQmldirData::initializeFromCachedUnit(const QV4::CompiledData::Unit *)
+void QQmlQmldirData::initializeFromCachedUnit(const QQmlPrivate::CachedQmlUnit *)
{
Q_UNIMPLEMENTED();
}
diff --git a/src/qml/qml/qqmldirdata_p.h b/src/qml/qml/qqmldirdata_p.h
index 34f1ff1678..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 QV4::CompiledData::Unit *) 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 6e1365ea9f..14408c735b 100644
--- a/src/qml/qml/qqmlengine.cpp
+++ b/src/qml/qml/qqmlengine.cpp
@@ -1,142 +1,56 @@
-/****************************************************************************
-**
-** 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 <private/qqmldirparser_p.h>
+
+#include <private/qqmlabstractbinding_p.h>
#include <private/qqmlboundsignal_p.h>
-#include <private/qqmljsdiagnosticmessage_p.h>
-#include <QtCore/qstandardpaths.h>
-#include <QtCore/qsettings.h>
-#include <QtCore/qmetaobject.h>
-#include <QDebug>
+#include <private/qqmlcontext_p.h>
+#include <private/qqmlnotifier_p.h>
+#include <private/qqmlpluginimporter_p.h>
+#include <private/qqmlprofiler_p.h>
+#include <private/qqmlscriptdata_p.h>
+#include <private/qqmlsourcecoordinate_p.h>
+#include <private/qqmltype_p.h>
+#include <private/qqmltypedata_p.h>
+#include <private/qqmlvmemetaobject_p.h>
+#include <private/qqmlcomponent_p.h>
+
+#include <private/qobject_p.h>
+#include <private/qthread_p.h>
+
+#include <QtQml/qqml.h>
+#include <QtQml/qqmlcomponent.h>
+#include <QtQml/qqmlcontext.h>
+#include <QtQml/qqmlincubator.h>
+#include <QtQml/qqmlscriptstring.h>
+
#include <QtCore/qcoreapplication.h>
#include <QtCore/qcryptographichash.h>
#include <QtCore/qdir.h>
+#include <QtCore/qmetaobject.h>
#include <QtCore/qmutex.h>
+#include <QtCore/qstandardpaths.h>
#include <QtCore/qthread.h>
-#include <private/qthread_p.h>
#if QT_CONFIG(qml_network)
-#include "qqmlnetworkaccessmanagerfactory.h"
-#include <QNetworkAccessManager>
-#include <QtNetwork/qnetworkconfigmanager.h>
-#endif
-
-#include <private/qobject_p.h>
-#include <private/qmetaobject_p.h>
-#if QT_CONFIG(qml_locale)
-#include <private/qqmllocale_p.h>
+#include <QtQml/qqmlnetworkaccessmanagerfactory.h>
+#include <QtNetwork/qnetworkaccessmanager.h>
#endif
-#include <private/qqmlbind_p.h>
-#include <private/qqmlconnections_p.h>
-#if QT_CONFIG(qml_animation)
-#include <private/qqmltimer_p.h>
-#endif
-#include <private/qqmlplatform_p.h>
-#include <private/qqmlloggingcategory_p.h>
#ifdef Q_OS_WIN // for %APPDATA%
# include <qt_windows.h>
-# ifndef Q_OS_WINRT
-# include <shlobj.h>
-# endif
-# include <qlibrary.h>
+# include <shlobj.h>
+# include <QtCore/qlibrary.h>
# ifndef CSIDL_APPDATA
# define CSIDL_APPDATA 0x001a // <username>\Application Data
# endif
#endif // Q_OS_WIN
-Q_DECLARE_METATYPE(QQmlProperty)
-
QT_BEGIN_NAMESPACE
-// Declared in qqml.h
-int qmlRegisterUncreatableMetaObject(const QMetaObject &staticMetaObject,
- const char *uri, int versionMajor,
- int versionMinor, const char *qmlName,
- const QString& reason)
-{
- QQmlPrivate::RegisterType type = {
- 0,
-
- 0,
- 0,
- 0,
- nullptr,
- reason,
-
- uri, versionMajor, versionMinor, qmlName, &staticMetaObject,
-
- QQmlAttachedPropertiesFunc(),
- nullptr,
-
- 0,
- 0,
- 0,
-
- nullptr, nullptr,
-
- nullptr,
- 0
- };
-
- return QQmlPrivate::qmlregister(QQmlPrivate::TypeRegistration, &type);
-}
+void qml_register_types_QML();
/*!
\qmltype QtObject
@@ -194,28 +108,9 @@ int qmlRegisterUncreatableMetaObject(const QMetaObject &staticMetaObject,
\endcode
*/
-bool QQmlEnginePrivate::qml_debugging_enabled = false;
+Q_CONSTINIT std::atomic<bool> QQmlEnginePrivate::qml_debugging_enabled{false};
bool QQmlEnginePrivate::s_designerMode = false;
-void QQmlEnginePrivate::defineModule()
-{
- const char uri[] = "QtQml";
-
- qmlRegisterTypesAndRevisions<
- QObjectForeign,
-#if QT_CONFIG(qml_animation)
- QQmlTimer,
-#endif
-#if QT_CONFIG(qml_locale)
- QQmlLocale,
-#endif
- QQmlComponent,
- QQmlBind,
- QQmlConnections,
- QQmlLoggingCategory
- >(uri, 2);
-}
-
bool QQmlEnginePrivate::designerMode()
{
return s_designerMode;
@@ -290,440 +185,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 "winrt" - WinRT / UWP
- \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, {QtQuick.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),
- cleanup(nullptr), 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
- urlInterceptor(nullptr), 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);
- while (cleanup) {
- QQmlCleanup *c = cleanup;
- cleanup = c->next;
- if (cleanup) cleanup->prev = &cleanup;
- c->next = nullptr;
- c->prev = nullptr;
- c->clear();
- }
-
- 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;
-
- // since unregisterInternalCompositeType() will not be called in this
- // case, we have to clean up the type registration manually
- QMetaType::unregisterType(iter.value()->metaTypeId);
- QMetaType::unregisterType(iter.value()->listMetaTypeId);
- }
#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 (QQmlContextData *lc = d->ownContext->linkedContext; lc; lc = lc->linkedContext) {
- lc->invalidate();
- if (lc->contextObject == o)
- lc->contextObject = nullptr;
- }
- d->ownContext->invalidate();
- if (d->ownContext->contextObject == o)
- d->ownContext->contextObject = 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->contextObject = 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()
- : ownedByQml1(false), 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), parentFrozen(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();
@@ -736,18 +255,9 @@ QQmlData::~QQmlData()
void QQmlData::destroyed(QAbstractDeclarativeData *d, QObject *o)
{
QQmlData *ddata = static_cast<QQmlData *>(d);
- if (ddata->ownedByQml1)
- return;
ddata->destroyed(o);
}
-void QQmlData::parentChanged(QAbstractDeclarativeData *d, QObject *o, QObject *p)
-{
- QQmlData *ddata = static_cast<QQmlData *>(d);
- if (ddata->ownedByQml1)
- return;
- ddata->parentChanged(o, p);
-}
class QQmlThreadNotifierProxyObject : public QObject
{
@@ -775,7 +285,6 @@ void QQmlData::signalEmitted(QAbstractDeclarativeData *, QObject *object, int in
{
QQmlData *ddata = QQmlData::get(object, false);
if (!ddata) return; // Probably being deleted
- if (ddata->ownedByQml1) return;
// In general, QML only supports QObject's that live on the same thread as the QQmlEngine
// that they're exposed to. However, to make writing "worker objects" that calculate data
@@ -783,43 +292,48 @@ 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 &&
- QThread::currentThreadId() != QObjectPrivate::get(object)->threadData->threadId.loadRelaxed()) {
- if (!QObjectPrivate::get(object)->threadData->thread.loadAcquire())
+ // 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();
+ if (QThread::currentThreadId() != objectThreadData->threadId.loadRelaxed()) {
+ if (!objectThreadData->thread.loadAcquire())
return;
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();
- int *types = ev->types();
+ 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::VoidStar;
+ types[ii + 1] = QMetaType(QMetaType::VoidStar);
else
- types[ii + 1] = QMetaType::type(typeName);
+ types[ii + 1] = QMetaType::fromName(typeName);
- if (!types[ii + 1]) {
+ if (!types[ii + 1].isValid()) {
qWarning("QObject::connect: Cannot queue arguments of type '%s'\n"
"(Make sure '%s' is registered using qRegisterMetaType().)",
typeName.constData(), typeName.constData());
return;
}
- args[ii + 1] = QMetaType::create(types[ii + 1], a[ii + 1]);
+ args[ii + 1] = types[ii + 1].create(a[ii + 1]);
}
QQmlThreadNotifierProxyObject *mpo = new QQmlThreadNotifierProxyObject;
mpo->target = object;
- mpo->moveToThread(QObjectPrivate::get(object)->threadData->thread.loadAcquire());
- QCoreApplication::postEvent(mpo, ev.take());
+ mpo->moveToThread(objectThreadData->thread.loadAcquire());
+ QCoreApplication::postEvent(mpo, ev.release());
} else {
QQmlNotifierEndpoint *ep = ddata->notify(index);
@@ -830,16 +344,12 @@ void QQmlData::signalEmitted(QAbstractDeclarativeData *, QObject *object, int in
int QQmlData::receivers(QAbstractDeclarativeData *d, const QObject *, int index)
{
QQmlData *ddata = static_cast<QQmlData *>(d);
- if (ddata->ownedByQml1)
- return 0;
return ddata->endpointCount(index);
}
bool QQmlData::isSignalConnected(QAbstractDeclarativeData *d, const QObject *, int index)
{
QQmlData *ddata = static_cast<QQmlData *>(d);
- if (ddata->ownedByQml1)
- return false;
return ddata->signalHasEndpoint(index);
}
@@ -859,11 +369,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);
}
}
@@ -872,40 +386,70 @@ void QQmlData::setQueuedForDeletion(QObject *object)
if (object) {
if (QQmlData *ddata = QQmlData::get(object)) {
if (ddata->ownContext) {
- Q_ASSERT(ddata->ownContext == ddata->context);
- ddata->context->emitDestruction();
- if (ddata->ownContext->contextObject == object)
- ddata->ownContext->contextObject = nullptr;
- ddata->ownContext = nullptr;
+ Q_ASSERT(ddata->ownContext.data() == ddata->context);
+ 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;
@@ -914,23 +458,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>>);
+
+ qRegisterMetaType<QQmlScriptString>();
+ qRegisterMetaType<QQmlComponent::Status>();
+ qRegisterMetaType<QList<QObject*> >();
+ qRegisterMetaType<QQmlBinding*>();
- // required for the Compiler.
- qmlRegisterType<QObject>("QML", 1, 0, "QtObject");
- qmlRegisterType<QQmlComponent>("QML", 1, 0, "Component");
+ // 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);
@@ -942,29 +488,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.
+ 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.
- \code
- QQmlEngine engine;
- QQmlComponent component(&engine);
- component.setData("import QtQuick 2.0\nText { text: \"Hello world!\" }", QUrl());
- QQuickItem *item = qobject_cast<QQuickItem *>(component.create());
+ 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}.
- //add item to view, etc
- ...
- \endcode
-
- In this case, the Text item will be created in the engine's
- \l {QQmlEngine::rootContext()}{root context}.
-
- \sa QQmlComponent, QQmlContext, {QML Global Object}
+ \sa QQmlComponent, QQmlContext, {QML Global Object}, QQmlApplicationEngine
*/
/*!
@@ -995,30 +528,29 @@ 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);
- d->typeLoader.invalidate();
-
// Emit onDestruction signals for the root context before
// we destroy the contexts, engine, Singleton Types etc. that
// may be required to handle the destruction signal.
- QQmlContextData::get(rootContext())->emitDestruction();
+ QQmlContextPrivate::get(rootContext())->emitDestruction();
// clean up all singleton type instances which we own.
// 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?
- QList<QQmlType> singletonTypes = QQmlMetaType::qmlSingletonTypes();
- for (const QQmlType &currType : singletonTypes)
- d->destroySingletonInstance(currType);
+ d->singletonInstances.clear();
delete d->rootContext;
d->rootContext = nullptr;
+
+ d->typeLoader.invalidate();
}
/*! \fn void QQmlEngine::quit()
@@ -1055,14 +587,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();
}
/*!
@@ -1080,10 +633,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.
@@ -1100,48 +675,77 @@ QQmlContext *QQmlEngine::rootContext() const
return d->rootContext;
}
+#if QT_DEPRECATED_SINCE(6, 0)
/*!
\internal
+ \deprecated
This API is private for 5.1
- Sets the \a urlInterceptor to be used when resolving URLs in QML.
+ Returns the last QQmlAbstractUrlInterceptor. It must not be modified outside
+ the GUI thread.
+*/
+QQmlAbstractUrlInterceptor *QQmlEngine::urlInterceptor() const
+{
+ Q_D(const QQmlEngine);
+ return d->urlInterceptors.last();
+}
+#endif
+
+/*!
+ Adds a \a urlInterceptor to be used when resolving URLs in QML.
This also applies to URLs used for loading script files and QML types.
- This should not be modifed while the engine is loading files, or URL
- selection may be inconsistent.
+ The URL interceptors should not be modifed while the engine is loading files,
+ or URL selection may be inconsistent. Multiple URL interceptors, when given,
+ will be called in the order they were added for each URL.
+
+ QQmlEngine does not take ownership of the interceptor and won't delete it.
*/
-void QQmlEngine::setUrlInterceptor(QQmlAbstractUrlInterceptor *urlInterceptor)
+void QQmlEngine::addUrlInterceptor(QQmlAbstractUrlInterceptor *urlInterceptor)
{
Q_D(QQmlEngine);
- d->urlInterceptor = urlInterceptor;
+ d->urlInterceptors.append(urlInterceptor);
}
/*!
- \internal
- This API is private for 5.1
+ Remove a \a urlInterceptor that was previously added using
+ \l addUrlInterceptor. The URL interceptors should not be modifed while the
+ engine is loading files, or URL selection may be inconsistent.
- Returns the current QQmlAbstractUrlInterceptor. It must not be modified outside
- the GUI thread.
+ This does not delete the interceptor, but merely removes it from the engine.
+ You can re-use it on the same or a different engine afterwards.
*/
-QQmlAbstractUrlInterceptor *QQmlEngine::urlInterceptor() const
+void QQmlEngine::removeUrlInterceptor(QQmlAbstractUrlInterceptor *urlInterceptor)
+{
+ Q_D(QQmlEngine);
+ d->urlInterceptors.removeOne(urlInterceptor);
+}
+
+/*!
+ Run the current URL interceptors on the given \a url of the given \a type and
+ return the result.
+ */
+QUrl QQmlEngine::interceptUrl(const QUrl &url, QQmlAbstractUrlInterceptor::DataType type) const
{
Q_D(const QQmlEngine);
- return d->urlInterceptor;
+ QUrl result = url;
+ for (QQmlAbstractUrlInterceptor *interceptor : d->urlInterceptors)
+ result = interceptor->intercept(result, type);
+ 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);
}
@@ -1236,7 +840,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));
}
@@ -1249,7 +853,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();
}
@@ -1262,7 +866,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);
}
@@ -1280,7 +884,9 @@ QUrl QQmlEngine::baseUrl() const
{
Q_D(const QQmlEngine);
if (d->baseUrl.isEmpty()) {
- return QUrl::fromLocalFile(QDir::currentPath() + QDir::separator());
+ const QString currentPath = QDir::currentPath();
+ const QString rootPath = QDir::rootPath();
+ return QUrl::fromLocalFile((currentPath == rootPath) ? rootPath : (currentPath + QDir::separator()));
} else {
return d->baseUrl;
}
@@ -1325,6 +931,75 @@ 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
+
+ Capture the given property as part of a binding.
+ */
+void QQmlEngine::captureProperty(QObject *object, const QMetaProperty &property) const
+{
+ Q_D(const QQmlEngine);
+ if (d->propertyCapture && !property.isConstant()) {
+ d->propertyCapture->captureProperty(
+ object, property.propertyIndex(),
+ QMetaObjectPrivate::signalIndex(property.notifySignal()));
+ }
+}
+
+/*!
+ \qmlproperty string Qt::uiLanguage
+ \since 5.15
+
+ The uiLanguage holds the name of the language to be used for user interface
+ string translations. It is exposed in C++ as QQmlEngine::uiLanguage property.
+
+ You can set the value freely and use it in bindings. It is recommended to set it
+ after installing translators in your application. By convention, an empty string
+ means no translation from the language used in the source code is intended to occur.
+
+ If you're using QQmlApplicationEngine and the value changes, QQmlEngine::retranslate()
+ will be called.
+*/
+
/*!
\fn template<typename T> T QQmlEngine::singletonInstance(int qmlTypeId)
@@ -1336,43 +1011,30 @@ void QQmlEngine::setOutputWarningsToStandardError(bool enabled)
type, either a default constructed QJSValue or a \c nullptr is returned.
QObject* example:
- \code
- class MySingleton : public QObject {
- Q_OBJECT
- static int typeId;
- // ...
- };
- // Register with QObject* callback
- MySingleton::typeId = qmlRegisterSingletonType<MySingleton>(...);
-
- // Retrieve as QObject*
- QQmlEngine engine;
- MySingleton* instance = engine.singletonInstance<MySingleton*>(MySingleton::typeId);
- \endcode
+ \snippet code/src_qml_qqmlengine.cpp 0
+ \codeline
+ \snippet code/src_qml_qqmlengine.cpp 1
+ \codeline
+ \snippet code/src_qml_qqmlengine.cpp 2
QJSValue example:
- \code
- // Register with QJSValue callback
- int typeId = qmlRegisterSingletonType(...);
- // Retrieve as QJSValue
- QQmlEngine engine;
- QJSValue instance = engine.singletonInstance<QJSValue>(typeId);
- \endcode
+ \snippet code/src_qml_qqmlengine.cpp 3
+ \codeline
+ \snippet code/src_qml_qqmlengine.cpp 4
- It is recommended to store the QML type id during registration, e.g. as a static member
- in the singleton class. Otherwise, a costly lookup via qmlTypeId() has to be performed
- at run-time.
+ It is recommended to store the QML type id, e.g. as a static member in the
+ singleton class. The lookup via qmlTypeId() is costly.
- \sa qmlRegisterSingletonType(), qmlTypeId()
+ \sa QML_SINGLETON, qmlRegisterSingletonType(), qmlTypeId()
\since 5.12
*/
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();
@@ -1380,6 +1042,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.
@@ -1387,31 +1091,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);
- QQmlContextData *context = QQmlContextData::get(d->rootContext)->childContexts;
- while (context) {
- context->refreshExpressions();
- context = context->nextChild;
- }
+ 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)
{
@@ -1444,78 +1140,10 @@ void QQmlEngine::setContextForObject(QObject *object, QQmlContext *context)
return;
}
- QQmlContextData *contextData = QQmlContextData::get(context);
+ QQmlRefPointer<QQmlContextData> contextData = QQmlContextData::get(context);
Q_ASSERT(data->context == nullptr);
- data->context = contextData;
- contextData->addObject(data);
-}
-
-/*!
- \enum QQmlEngine::ObjectOwnership
-
- ObjectOwnership controls whether or not QML automatically destroys the
- QObject when the corresponding JavaScript object is garbage collected by the
- engine. The two ownership options are:
-
- \value CppOwnership The object is owned by C++ code and QML will never delete
- it. The JavaScript destroy() method cannot be used on these objects. This
- option is similar to QScriptEngine::QtOwnership.
-
- \value JavaScriptOwnership The object is owned by JavaScript. When the object
- is returned to QML as the return value of a method call, QML will track it
- and delete it if there are no remaining JavaScript references to it and
- it has no QObject::parent(). An object tracked by one QQmlEngine will be
- deleted during that QQmlEngine's destructor. Thus, JavaScript references
- between objects with JavaScriptOwnership from two different engines will
- not be valid if one of these engines is deleted. This option is similar to
- QScriptEngine::ScriptOwnership.
-
- Generally an application doesn't need to set an object's ownership
- explicitly. QML uses a heuristic to set the default ownership. By default, an
- object that is created by QML has JavaScriptOwnership. The exception to this
- are the root objects created by calling QQmlComponent::create() or
- QQmlComponent::beginCreate(), which have CppOwnership by default. The
- ownership of these root-level objects is considered to have been transferred
- to the C++ caller.
-
- Objects not-created by QML have CppOwnership by default. The exception to this
- are objects returned from C++ method calls; their ownership will be set to
- JavaScriptOwnership. This applies only to explicit invocations of Q_INVOKABLE
- methods or slots, but not to property getter invocations.
-
- Calling setObjectOwnership() overrides the default ownership heuristic used by
- QML.
-*/
-
-/*!
- Sets the \a ownership of \a object.
-*/
-void QQmlEngine::setObjectOwnership(QObject *object, ObjectOwnership ownership)
-{
- if (!object)
- return;
-
- QQmlData *ddata = QQmlData::get(object, true);
- if (!ddata)
- return;
-
- ddata->indestructible = (ownership == CppOwnership)?true:false;
- ddata->explicitIndestructibleSet = true;
-}
-
-/*!
- Returns the ownership of \a object.
-*/
-QQmlEngine::ObjectOwnership QQmlEngine::objectOwnership(QObject *object)
-{
- if (!object)
- return CppOwnership;
-
- QQmlData *ddata = QQmlData::get(object, false);
- if (!ddata)
- return CppOwnership;
- else
- return ddata->indestructible?CppOwnership:JavaScriptOwnership;
+ data->context = contextData.data();
+ contextData->addOwnedObject(data);
}
/*!
@@ -1523,165 +1151,13 @@ QQmlEngine::ObjectOwnership QQmlEngine::objectOwnership(QObject *object)
*/
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;
-}
-
-namespace QtQml {
-
-void qmlExecuteDeferred(QObject *object)
-{
- QQmlData *data = QQmlData::get(object);
-
- if (data && !data->deferredData.isEmpty() && !data->wasDeleted(object)) {
- QQmlEnginePrivate *ep = QQmlEnginePrivate::get(data->context->engine);
-
- 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)
-{
- return QQmlEngine::contextForObject(obj);
-}
-
-QQmlEngine *qmlEngine(const QObject *obj)
-{
- QQmlData *data = QQmlData::get(obj, false);
- if (!data || !data->context)
- return nullptr;
- return data->context->engine;
-}
-
-static QObject *resolveAttachedProperties(QQmlAttachedPropertiesFunc pf, QQmlData *data,
- QObject *object, bool create)
-{
- if (!pf)
- return nullptr;
-
- QObject *rv = data->hasExtendedData() ? data->attachedProperties()->value(pf) : 0;
- if (rv || !create)
- return rv;
-
- rv = pf(object);
-
- if (rv)
- data->attachedProperties()->insert(pf, rv);
-
- return rv;
-}
-
-#if QT_DEPRECATED_SINCE(5, 14)
-QObject *qmlAttachedPropertiesObjectById(int id, const QObject *object, bool create)
-{
- QQmlData *data = QQmlData::get(object, create);
-
- // Attached properties are only on objects created by QML,
- // unless explicitly requested (create==true)
- if (!data)
- return nullptr;
-
- QQmlEnginePrivate *engine = QQmlEnginePrivate::get(data->context);
- return resolveAttachedProperties(QQmlMetaType::attachedPropertiesFuncById(engine, id), data,
- const_cast<QObject *>(object), create);
-}
-
-QObject *qmlAttachedPropertiesObject(int *idCache, const QObject *object,
- const QMetaObject *attachedMetaObject, bool create)
-{
- if (*idCache == -1) {
- QQmlEngine *engine = object ? qmlEngine(object) : nullptr;
- *idCache = QQmlMetaType::attachedPropertiesFuncId(engine ? QQmlEnginePrivate::get(engine) : nullptr, attachedMetaObject);
- }
-
- if (*idCache == -1 || !object)
- return nullptr;
-
- return qmlAttachedPropertiesObjectById(*idCache, object, create);
-}
-#endif
-
-QQmlAttachedPropertiesFunc qmlAttachedPropertiesFunction(QObject *object,
- const QMetaObject *attachedMetaObject)
-{
- QQmlEngine *engine = object ? qmlEngine(object) : nullptr;
- return QQmlMetaType::attachedPropertiesFunc(engine ? QQmlEnginePrivate::get(engine) : nullptr,
- attachedMetaObject);
-}
-
-QObject *qmlAttachedPropertiesObject(QObject *object, QQmlAttachedPropertiesFunc func, bool create)
-{
- if (!object)
- return nullptr;
-
- QQmlData *data = QQmlData::get(object, create);
-
- // Attached properties are only on objects created by QML,
- // unless explicitly requested (create==true)
- if (!data)
- return nullptr;
-
- return resolveAttachedProperties(func, data, object, create);
-}
-
-} // namespace QtQml
-
-#if QT_DEPRECATED_SINCE(5, 1)
-
-// Also define symbols outside namespace to keep binary compatibility with Qt 5.0
-
-Q_QML_EXPORT void qmlExecuteDeferred(QObject *obj)
-{
- QtQml::qmlExecuteDeferred(obj);
-}
-
-Q_QML_EXPORT QQmlContext *qmlContext(const QObject *obj)
-{
- return QtQml::qmlContext(obj);
-}
-
-Q_QML_EXPORT QQmlEngine *qmlEngine(const QObject *obj)
-{
- return QtQml::qmlEngine(obj);
-}
-
-Q_QML_EXPORT QObject *qmlAttachedPropertiesObjectById(int id, const QObject *obj, bool create)
-{
- return QtQml::qmlAttachedPropertiesObjectById(id, obj, create);
-}
-
-Q_QML_EXPORT QObject *qmlAttachedPropertiesObject(int *idCache, const QObject *object,
- const QMetaObject *attachedMetaObject,
- bool create)
-{
- return QtQml::qmlAttachedPropertiesObject(idCache, object, attachedMetaObject, create);
-}
-
-#endif // QT_DEPRECATED_SINCE(5, 1)
-
class QQmlDataExtended {
public:
QQmlDataExtended();
@@ -1751,7 +1227,9 @@ void QQmlData::NotifyList::layout()
todo = nullptr;
}
-void QQmlData::deferData(int objectIndex, const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit, QQmlContextData *context)
+void QQmlData::deferData(
+ int objectIndex, const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit,
+ const QQmlRefPointer<QQmlContextData> &context)
{
QQmlData::DeferredData *deferData = new QQmlData::DeferredData;
deferData->deferredIdx = objectIndex;
@@ -1759,13 +1237,14 @@ void QQmlData::deferData(int objectIndex, const QQmlRefPointer<QV4::ExecutableCo
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);
@@ -1787,49 +1266,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;
+
+ }
}
}
@@ -1845,8 +1348,8 @@ void QQmlData::destroyed(QObject *object)
nextContextObject->prevContextObject = prevContextObject;
if (prevContextObject)
*prevContextObject = nextContextObject;
- else if (outerContext && outerContext->contextObjects == this)
- outerContext->contextObjects = nextContextObject;
+ else if (outerContext && outerContext->ownedObjects() == this)
+ outerContext->setOwnedObjects(nextContextObject);
QQmlAbstractBinding *binding = bindings;
while (binding) {
@@ -1856,7 +1359,7 @@ void QQmlData::destroyed(QObject *object)
if (bindings && !bindings->ref.deref())
delete bindings;
- compilationUnit = nullptr;
+ compilationUnit.reset();
qDeleteAll(deferredData);
deferredData.clear();
@@ -1903,17 +1406,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;
@@ -1927,25 +1431,6 @@ void QQmlData::destroyed(QObject *object)
this->~QQmlData();
}
-DEFINE_BOOL_CONFIG_OPTION(parentTest, QML_PARENT_TEST);
-
-void QQmlData::parentChanged(QObject *object, QObject *parent)
-{
- if (parentTest()) {
- if (parentFrozen && !QObjectPrivate::get(object)->wasDeleted) {
- QString on;
- QString pn;
-
- { QDebug dbg(&on); dbg << object; on = on.left(on.length() - 1); }
- { QDebug dbg(&pn); dbg << parent; pn = pn.left(pn.length() - 1); }
-
- qFatal("Object %s has had its parent frozen by QML and cannot be changed.\n"
- "User code is attempting to change it to %s.\n"
- "This behavior is NOT supported!", qPrintable(on), qPrintable(pn));
- }
- }
-}
-
QQmlData::BindingBitsType *QQmlData::growBits(QObject *obj, int bit)
{
BindingBitsType *bits = (bindingBitsArraySize == InlineBindingArraySize) ? bindingBitsValue : bindingBits;
@@ -1973,16 +1458,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);
- if (ddata->propertyCache)
- ddata->propertyCache->addref();
+ ddata->propertyCache = QQmlMetaType::propertyCache(object, QTypeRevision {});
return ddata->propertyCache;
}
@@ -2008,38 +1491,38 @@ static void dumpwarning(const QQmlError &error)
switch (error.messageType()) {
case QtDebugMsg:
QMessageLogger(error.url().toString().toLatin1().constData(),
- error.line(), nullptr).debug().nospace()
- << qPrintable(error.toString());
+ error.line(), nullptr).debug().noquote().nospace()
+ << error.toString();
break;
case QtInfoMsg:
QMessageLogger(error.url().toString().toLatin1().constData(),
- error.line(), nullptr).info().nospace()
- << qPrintable(error.toString());
+ error.line(), nullptr).info().noquote().nospace()
+ << error.toString();
break;
case QtWarningMsg:
case QtFatalMsg: // fatal does not support streaming, and furthermore, is actually fatal. Probably not desirable for QML.
QMessageLogger(error.url().toString().toLatin1().constData(),
- error.line(), nullptr).warning().nospace()
- << qPrintable(error.toString());
+ error.line(), nullptr).warning().noquote().nospace()
+ << error.toString();
break;
case QtCriticalMsg:
QMessageLogger(error.url().toString().toLatin1().constData(),
- error.line(), nullptr).critical().nospace()
- << qPrintable(error.toString());
+ error.line(), nullptr).critical().noquote().nospace()
+ << error.toString();
break;
}
}
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);
}
@@ -2047,7 +1530,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);
}
@@ -2090,15 +1573,15 @@ QList<QQmlError> QQmlEnginePrivate::qmlErrorFromDiagnostics(
QList<QQmlError> errors;
for (const QQmlJS::DiagnosticMessage &m : diagnosticMessages) {
if (m.isWarning()) {
- qWarning("%s:%d : %s", qPrintable(fileName), m.line, qPrintable(m.message));
+ qWarning("%s:%d : %s", qPrintable(fileName), m.loc.startLine, qPrintable(m.message));
continue;
}
QQmlError error;
error.setUrl(QUrl(fileName));
error.setDescription(m.message);
- error.setLine(m.line);
- error.setColumn(m.column);
+ error.setLine(qmlConvertSourceCoordinate<quint32, int>(m.loc.startLine));
+ error.setColumn(qmlConvertSourceCoordinate<quint32, int>(m.loc.startColumn));
errors << error;
}
return errors;
@@ -2130,7 +1613,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)
{
@@ -2148,9 +1632,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 QML2_IMPORT_PATH environment variable,
- and the builtin \c Qml2ImportsPath from QLibraryInfo.
+ By default, this list contains the paths mentioned in
+ \l {QML Import Path}.
\sa addImportPath(), setImportPathList()
*/
@@ -2164,9 +1647,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 QML2_IMPORT_PATH environment variable,
- and the builtin \c Qml2ImportsPath 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()
*/
@@ -2194,7 +1679,6 @@ void QQmlEngine::addPluginPath(const QString& path)
d->importDatabase.addPluginPath(path);
}
-
/*!
Returns the list of directories where the engine searches for
native plugins for imported modules (referenced in the \c qmldir file).
@@ -2227,20 +1711,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(), -1, errors);
+ QQmlTypeLoaderQmldirContent qmldir;
+ QQmlPluginImporter importer(
+ uri, QTypeRevision(), &d->importDatabase, &qmldir, &d->typeLoader, errors);
+ return importer.importDynamicPlugin(filePath, uri, false).isValid();
}
#endif
+#endif
/*!
\property QQmlEngine::offlineStoragePath
@@ -2249,7 +1744,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.
@@ -2257,11 +1752,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
@@ -2269,12 +1776,14 @@ QString QQmlEngine::offlineStoragePath() const
Q_D(const QQmlEngine);
if (d->offlineStoragePath.isEmpty()) {
- QString dataLocation = QStandardPaths::writableLocation(QStandardPaths::DataLocation);
+ 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;
@@ -2295,144 +1804,24 @@ QString QQmlEngine::offlineStorageDatabaseFilePath(const QString &databaseName)
return d->offlineStorageDatabaseDirectory() + QLatin1String(md5.result().toHex());
}
-// #### Qt 6: Remove this function, it exists only for binary compatibility.
-/*!
- * \internal
- */
-bool QQmlEngine::addNamedBundle(const QString &name, const QString &fileName)
-{
- Q_UNUSED(name)
- Q_UNUSED(fileName)
- return false;
-}
-
QString QQmlEnginePrivate::offlineStorageDatabaseDirectory() const
{
Q_Q(const QQmlEngine);
return q->offlineStoragePath() + QDir::separator() + QLatin1String("Databases") + QDir::separator();
}
-bool QQmlEnginePrivate::isQObject(int t)
-{
- Locker locker(this);
- return m_compositeTypes.contains(t) || QQmlMetaType::isQObject(t);
-}
-
-QObject *QQmlEnginePrivate::toQObject(const QVariant &v, bool *ok) const
-{
- Locker locker(this);
- int t = v.userType();
- if (t == QMetaType::QObjectStar || m_compositeTypes.contains(t)) {
- if (ok) *ok = true;
- return *(QObject *const *)(v.constData());
- } else {
- return QQmlMetaType::toQObject(v, ok);
- }
-}
-
-QQmlMetaType::TypeCategory QQmlEnginePrivate::typeCategory(int t) const
-{
- Locker locker(this);
- if (m_compositeTypes.contains(t))
- return QQmlMetaType::Object;
- return QQmlMetaType::typeCategory(t);
-}
-
-bool QQmlEnginePrivate::isList(int t) const
-{
- return QQmlMetaType::isList(t);
-}
-
-int QQmlEnginePrivate::listType(int t) const
-{
- return QQmlMetaType::listType(t);
-}
-
-QQmlMetaObject QQmlEnginePrivate::rawMetaObjectForType(int t) const
-{
- Locker locker(this);
- auto iter = m_compositeTypes.constFind(t);
- if (iter != m_compositeTypes.cend()) {
- return QQmlMetaObject((*iter)->rootPropertyCache().data());
- } else {
- QQmlType type = QQmlMetaType::qmlType(t);
- return QQmlMetaObject(type.baseMetaObject());
- }
-}
-
-QQmlMetaObject QQmlEnginePrivate::metaObjectForType(int t) const
-{
- Locker locker(this);
- auto iter = m_compositeTypes.constFind(t);
- if (iter != m_compositeTypes.cend()) {
- return QQmlMetaObject((*iter)->rootPropertyCache().data());
- } else {
- QQmlType type = QQmlMetaType::qmlType(t);
- return QQmlMetaObject(type.metaObject());
- }
-}
-
-QQmlPropertyCache *QQmlEnginePrivate::propertyCacheForType(int t)
-{
- Locker locker(this);
- auto iter = m_compositeTypes.constFind(t);
- if (iter != m_compositeTypes.cend()) {
- return (*iter)->rootPropertyCache().data();
- } else {
- QQmlType type = QQmlMetaType::qmlType(t);
- locker.unlock();
- return type.isValid() ? cache(type.metaObject()) : nullptr;
- }
-}
-
-QQmlPropertyCache *QQmlEnginePrivate::rawPropertyCacheForType(int t, int minorVersion)
-{
- Locker locker(this);
- auto iter = m_compositeTypes.constFind(t);
- if (iter != m_compositeTypes.cend()) {
- return (*iter)->rootPropertyCache().data();
- } else {
- QQmlType type = QQmlMetaType::qmlType(t);
- locker.unlock();
-
- if (minorVersion >= 0)
- return type.isValid() ? cache(type, minorVersion) : nullptr;
- else
- return type.isValid() ? cache(type.baseMetaObject()) : nullptr;
- }
-}
-
-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->metaTypeId, compilationUnit);
-}
-
-void QQmlEnginePrivate::unregisterInternalCompositeType(QV4::ExecutableCompilationUnit *compilationUnit)
-{
- compilationUnit->isRegisteredWithEngine = false;
-
- Locker locker(this);
- m_compositeTypes.remove(compilationUnit->metaTypeId);
-}
-
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()) {
@@ -2441,7 +1830,7 @@ QJSValue QQmlEnginePrivate::singletonInstance<QJSValue>(const QQmlType &type)
// should behave identically to QML singleton types.
q->setContextForObject(o, new QQmlContext(q->rootContext(), q));
}
- singletonInstances.insert(type, value);
+ singletonInstances.convertAndInsert(v4engine(), siinfo, &value);
} else if (siinfo->qobjectCallback) {
QObject *o = siinfo->qobjectCallback(q, q);
@@ -2452,49 +1841,178 @@ QJSValue QQmlEnginePrivate::singletonInstance<QJSValue>(const QQmlType &type)
qPrintable(QString::fromUtf8(type.typeName()))));
warning(error);
} else {
+ 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.insert(type, value);
+ singletonInstances.convertAndInsert(v4engine(), siinfo, &value);
} else if (!siinfo->url.isEmpty()) {
QQmlComponent component(q, siinfo->url, QQmlComponent::PreferSynchronous);
+ if (component.isError()) {
+ warning(component.errors());
+ v4engine()->throwError(QLatin1String("Due to the preceding error(s), Singleton \"%1\" could not be loaded.").arg(QString::fromUtf8(type.typeName())));
+
+ return QJSValue(QJSValue::UndefinedValue);
+ }
QObject *o = component.beginCreate(q->rootContext());
+ auto *compPriv = QQmlComponentPrivate::get(&component);
+ if (compPriv->state.hasUnsetRequiredProperties()) {
+ /* We would only get the errors from the component after (complete)Create.
+ We can't call create, as we need to convertAndInsert before completeCreate (otherwise
+ tst_qqmllanguage::compositeSingletonCircular fails).
+ On the other hand, we don't want to call cnovertAndInsert if we have an error
+ So create the unset required component errors manually.
+ */
+ delete o;
+ const auto requiredProperties = compPriv->state.requiredProperties();
+ QList<QQmlError> errors (requiredProperties->size());
+ for (const auto &reqProp: *requiredProperties)
+ errors.push_back(QQmlComponentPrivate::unsetRequiredPropertyToQQmlError(reqProp));
+ warning(errors);
+ v4engine()->throwError(QLatin1String("Due to the preceding error(s), Singleton \"%1\" could not be loaded.").arg(QString::fromUtf8(type.typeName())));
+ return QJSValue(QJSValue::UndefinedValue);
+ }
+
value = q->newQObject(o);
- singletonInstances.insert(type, value);
+ singletonInstances.convertAndInsert(v4engine(), siinfo, &value);
component.completeCreate();
}
return value;
}
-void QQmlEnginePrivate::destroySingletonInstance(const QQmlType &type)
+bool QQmlEnginePrivate::isTypeLoaded(const QUrl &url) const
{
- Q_ASSERT(type.isSingleton() || type.isCompositeSingleton());
+ return typeLoader.isTypeLoaded(url);
+}
- 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::isScriptLoaded(const QUrl &url) const
+{
+ return typeLoader.isScriptLoaded(url);
+}
+
+void QQmlEnginePrivate::executeRuntimeFunction(const QUrl &url, qsizetype functionIndex,
+ QObject *thisObject, int argc, void **args,
+ QMetaType *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::Scoped<QV4::JavaScriptFunctionObject> 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());
}
+
+ v4->callInContext(function, thisObject, callContext, argc, args, types);
}
-bool QQmlEnginePrivate::isTypeLoaded(const QUrl &url) const
+QV4::ExecutableCompilationUnit *QQmlEnginePrivate::compilationUnitFromUrl(const QUrl &url)
{
- return typeLoader.isTypeLoaded(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();
}
-bool QQmlEnginePrivate::isScriptLoaded(const QUrl &url) const
+QQmlRefPointer<QQmlContextData>
+QQmlEnginePrivate::createInternalContext(const QQmlRefPointer<QV4::ExecutableCompilationUnit> &unit,
+ const QQmlRefPointer<QQmlContextData> &parentContext,
+ int subComponentIndex, bool isComponentRoot)
{
- return typeLoader.isScriptLoaded(url);
+ 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) && !defined(Q_OS_WINRT)
+#if defined(Q_OS_WIN)
// Normalize a file name using Shell API. As opposed to converting it
// to a short 8.3 name and back, this also works for drives where 8.3 notation
// is disabled (see 8dot3name options of fsutil.exe).
@@ -2526,15 +2044,15 @@ static inline QString shellNormalizeFileName(const QString &name)
canonicalName[0] = canonicalName.at(0).toUpper();
return QDir::cleanPath(canonicalName);
}
-#endif // Q_OS_WIN && !Q_OS_WINRT
+#endif // Q_OS_WIN
bool QQml_isFileCaseCorrect(const QString &fileName, int lengthIn /* = -1 */)
{
-#if defined(Q_OS_MAC) || defined(Q_OS_WIN)
+#if defined(Q_OS_DARWIN) || defined(Q_OS_WIN)
QFileInfo info(fileName);
const QString absolute = info.absoluteFilePath();
-#if defined(Q_OS_DARWIN) || defined(Q_OS_WINRT)
+#if defined(Q_OS_DARWIN)
const QString canonical = info.canonicalFilePath();
#elif defined(Q_OS_WIN)
// No difference if the path is qrc based
@@ -2571,8 +2089,8 @@ bool QQml_isFileCaseCorrect(const QString &fileName, int lengthIn /* = -1 */)
return false;
}
#else
- Q_UNUSED(lengthIn)
- Q_UNUSED(fileName)
+ Q_UNUSED(lengthIn);
+ Q_UNUSED(fileName);
#endif
return true;
}
@@ -2601,6 +2119,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 31fe3a1849..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
@@ -46,21 +10,20 @@
#include <QtQml/qjsengine.h>
#include <QtQml/qqml.h>
#include <QtQml/qqmlerror.h>
+#include <QtQml/qqmlabstracturlinterceptor.h>
QT_BEGIN_NAMESPACE
-class QQmlAbstractUrlInterceptor;
-
-class Q_QML_EXPORT QQmlImageProviderBase
+class Q_QML_EXPORT QQmlImageProviderBase : public QObject
{
+ Q_OBJECT
public:
- enum ImageType {
+ enum ImageType : int {
+ Invalid = 0,
Image,
Pixmap,
Texture,
- Invalid,
- ImageResponse
- // ### Qt6: reorder these, and give Invalid a fixed large value
+ ImageResponse,
};
enum Flag {
@@ -81,7 +44,6 @@ Q_DECLARE_OPERATORS_FOR_FLAGS(QQmlImageProviderBase::Flags)
class QQmlComponent;
class QQmlEnginePrivate;
-class QQmlImportsPrivate;
class QQmlExpression;
class QQmlContext;
class QQmlType;
@@ -93,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);
@@ -103,6 +65,7 @@ public:
void clearComponentCache();
void trimComponentCache();
+ void clearSingletons();
QStringList importPathList() const;
void setImportPathList(const QStringList &paths);
@@ -112,11 +75,16 @@ public:
void setPluginPathList(const QStringList &paths);
void addPluginPath(const QString& dir);
- bool addNamedBundle(const QString &name, const QString &fileName);
+#if QT_DEPRECATED_SINCE(6, 0)
+ QT_DEPRECATED bool addNamedBundle(const QString &, const QString &) { return false; }
+#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 *);
@@ -125,8 +93,18 @@ public:
QNetworkAccessManager *networkAccessManager() const;
#endif
- void setUrlInterceptor(QQmlAbstractUrlInterceptor* urlInterceptor);
- QQmlAbstractUrlInterceptor* urlInterceptor() const;
+#if QT_DEPRECATED_SINCE(6, 0)
+ QT_DEPRECATED void setUrlInterceptor(QQmlAbstractUrlInterceptor* urlInterceptor)
+ {
+ addUrlInterceptor(urlInterceptor);
+ }
+ QT_DEPRECATED QQmlAbstractUrlInterceptor *urlInterceptor() const;
+#endif
+
+ 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 *);
QQmlImageProviderBase *imageProvider(const QString &id) const;
@@ -145,19 +123,26 @@ 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 *);
- enum ObjectOwnership { CppOwnership, JavaScriptOwnership };
- static void setObjectOwnership(QObject *, ObjectOwnership);
- static ObjectOwnership objectOwnership(QObject *);
protected:
QQmlEngine(QQmlEnginePrivate &dd, QObject *p);
bool event(QEvent *) override;
@@ -180,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 98c7823921..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,60 +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 "qqmlcontext_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 <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 <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 QQmlCleanup;
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)
- 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
@@ -123,11 +73,35 @@ public:
QQmlJavaScriptExpressionGuard *next;
};
-class Q_QML_PRIVATE_EXPORT QQmlEnginePrivate : public QJSEnginePrivate
+struct QPropertyChangeTrigger : QPropertyObserver {
+ 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 {
+ TriggerList(QQmlJavaScriptExpression *expression)
+ : QPropertyChangeTrigger(expression)
+ {}
+ TriggerList *next = nullptr;
+};
+
+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();
@@ -135,52 +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;
-
- // Registered cleanup handlers
- QQmlCleanup *cleanup;
+ 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;
- QQmlAbstractUrlInterceptor* urlInterceptor;
-
- int scarceResourcesRefCount;
+ int scarceResourcesRefCount = 0;
void referenceScarceResources();
void dereferenceScarceResources();
@@ -189,55 +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;
- void incubate(QQmlIncubator &, QQmlContextData *);
+ 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 &, int);
- using QJSEnginePrivate::cache;
-
- // These methods may be called from the loader thread
- bool isQObject(int);
- QObject *toQObject(const QVariant &, bool *ok = nullptr) const;
- QQmlMetaType::TypeCategory typeCategory(int) const;
- bool isList(int) const;
- int listType(int) const;
- QQmlMetaObject rawMetaObjectForType(int) const;
- QQmlMetaObject metaObjectForType(int) const;
- QQmlPropertyCache *propertyCacheForType(int);
- QQmlPropertyCache *rawPropertyCacheForType(int, int minorVersion = -1);
- void registerInternalCompositeType(QV4::ExecutableCompilationUnit *compilationUnit);
- void unregisterInternalCompositeType(QV4::ExecutableCompilationUnit *compilationUnit);
-
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);
@@ -252,33 +191,108 @@ public:
inline static QQmlEnginePrivate *get(QQmlEngine *e);
inline static const QQmlEnginePrivate *get(const QQmlEngine *e);
inline static QQmlEnginePrivate *get(QQmlContext *c);
- inline static QQmlEnginePrivate *get(QQmlContextData *c);
+ inline static QQmlEnginePrivate *get(const QQmlRefPointer<QQmlContextData> &c);
inline static QQmlEngine *get(QQmlEnginePrivate *p);
inline static QQmlEnginePrivate *get(QV4::ExecutionEngine *e);
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.constFind(typeIndex);
+ if (it != cachedValueTypeInstances.cend())
+ return *it;
+
+ if (QQmlValueType *valueType = QQmlMetaType::valueType(type)) {
+ QQmlGadgetPtrWrapper *instance = new QQmlGadgetPtrWrapper(valueType);
+ cachedValueTypeInstances.insert(typeIndex, instance);
+ return instance;
+ }
+
+ return 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:
- QHash<QQmlType, QJSValue> singletonInstances;
+ class SingletonInstances : private QHash<QQmlType::SingletonInstanceInfo::ConstPtr, QJSValue>
+ {
+ public:
+ void convertAndInsert(
+ QV4::ExecutionEngine *engine, const QQmlType::SingletonInstanceInfo::ConstPtr &type,
+ QJSValue *value)
+ {
+ QJSValuePrivate::manageStringOnV4Heap(engine, value);
+ insert(type, *value);
+ }
- // 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;
+ 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);
+ };
- // 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();
+ 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;
+
+ static bool s_designerMode;
void cleanupScarceResources();
};
@@ -313,83 +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, int minorVersion)
-{
- Q_ASSERT(type.isValid());
-
- if (minorVersion == -1 || !type.containsRevisionedAttributes())
- return cache(type.metaObject(), minorVersion);
-
- Locker locker(this);
- return QQmlMetaType::propertyCache(type, minorVersion);
-}
-
QV4::ExecutionEngine *QQmlEnginePrivate::getV4Engine(QQmlEngine *e)
{
Q_ASSERT(e);
@@ -411,14 +348,24 @@ const QQmlEnginePrivate *QQmlEnginePrivate::get(const QQmlEngine *e)
return e ? e->d_func() : nullptr;
}
+template<typename Context>
+QQmlEnginePrivate *contextEngine(const Context &context)
+{
+ if (!context)
+ return nullptr;
+ if (QQmlEngine *engine = context->engine())
+ return QQmlEnginePrivate::get(engine);
+ return nullptr;
+}
+
QQmlEnginePrivate *QQmlEnginePrivate::get(QQmlContext *c)
{
- return (c && c->engine()) ? QQmlEnginePrivate::get(c->engine()) : nullptr;
+ return contextEngine(c);
}
-QQmlEnginePrivate *QQmlEnginePrivate::get(QQmlContextData *c)
+QQmlEnginePrivate *QQmlEnginePrivate::get(const QQmlRefPointer<QQmlContextData> &c)
{
- return (c && c->engine) ? QQmlEnginePrivate::get(c->engine) : nullptr;
+ return contextEngine(c);
}
QQmlEngine *QQmlEnginePrivate::get(QQmlEnginePrivate *p)
@@ -437,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 0b94ed3b49..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>
@@ -77,12 +40,21 @@ QT_BEGIN_NAMESPACE
\sa QQuickView::errors(), QQmlComponent::errors()
*/
-class QQmlErrorPrivate : public QQmlJS::DiagnosticMessage
+class QQmlErrorPrivate
{
public:
- QQmlErrorPrivate() { type = QtWarningMsg; }
QUrl url;
QPointer<QObject> object;
+ QString message;
+ QtMsgType type = QtWarningMsg;
+ int line = -1;
+ int column = -1;
+
+ friend bool operator==(const QQmlErrorPrivate &a, const QQmlErrorPrivate &b)
+ {
+ return a.url == b.url && a.object == b.object && a.message == b.message
+ && a.type == b.type && a.line == b.line && a.column == b.column;
+ }
};
/*!
@@ -185,7 +157,7 @@ void QQmlError::setDescription(const QString &description)
int QQmlError::line() const
{
if (d)
- return qmlConvertSourceCoordinate<quint32, int>(d->line);
+ return d->line;
return -1;
}
@@ -196,7 +168,7 @@ void QQmlError::setLine(int line)
{
if (!d)
d = new QQmlErrorPrivate;
- d->line = qmlConvertSourceCoordinate<int, quint32>(line);
+ d->line = line;
}
/*!
@@ -205,7 +177,7 @@ void QQmlError::setLine(int line)
int QQmlError::column() const
{
if (d)
- return qmlConvertSourceCoordinate<quint32, int>(d->column);
+ return d->column;
return -1;
}
@@ -216,7 +188,7 @@ void QQmlError::setColumn(int column)
{
if (!d)
d = new QQmlErrorPrivate;
- d->column = qmlConvertSourceCoordinate<int, quint32>(column);
+ d->column = column;
}
/*!
@@ -295,6 +267,11 @@ QString QQmlError::toString() const
return rv;
}
+bool operator==(const QQmlError &a, const QQmlError &b)
+{
+ return a.d == b.d || (a.d && b.d && *a.d == *b.d);
+}
+
/*!
\relates QQmlError
\fn QDebug operator<<(QDebug debug, const QQmlError &error)
@@ -314,19 +291,16 @@ QDebug operator<<(QDebug debug, const QQmlError &error)
if (f.open(QIODevice::ReadOnly)) {
QByteArray data = f.readAll();
QTextStream stream(data, QIODevice::ReadOnly);
-#if QT_CONFIG(textcodec)
- stream.setCodec("UTF-8");
-#endif
const QString code = stream.readAll();
- const auto lines = code.splitRef(QLatin1Char('\n'));
+ const auto lines = QStringView{code}.split(QLatin1Char('\n'));
- if (lines.count() >= error.line()) {
- const QStringRef &line = lines.at(error.line() - 1);
+ 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 8ea493c11d..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;
@@ -76,13 +48,14 @@ public:
void setMessageType(QtMsgType messageType);
QString toString() const;
+ friend bool Q_QML_EXPORT operator==(const QQmlError &a, const QQmlError &b);
private:
QQmlErrorPrivate *d;
};
QDebug Q_QML_EXPORT operator<<(QDebug debug, const QQmlError &error);
-Q_DECLARE_TYPEINFO(QQmlError, Q_MOVABLE_TYPE);
+Q_DECLARE_TYPEINFO(QQmlError, Q_RELOCATABLE_TYPE);
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlexpression.cpp b/src/qml/qml/qqmlexpression.cpp
index f6a5afb891..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>
@@ -63,7 +25,8 @@ QQmlExpressionPrivate::~QQmlExpressionPrivate()
{
}
-void QQmlExpressionPrivate::init(QQmlContextData *ctxt, const QString &expr, QObject *me)
+void QQmlExpressionPrivate::init(const QQmlRefPointer<QQmlContextData> &ctxt, const QString &expr,
+ QObject *me)
{
expression = expr;
@@ -72,10 +35,11 @@ void QQmlExpressionPrivate::init(QQmlContextData *ctxt, const QString &expr, QOb
expressionFunctionValid = false;
}
-void QQmlExpressionPrivate::init(QQmlContextData *ctxt, QV4::Function *runtimeFunction, QObject *me)
+void QQmlExpressionPrivate::init(const QQmlRefPointer<QQmlContextData> &ctxt,
+ QV4::Function *runtimeFunction, QObject *me)
{
expressionFunctionValid = true;
- QV4::ExecutionEngine *engine = ctxt->engine->handle();
+ QV4::ExecutionEngine *engine = ctxt->engine()->handle();
QV4::Scope scope(engine);
QV4::Scoped<QV4::QmlContext> qmlContext(scope, QV4::QmlContext::create(engine->rootContext(), ctxt, me));
setupFunction(qmlContext, runtimeFunction);
@@ -141,23 +105,35 @@ 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;
- QQmlContextData *evalCtxtData = QQmlContextData::get(ctxt ? ctxt : scriptPrivate->context);
+ QQmlRefPointer<QQmlContextData> evalCtxtData
+ = QQmlContextData::get(ctxt ? ctxt : scriptPrivate->context);
QObject *scopeObject = scope ? scope : scriptPrivate->scope;
QV4::Function *runtimeFunction = nullptr;
if (scriptPrivate->context) {
- QQmlContextData *ctxtdata = QQmlContextData::get(scriptPrivate->context);
+ QQmlRefPointer<QQmlContextData> ctxtdata = QQmlContextData::get(scriptPrivate->context);
QQmlEnginePrivate *engine = QQmlEnginePrivate::get(scriptPrivate->context->engine());
- if (engine && ctxtdata && !ctxtdata->urlString().isEmpty() && ctxtdata->typeCompilationUnit) {
+ if (engine
+ && ctxtdata
+ && !ctxtdata->urlString().isEmpty()
+ && ctxtdata->typeCompilationUnit()) {
d->url = ctxtdata->urlString();
d->line = scriptPrivate->lineNumber;
d->column = scriptPrivate->columnNumber;
if (scriptPrivate->bindingId != QQmlBinding::Invalid)
- runtimeFunction = ctxtdata->typeCompilationUnit->runtimeFunctions.at(scriptPrivate->bindingId);
+ runtimeFunction = ctxtdata->typeCompilationUnit()->runtimeFunctions.at(scriptPrivate->bindingId);
}
}
@@ -175,10 +151,8 @@ QQmlExpression::QQmlExpression(const QQmlScriptString &script, QQmlContext *ctxt
If specified, the \a scope object's properties will also be in scope during
the expression's execution.
*/
-QQmlExpression::QQmlExpression(QQmlContext *ctxt,
- QObject *scope,
- const QString &expression,
- QObject *parent)
+QQmlExpression::QQmlExpression(QQmlContext *ctxt, QObject *scope, const QString &expression,
+ QObject *parent)
: QObject(*new QQmlExpressionPrivate, parent)
{
Q_D(QQmlExpression);
@@ -188,12 +162,10 @@ QQmlExpression::QQmlExpression(QQmlContext *ctxt,
/*!
\internal
*/
-QQmlExpression::QQmlExpression(QQmlContextData *ctxt, QObject *scope,
- const QString &expression)
-: QObject(*new QQmlExpressionPrivate, nullptr)
+QQmlExpression::QQmlExpression(QQmlExpressionPrivate &dd, QObject *parent) : QObject(dd, parent)
{
- Q_D(QQmlExpression);
- d->init(ctxt, expression, scope);
+// Q_D(QQmlExpression);
+// d->init(QQmlContextData::get(ctxt), expression, scope);
}
/*!
@@ -204,24 +176,23 @@ 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
{
Q_D(const QQmlExpression);
- return d->context()?d->context()->engine:nullptr;
+ return d->engine();
}
/*!
- 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
{
Q_D(const QQmlExpression);
- QQmlContextData *data = d->context();
- return data?data->asQQmlContext():nullptr;
+ return d->publicContext();
}
/*!
@@ -265,7 +236,7 @@ QVariant QQmlExpressionPrivate::value(bool *isUndefined)
{
Q_Q(QQmlExpression);
- if (!context() || !context()->isValid()) {
+ if (!hasValidContext()) {
qWarning("QQmlExpression: Attempted to evaluate an expression in an invalid context");
return QVariant();
}
@@ -280,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 0eceeb12e1..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;
@@ -90,7 +53,7 @@ Q_SIGNALS:
void valueChanged();
private:
- QQmlExpression(QQmlContextData *, QObject *, const QString &);
+ QQmlExpression(QQmlExpressionPrivate &dd, QObject *parent);
Q_DISABLE_COPY(QQmlExpression)
Q_DECLARE_PRIVATE(QQmlExpression)
diff --git a/src/qml/qml/qqmlexpression_p.h b/src/qml/qml/qqmlexpression_p.h
index da10b31b2c..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
@@ -70,12 +33,13 @@ public:
QQmlExpressionPrivate();
~QQmlExpressionPrivate() override;
- void init(QQmlContextData *, const QString &, QObject *);
- void init(QQmlContextData *, QV4::Function *runtimeFunction, QObject *);
+ void init(const QQmlRefPointer<QQmlContextData> &, const QString &, QObject *);
+ void init(const QQmlRefPointer<QQmlContextData> &, QV4::Function *runtimeFunction, QObject *);
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 26364661a8..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,24 +84,47 @@ 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
/*!
- \internal
+ \since 6.0
+
+ Override this method to unregister types manually registered in registerTypes.
*/
+void QQmlExtensionPlugin::unregisterTypes()
+{
+}
+
+/*!
+ 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);
@@ -127,8 +132,6 @@ void QQmlExtensionPlugin::initializeEngine(QQmlEngine *engine, const char *uri)
}
/*!
- \fn void QQmlEngineExtensionPlugin::initializeEngine(QQmlEngine *engine, const char *uri)
-
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.
@@ -157,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 ef7ff422cd..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,9 +34,13 @@ 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();
void initializeEngine(QQmlEngine *engine, const char *uri) override;
private:
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 465a342129..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(':') + url.midRef(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)
- return QLatin1Char(':') + url.midRef(4);
- return QString();
+ Q_ASSERT(!isDoubleSlashed(url, strlen("qrc:")));
+ if (url.size() > 4)
+ return QLatin1Char(':') + QStringView{url}.mid(4);
+ 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 32dce8b4bc..1704e2d994 100644
--- a/src/qml/qml/qqmlfileselector.cpp
+++ b/src/qml/qml/qqmlfileselector.cpp
@@ -1,53 +1,18 @@
-/****************************************************************************
-**
-** 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>
+#include <QtQml/private/qqmlengine_p.h>
+#include <QtQml/private/qqmlapplicationengine_p.h>
#include <qobjectdefs.h>
#include "qqmlfileselector.h"
#include "qqmlfileselector_p.h"
+#include "qqmlengine_p.h"
#include <QDebug>
QT_BEGIN_NAMESPACE
-typedef QHash<QQmlAbstractUrlInterceptor*, QQmlFileSelector*> interceptorSelectorMap;
-Q_GLOBAL_STATIC(interceptorSelectorMap, interceptorInstances);
/*!
\class QQmlFileSelector
\since 5.2
@@ -89,8 +54,7 @@ Q_GLOBAL_STATIC(interceptorSelectorMap, interceptorInstances);
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.
*/
/*!
@@ -104,8 +68,7 @@ QQmlFileSelector::QQmlFileSelector(QQmlEngine* engine, QObject* parent)
{
Q_D(QQmlFileSelector);
d->engine = engine;
- interceptorInstances()->insert(d->myInstance.data(), this);
- d->engine->setUrlInterceptor(d->myInstance.data());
+ d->engine->addUrlInterceptor(d->myInstance.data());
}
/*!
@@ -114,18 +77,17 @@ QQmlFileSelector::QQmlFileSelector(QQmlEngine* engine, QObject* parent)
QQmlFileSelector::~QQmlFileSelector()
{
Q_D(QQmlFileSelector);
- if (d->engine && QQmlFileSelector::get(d->engine) == this) {
- d->engine->setUrlInterceptor(nullptr);
+ if (d->engine) {
+ d->engine->removeUrlInterceptor(d->myInstance.data());
d->engine = nullptr;
}
- interceptorInstances()->remove(d->myInstance.data());
}
/*!
\since 5.7
Returns the QFileSelector instance used by the QQmlFileSelector.
*/
-QFileSelector *QQmlFileSelector::selector() const Q_DECL_NOTHROW
+QFileSelector *QQmlFileSelector::selector() const noexcept
{
Q_D(const QQmlFileSelector);
return d->selector;
@@ -148,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)
@@ -173,35 +135,49 @@ void QQmlFileSelector::setSelector(QFileSelector *selector)
Use this when extra selectors are all you need to avoid having to create your own
QFileSelector instance.
*/
-void QQmlFileSelector::setExtraSelectors(QStringList &strings)
-{
- Q_D(QQmlFileSelector);
- d->selector->setExtraSelectors(strings);
-}
-
-
-/*!
- Adds extra selectors contained in \a strings to the current QFileSelector being used.
- Use this when extra selectors are all you need to avoid having to create your own
- QFileSelector instance.
-*/
void QQmlFileSelector::setExtraSelectors(const QStringList &strings)
{
Q_D(QQmlFileSelector);
d->selector->setExtraSelectors(strings);
}
+#if QT_DEPRECATED_SINCE(6, 0)
/*!
+ \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
+ engine after setting it. It may be in use.
+
+ If the \a engine passed here is a QQmlApplicationEngine that hasn't loaded any
+ QML files, yet, it will be initialized. Any later calls to
+ QQmlApplicationEngine::setExtraFileSelectors() will have no effect.
+
+ \sa QQmlApplicationEngine
*/
QQmlFileSelector* QQmlFileSelector::get(QQmlEngine* engine)
{
- //Since I think we still can't use dynamic_cast inside Qt...
- QQmlAbstractUrlInterceptor* current = engine->urlInterceptor();
- if (current && interceptorInstances()->contains(current))
- return interceptorInstances()->value(current);
+ QQmlEnginePrivate *enginePrivate = QQmlEnginePrivate::get(engine);
+
+ if (qobject_cast<QQmlApplicationEngine *>(engine)) {
+ auto *appEnginePrivate = static_cast<QQmlApplicationEnginePrivate *>(enginePrivate);
+ appEnginePrivate->ensureInitialized();
+ }
+
+ const QUrl nonEmptyInvalid(QLatin1String(":"));
+ for (QQmlAbstractUrlInterceptor *interceptor : enginePrivate->urlInterceptors) {
+ const QUrl result = interceptor->intercept(
+ nonEmptyInvalid, QQmlAbstractUrlInterceptor::UrlString);
+ if (result.scheme() == QLatin1String("type")
+ && result.path() == QLatin1String("fileselector")) {
+ return static_cast<QQmlFileSelectorInterceptor *>(interceptor)->d->q_func();
+ }
+ }
return nullptr;
}
+#endif
/*!
\internal
@@ -216,9 +192,12 @@ QQmlFileSelectorInterceptor::QQmlFileSelectorInterceptor(QQmlFileSelectorPrivate
*/
QUrl QQmlFileSelectorInterceptor::intercept(const QUrl &path, DataType type)
{
- if ( type == QQmlAbstractUrlInterceptor::QmldirFile ) //Don't intercept qmldir files, to prevent double interception
- return path;
- return d->selector->select(path);
+ if (!path.isEmpty() && !path.isValid())
+ return QUrl(QLatin1String("type:fileselector"));
+
+ return type == QQmlAbstractUrlInterceptor::QmldirFile
+ ? path // Don't intercept qmldir files, to prevent double interception
+ : d->selector->select(path);
}
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlfileselector.h b/src/qml/qml/qqmlfileselector.h
index 9b70e3936d..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
@@ -56,11 +20,13 @@ class Q_QML_EXPORT QQmlFileSelector : public QObject
public:
explicit QQmlFileSelector(QQmlEngine *engine, QObject *parent = nullptr);
~QQmlFileSelector() override;
- QFileSelector *selector() const Q_DECL_NOTHROW;
+ QFileSelector *selector() const noexcept;
void setSelector(QFileSelector *selector);
- void setExtraSelectors(QStringList &strings); // TODO Qt6: remove
void setExtraSelectors(const QStringList &strings);
- static QQmlFileSelector* get(QQmlEngine*);
+
+#if QT_DEPRECATED_SINCE(6, 0)
+ QT_DEPRECATED static QQmlFileSelector *get(QQmlEngine*);
+#endif
private:
Q_DISABLE_COPY(QQmlFileSelector)
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 acebb6bac3..2e3fa5f86c 100644
--- a/src/qml/qml/qqmlglobal.cpp
+++ b/src/qml/qml/qqmlglobal.cpp
@@ -1,278 +1,754 @@
-/****************************************************************************
-**
-** 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>
+// 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
-QQmlValueTypeProvider::QQmlValueTypeProvider()
- : next(nullptr)
-{
+// Pre-filter the metatype before poking QQmlMetaType::qmlType() and locking its mutex.
+static bool isConstructibleMetaType(const QMetaType metaType)
+{
+ 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;
+ 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;
}
-QQmlValueTypeProvider::~QQmlValueTypeProvider()
+static void *createVariantData(QMetaType type, QVariant *variant)
{
- QQml_removeValueTypeProvider(this);
+ 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();
}
-const QMetaObject *QQmlValueTypeProvider::metaObjectForMetaType(int type)
+static void callConstructor(
+ const QMetaObject *targetMetaObject, int i, void *source, void *target)
{
- QQmlValueTypeProvider *p = this;
- do {
- if (const QMetaObject *mo = p->getMetaObjectForMetaType(type))
- return mo;
- } while ((p = p->next));
+ void *p[] = { target, source };
+ targetMetaObject->static_metacall(QMetaObject::ConstructInPlace, i, p);
+}
- return nullptr;
+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());
}
-bool QQmlValueTypeProvider::initValueType(int type, QVariant& dst)
+
+template<typename Allocate, typename Retrieve>
+static bool fromMatchingType(
+ const QMetaObject *targetMetaObject, Allocate &&allocate, Retrieve &&retrieve)
{
- QQmlValueTypeProvider *p = this;
- do {
- if (p->init(type, dst))
+ 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;
- } while ((p = p->next));
+ }
+ }
return false;
}
-QVariant QQmlValueTypeProvider::createValueType(int type, int argc, const void *argv[])
+template<typename Allocate>
+static bool fromMatchingType(
+ const QMetaObject *targetMetaObject, const QV4::Value &source, Allocate &&allocate)
{
- QVariant v;
-
- QQmlValueTypeProvider *p = this;
- do {
- if (p->create(type, argc, argv, &v))
- return v;
- } while ((p = p->next));
+ return fromMatchingType(
+ targetMetaObject, std::forward<Allocate>(allocate),
+ [&](QMetaType parameterType, auto callback) {
+ QVariant variant = QV4::ExecutionEngine::toVariant(source, parameterType);
+ return callback(variant.metaType(), variant.data());
+ });
+}
- return QVariant();
+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());
+ });
}
-bool QQmlValueTypeProvider::createValueFromString(int type, const QString &s, void *data, size_t n)
+template<typename Allocate>
+static bool fromString(const QMetaObject *mo, QString s, Allocate &&allocate)
{
- Q_ASSERT(data);
+ for (int i = 0, end = mo->constructorCount(); i < end; ++i) {
+ const QMetaMethod ctor = mo->constructor(i);
+ if (ctor.parameterCount() != 1)
+ continue;
- QQmlValueTypeProvider *p = this;
- do {
- if (p->createFromString(type, s, data, n))
+ if (ctor.parameterMetaType(0) == QMetaType::fromType<QString>()) {
+ callConstructor(mo, i, &s, allocate());
return true;
- } while ((p = p->next));
+ }
+ }
return false;
}
-bool QQmlValueTypeProvider::createStringFromValue(int type, const void *data, QString *s)
+template<typename Get, typename Convert>
+static bool doWriteProperty(const QMetaProperty &metaProperty, void *target,
+ Get &&get, Convert &&convert)
{
- Q_ASSERT(data);
- Q_ASSERT(s);
+ const QMetaType propertyType = metaProperty.metaType();
+ QVariant property = get(propertyType);
+ if (property.metaType() == propertyType) {
+ metaProperty.writeOnGadget(target, std::move(property));
+ return true;
+ }
- QQmlValueTypeProvider *p = this;
- do {
- if (p->createStringFrom(type, data, s))
- return true;
- } while ((p = p->next));
+ 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;
}
-QVariant QQmlValueTypeProvider::createVariantFromString(const QString &s)
+static void doWriteProperties(
+ const QMetaObject *targetMetaObject, void *target, const QV4::Value &source)
{
- QVariant v;
+ const QV4::Object *o = static_cast<const QV4::Object *>(&source);
+ QV4::Scope scope(o->engine());
+ QV4::ScopedObject object(scope, o);
- QQmlValueTypeProvider *p = this;
- do {
- if (p->variantFromString(s, &v))
- return v;
- } while ((p = p->next));
+ for (int i = 0; i < targetMetaObject->propertyCount(); ++i) {
+ const QMetaProperty metaProperty = targetMetaObject->property(i);
+ const QString propertyName = QString::fromUtf8(metaProperty.name());
- // Return a variant containing the string itself
- return QVariant(s);
-}
+ QV4::ScopedString v4PropName(scope, scope.engine->newString(propertyName));
+ QV4::ScopedValue v4PropValue(scope, object->get(v4PropName));
-QVariant QQmlValueTypeProvider::createVariantFromString(int type, const QString &s, bool *ok)
-{
- QVariant v;
+ // We assume that data is freshly constructed.
+ // There is no point in reset()'ing properties of a freshly created object.
+ if (v4PropValue->isUndefined())
+ continue;
- QQmlValueTypeProvider *p = this;
- do {
- if (p->variantFromString(type, s, &v)) {
- if (ok) *ok = true;
- return v;
+ if (doWriteProperty(metaProperty, target, [&](const QMetaType &propertyType) {
+ return QV4::ExecutionEngine::toVariant(v4PropValue, propertyType);
+ }, [&](const QMetaType &propertyType) {
+ return QQmlValueTypeProvider::createValueType(v4PropValue, propertyType);
+ })) {
+ continue;
}
- } while ((p = p->next));
- if (ok) *ok = false;
- return QVariant();
+ 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)
+{
+ if (!source.isObject() || !targetMetaObject)
+ return QVariant();
+
+ QVariant result(metaType);
+ doWriteProperties(targetMetaObject, result.data(), source);
+ return result;
}
-QVariant QQmlValueTypeProvider::createVariantFromJsObject(int type, const QV4::Value &obj,
- QV4::ExecutionEngine *e, bool *ok)
+template<typename Read>
+static void doWriteProperties(
+ const QMetaObject *targetMetaObject, void *target,
+ const QMetaObject *sourceMetaObject, Read &&read)
{
- QVariant v;
+ 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;
- QQmlValueTypeProvider *p = this;
- do {
- if (p->variantFromJsObject(type, obj, e, &v)) {
- if (ok) *ok = true;
- return v;
+ const QMetaType propertyType = metaProperty.metaType();
+ QVariant property = read(sourceMetaObject, sourceProperty);
+ if (property.metaType() == propertyType) {
+ metaProperty.writeOnGadget(target, std::move(property));
+ continue;
}
- } while ((p = p->next));
- if (ok) *ok = false;
- return QVariant();
+ 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()));
+ }
}
-bool QQmlValueTypeProvider::equalValueType(int type, const void *lhs, const QVariant& rhs)
+
+static void doWriteProperties(const QMetaObject *targetMeta, void *target, QObject *source)
{
- Q_ASSERT(lhs);
+ doWriteProperties(
+ targetMeta, target, source->metaObject(),
+ [source](const QMetaObject *sourceMetaObject, int sourceProperty) {
+ return sourceMetaObject->property(sourceProperty).read(source);
+ });
+}
- QQmlValueTypeProvider *p = this;
- do {
- if (p->equal(type, lhs, rhs))
- return true;
- } while ((p = p->next));
+static QVariant byProperties(
+ const QMetaObject *targetMetaObject, QMetaType targetMetaType, QObject *source)
+{
+ if (!source || !targetMetaObject)
+ return QVariant();
- return false;
+ QVariant result(targetMetaType);
+ doWriteProperties(targetMetaObject, result.data(), source);
+ return result;
}
-bool QQmlValueTypeProvider::storeValueType(int type, const void *src, void *dst, size_t dstSize)
+static QVariant byProperties(
+ const QMetaObject *targetMetaObject, QMetaType targetMetaType,
+ const QMetaObject *sourceMetaObject, const void *source)
{
- Q_ASSERT(src);
- Q_ASSERT(dst);
+ if (!source || !sourceMetaObject || !targetMetaObject)
+ return QVariant();
- QQmlValueTypeProvider *p = this;
- do {
- if (p->store(type, src, dst, dstSize))
- return true;
- } while ((p = p->next));
+ QVariant result(targetMetaType);
+ doWriteProperties(
+ targetMetaObject, result.data(), sourceMetaObject,
+ [source](const QMetaObject *sourceMetaObject, int sourceProperty) {
+ return sourceMetaObject->property(sourceProperty).readOnGadget(source);
+ });
+ return result;
+}
- return false;
+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;
}
-bool QQmlValueTypeProvider::readValueType(const QVariant& src, void *dst, int dstType)
+static QVariant byProperties(
+ const QMetaObject *targetMetaObject, QMetaType targetMetaType, const QVariant &source)
{
- Q_ASSERT(dst);
+ if (!targetMetaObject)
+ return QVariant();
- QQmlValueTypeProvider *p = this;
- do {
- if (p->read(src, dst, dstType))
+ if (source.metaType() == QMetaType::fromType<QJSValue>()) {
+ QJSValue val = source.value<QJSValue>();
+ // Generally, the GC might collect a Value at any point so that
+ // a `ScopedValue` should be used.
+ // In this case, the Value is tied to a `QJSValue` which is
+ // persistent to the GC and thus the cast is safe.
+ 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;
- } while ((p = p->next));
+ }
+ }
return false;
}
-bool QQmlValueTypeProvider::writeValueType(int type, const void *src, QVariant& dst)
-{
- Q_ASSERT(src);
+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;
+ }
+ }
+ }
- QQmlValueTypeProvider *p = this;
- do {
- if (p->write(type, src, dst))
- return true;
- } while ((p = p->next));
+ 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;
}
-const QMetaObject *QQmlValueTypeProvider::getMetaObjectForMetaType(int) { return nullptr; }
-bool QQmlValueTypeProvider::init(int, QVariant&) { return false; }
-bool QQmlValueTypeProvider::create(int, int, const void *[], QVariant *) { return false; }
-bool QQmlValueTypeProvider::createFromString(int, const QString &, void *, size_t) { return false; }
-bool QQmlValueTypeProvider::createStringFrom(int, const void *, QString *) { return false; }
-bool QQmlValueTypeProvider::variantFromString(const QString &, QVariant *) { return false; }
-bool QQmlValueTypeProvider::variantFromString(int, const QString &, QVariant *) { return false; }
-bool QQmlValueTypeProvider::variantFromJsObject(int, const QV4::Value &, QV4::ExecutionEngine *, QVariant *) { return false; }
-bool QQmlValueTypeProvider::equal(int, const void *, const QVariant&) { return false; }
-bool QQmlValueTypeProvider::store(int, const void *, void *, size_t) { return false; }
-bool QQmlValueTypeProvider::read(const QVariant&, void *, int) { return false; }
-bool QQmlValueTypeProvider::write(int, const void *, QVariant&) { 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);
+ // Generally, the GC might collect a Value at any point so that
+ // a `ScopedValue` should be used.
+ // In this case, the Value is tied to a `QJSValue` which is
+ // persistent to the GC and thus the cast is safe.
+ return populateValueType(
+ targetMetaType, target, QV4::Value(QJSValuePrivate::asReturnedValue(val)));
+ }
-struct ValueTypeProviderList {
- QQmlValueTypeProvider nullProvider;
- QQmlValueTypeProvider *head = &nullProvider;
-};
+ if (!isConstructibleMetaType(targetMetaType))
+ return false;
+
+ return createOrConstructValueType(
+ QQmlMetaType::qmlType(targetMetaType), sourceMetaType, source,
+ [targetMetaType, target]() {
+ targetMetaType.destruct(target);
+ return target;
+ }, [target]() {
+ return target;
+ });
+}
+
+/*!
+ * \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)
+{
+ if (!isConstructibleMetaType(targetMetaType))
+ return false;
+
+ 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(ValueTypeProviderList, valueTypeProviders)
+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_QML_PRIVATE_EXPORT void QQml_addValueTypeProvider(QQmlValueTypeProvider *newProvider)
+static QVariant fromJSValue(const QQmlType &type, const QJSValue &s, QMetaType metaType)
{
- if (ValueTypeProviderList *providers = valueTypeProviders()) {
- newProvider->next = providers->head;
- providers->head = newProvider;
+ if (const auto valueTypeFunction = type.createValueTypeFunction()) {
+ const QVariant result = valueTypeFunction(s);
+ if (result.metaType() == metaType)
+ return result;
}
+
+ return QVariant();
}
-Q_QML_PRIVATE_EXPORT void QQml_removeValueTypeProvider(QQmlValueTypeProvider *oldProvider)
+QVariant QQmlValueTypeProvider::createValueType(const QJSValue &s, QMetaType metaType)
{
- if (ValueTypeProviderList *providers = valueTypeProviders()) {
- QQmlValueTypeProvider *prev = providers->head;
- if (prev == oldProvider) {
- providers->head = oldProvider->next;
- return;
+ 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;
}
+ }
- // singly-linked list removal
- for (; prev; prev = prev->next) {
- if (prev->next != oldProvider)
- continue; // this is not the provider you're looking for
- prev->next = oldProvider->next;
- return;
+ 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);
+ }
+ }
- qWarning("QQml_removeValueTypeProvider: was asked to remove provider %p but it was not found", oldProvider);
+ 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);
+ }
}
-}
-Q_AUTOTEST_EXPORT QQmlValueTypeProvider *QQml_valueTypeProvider()
-{
- if (ValueTypeProviderList *providers = valueTypeProviders())
- return providers->head;
- return nullptr;
+ return QVariant();
}
QQmlColorProvider::~QQmlColorProvider() {}
@@ -283,11 +759,15 @@ QVariant QQmlColorProvider::fromHslF(double, double, double, double) { return QV
QVariant QQmlColorProvider::fromHsvF(double, double, double, double) { return QVariant(); }
QVariant QQmlColorProvider::lighter(const QVariant &, qreal) { return QVariant(); }
QVariant QQmlColorProvider::darker(const QVariant &, qreal) { return QVariant(); }
+QVariant QQmlColorProvider::alpha(const QVariant &, qreal)
+{
+ return QVariant();
+}
QVariant QQmlColorProvider::tint(const QVariant &, const QVariant &) { return QVariant(); }
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;
@@ -313,9 +793,12 @@ Q_AUTOTEST_EXPORT QQmlColorProvider *QQml_colorProvider(void)
QQmlGuiProvider::~QQmlGuiProvider() {}
-QObject *QQmlGuiProvider::application(QObject *) { return new QQmlApplication(); }
+QQmlApplication *QQmlGuiProvider::application(QObject *parent)
+{
+ return new QQmlApplication(parent);
+}
QStringList QQmlGuiProvider::fontFamilies() { return QStringList(); }
-bool QQmlGuiProvider::openUrlExternally(QUrl &) { return false; }
+bool QQmlGuiProvider::openUrlExternally(const QUrl &) { return false; }
QObject *QQmlGuiProvider::inputMethod()
{
@@ -338,7 +821,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;
@@ -363,18 +846,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)
@@ -442,6 +915,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 3c540a6124..5aa2f3ee6f 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,34 +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.
@@ -117,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.
@@ -152,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
@@ -167,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) \
@@ -216,57 +203,27 @@ inline void QQml_setParent_noEvent(QObject *object, QObject *parent)
d_ptr->sendChildEvents = sce;
}
-class Q_QML_PRIVATE_EXPORT QQmlValueTypeProvider
+class QQmlValueTypeProvider
{
public:
- QQmlValueTypeProvider();
- virtual ~QQmlValueTypeProvider();
-
- const QMetaObject *metaObjectForMetaType(int);
-
- bool initValueType(int, QVariant&);
-
- QVariant createValueType(int, int, const void *[]);
- bool createValueFromString(int, const QString &, void *, size_t);
- bool createStringFromValue(int, const void *, QString *);
-
- QVariant createVariantFromString(const QString &);
- QVariant createVariantFromString(int, const QString &, bool *);
- QVariant createVariantFromJsObject(int, const QV4::Value &, QV4::ExecutionEngine *, bool *);
-
- bool equalValueType(int, const void *, const QVariant&);
- bool storeValueType(int, const void *, void *, size_t);
- bool readValueType(const QVariant&, void *, int);
- bool writeValueType(int, const void *, QVariant&);
-
-private:
- virtual const QMetaObject *getMetaObjectForMetaType(int);
- virtual bool init(int, QVariant&);
-
- virtual bool create(int, int, const void *[], QVariant *);
- virtual bool createFromString(int, const QString &, void *, size_t);
- virtual bool createStringFrom(int, const void *, QString *);
-
- virtual bool variantFromString(const QString &, QVariant *);
- virtual bool variantFromString(int, const QString &, QVariant *);
- virtual bool variantFromJsObject(int, const QV4::Value &, QV4::ExecutionEngine *, QVariant *);
-
- virtual bool equal(int, const void *, const QVariant&);
- virtual bool store(int, const void *, void *, size_t);
- virtual bool read(const QVariant&, void *, int);
- virtual bool write(int, const void *, QVariant&);
-
- friend Q_QML_PRIVATE_EXPORT void QQml_addValueTypeProvider(QQmlValueTypeProvider *);
- friend Q_QML_PRIVATE_EXPORT void QQml_removeValueTypeProvider(QQmlValueTypeProvider *);
-
- QQmlValueTypeProvider *next;
+ 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_QML_PRIVATE_EXPORT void QQml_addValueTypeProvider(QQmlValueTypeProvider *);
-Q_AUTOTEST_EXPORT QQmlValueTypeProvider *QQml_valueTypeProvider();
-
-
-class Q_QML_PRIVATE_EXPORT QQmlColorProvider
+class Q_QML_EXPORT QQmlColorProvider
{
public:
virtual ~QQmlColorProvider();
@@ -278,31 +235,32 @@ public:
virtual QVariant fromHsvF(double, double, double, double);
virtual QVariant lighter(const QVariant &, qreal);
virtual QVariant darker(const QVariant &, qreal);
+ virtual QVariant alpha(const QVariant &, qreal);
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 Q_QML_PRIVATE_EXPORT QQmlGuiProvider
+class QQmlApplication;
+class Q_QML_EXPORT QQmlGuiProvider
{
public:
virtual ~QQmlGuiProvider();
- virtual QObject *application(QObject *parent);
+ virtual QQmlApplication *application(QObject *parent);
virtual QObject *inputMethod();
virtual QObject *styleHints();
virtual QStringList fontFamilies();
- virtual bool openUrlExternally(QUrl &);
+ virtual bool openUrlExternally(const QUrl &);
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
@@ -311,6 +269,7 @@ class Q_QML_PRIVATE_EXPORT QQmlApplication : public QObject
Q_PROPERTY(QString version READ version WRITE setVersion NOTIFY versionChanged)
Q_PROPERTY(QString organization READ organization WRITE setOrganization NOTIFY organizationChanged)
Q_PROPERTY(QString domain READ domain WRITE setDomain NOTIFY domainChanged)
+ QML_ANONYMOUS
public:
QQmlApplication(QObject* parent=nullptr);
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
new file mode 100644
index 0000000000..048f809f48
--- /dev/null
+++ b/src/qml/qml/qqmlguardedcontextdata_p.h
@@ -0,0 +1,95 @@
+// 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
+
+//
+// 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 <QtQml/private/qqmlcontextdata_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQmlGuardedContextData
+{
+ Q_DISABLE_COPY(QQmlGuardedContextData);
+public:
+ QQmlGuardedContextData() = default;
+ ~QQmlGuardedContextData() { unlink(); }
+
+ QQmlGuardedContextData(QQmlGuardedContextData &&) = default;
+ QQmlGuardedContextData &operator=(QQmlGuardedContextData &&) = default;
+
+ QQmlGuardedContextData(QQmlRefPointer<QQmlContextData> data)
+ {
+ setContextData(std::move(data));
+ }
+
+ QQmlGuardedContextData &operator=(QQmlRefPointer<QQmlContextData> d)
+ {
+ setContextData(std::move(d));
+ return *this;
+ }
+
+ QQmlRefPointer<QQmlContextData> contextData() const { return m_contextData; }
+ void setContextData(QQmlRefPointer<QQmlContextData> contextData)
+ {
+ if (m_contextData.data() == contextData.data())
+ return;
+ unlink();
+
+ if (contextData) {
+ m_contextData = std::move(contextData);
+ m_next = m_contextData->m_contextGuards;
+ if (m_next)
+ m_next->m_prev = &m_next;
+
+ m_contextData->m_contextGuards = this;
+ m_prev = &m_contextData->m_contextGuards;
+ }
+ }
+
+ bool isNull() const { return !m_contextData; }
+
+ operator const QQmlRefPointer<QQmlContextData> &() const { return m_contextData; }
+ QQmlContextData &operator*() const { return m_contextData.operator*(); }
+ QQmlContextData *operator->() const { return m_contextData.operator->(); }
+
+ QQmlGuardedContextData *next() const { return m_next; }
+
+private:
+ void reset()
+ {
+ m_contextData.reset();
+ m_next = nullptr;
+ m_prev = nullptr;
+ }
+
+ void unlink()
+ {
+ if (m_prev) {
+ *m_prev = m_next;
+ if (m_next)
+ m_next->m_prev = m_prev;
+ reset();
+ }
+ }
+
+ QQmlRefPointer<QQmlContextData> m_contextData;
+ QQmlGuardedContextData *m_next = nullptr;
+ QQmlGuardedContextData **m_prev = nullptr;
+};
+
+QT_END_NAMESPACE
+
+#endif // QQMLGUARDEDCONTEXTDATA_P_H
diff --git a/src/qml/qml/qqmlimport.cpp b/src/qml/qml/qqmlimport.cpp
index af6d067fbb..217cb44669 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,25 +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>
+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('.');
@@ -79,6 +80,28 @@ static bool designerSupportRequired = false;
namespace {
+QTypeRevision relevantVersion(const QString &uri, QTypeRevision version)
+{
+ return QQmlMetaType::latestModuleVersion(uri).isValid() ? version : QTypeRevision();
+}
+
+QQmlError moduleNotFoundError(const QString &uri, QTypeRevision version)
+{
+ QQmlError error;
+ if (version.hasMajorVersion()) {
+ error.setDescription(QQmlImportDatabase::tr(
+ "module \"%1\" version %2.%3 is not installed")
+ .arg(uri).arg(version.majorVersion())
+ .arg(version.hasMinorVersion()
+ ? QString::number(version.minorVersion())
+ : QLatin1String("x")));
+ } else {
+ error.setDescription(QQmlImportDatabase::tr("module \"%1\" is not installed")
+ .arg(uri));
+ }
+ return error;
+}
+
QString resolveLocalUrl(const QString &url, const QString &relative)
{
if (relative.contains(Colon)) {
@@ -89,14 +112,14 @@ QString resolveLocalUrl(const QString &url, const QString &relative)
} else if (relative.at(0) == Slash || !url.contains(Slash)) {
return relative;
} else {
- const QStringRef baseRef = url.leftRef(url.lastIndexOf(Slash) + 1);
+ const QStringView baseRef = QStringView{url}.left(url.lastIndexOf(Slash) + 1);
if (relative == QLatin1String("."))
return baseRef.toString();
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) &&
@@ -135,41 +158,6 @@ bool isPathAbsolute(const QString &path)
} // namespace
-struct RegisteredPlugin {
- QString uri;
- QPluginLoader* loader;
-};
-
-struct StringRegisteredPluginMap : public QMap<QString, RegisteredPlugin> {
- QMutex mutex;
-
- ~StringRegisteredPluginMap()
- {
- QMutexLocker lock(&mutex);
- for (const RegisteredPlugin &plugin : qAsConst(*this))
- delete plugin.loader;
- }
-};
-
-Q_GLOBAL_STATIC(StringRegisteredPluginMap, qmlEnginePluginsWithRegisteredTypes); // stores the uri and the PluginLoaders
-
-void qmlClearEnginePlugins()
-{
- StringRegisteredPluginMap *plugins = qmlEnginePluginsWithRegisteredTypes();
- QMutexLocker lock(&plugins->mutex);
-#if QT_CONFIG(library)
- for (auto &plugin : qAsConst(*plugins)) {
- QPluginLoader* loader = plugin.loader;
- if (loader && !loader->unload())
- qWarning("Unloading %s failed: %s", qPrintable(plugin.uri), qPrintable(loader->errorString()));
- delete loader;
- }
-#endif
- plugins->clear();
-}
-
-typedef QPair<QStaticPlugin, QJsonArray> StaticPluginPair;
-
/*!
\internal
\class QQmlImportInstance
@@ -203,106 +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;
-
- bool addLibraryImport(const QString& uri, const QString &prefix,
- int vmaj, int vmin, const QString &qmldirIdentifier, const QString &qmldirUrl, bool incomplete,
- QQmlImportDatabase *database,
- QList<QQmlError> *errors);
-
- bool addFileImport(const QString &uri, const QString &prefix,
- int vmaj, int vmin,
- bool isImplicitImport, bool incomplete, QQmlImportDatabase *database,
- QList<QQmlError> *errors);
-
- bool updateQmldirContent(const QString &uri, const QString &prefix,
- const QString &qmldirIdentifier, const QString& qmldirUrl,
- QQmlImportDatabase *database,
- QList<QQmlError> *errors);
-
- bool resolveType(const QHashedStringRef &type, int *vmajor, int *vminor,
- QQmlType *type_return, QList<QQmlError> *errors,
- QQmlType::RegistrationType registrationType,
- QQmlImport::RecursionRestriction recursionRestriction
- = QQmlImport::PreventRecursion);
-
- 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 bool locateQmldir(const QString &uri, int vmaj, int vmin,
- QQmlImportDatabase *database,
- QString *outQmldirFilePath, QString *outUrl);
-
- static bool validateQmldirVersion(const QQmlTypeLoaderQmldirContent &qmldir, const QString &uri, int vmaj, int vmin,
- QList<QQmlError> *errors);
-
- bool importExtension(const QString &absoluteFilePath, const QString &uri,
- int vmaj, int vmin,
- 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,
- int vmaj, int vmin, QV4::CompiledData::Import::ImportType type,
- QList<QQmlError> *errors, bool lowPrecedence = false);
-
- 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))
-{
-}
-QQmlImports::~QQmlImports()
+QTypeRevision QQmlImports::validVersion(QTypeRevision version)
{
- 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);
}
/*!
@@ -310,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
@@ -340,17 +235,17 @@ 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->majversion);
+ QQmlTypeModule *module = QQmlMetaType::typeModule(import->uri, import->version);
if (module) {
- cache->m_anonymousImports.append(QQmlTypeModuleVersion(module, import->minversion));
+ cache->m_anonymousImports.append(QQmlTypeModuleVersion(module, import->version));
}
}
- 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;
@@ -358,12 +253,12 @@ 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->majversion);
+ QQmlTypeModule *module = QQmlMetaType::typeModule(import->uri, import->version);
if (module) {
QQmlImportRef &typeimport = cache->m_namedImports[set.prefix];
- typeimport.modules.append(QQmlTypeModuleVersion(module, import->minversion));
+ typeimport.modules.append(QQmlTypeModuleVersion(module, import->version));
}
}
}
@@ -379,7 +274,7 @@ bool excludeBaseUrl(const QString &importUrl, const QString &fileName, const QSt
if (baseUrl.startsWith(importUrl))
{
- if (fileName == baseUrl.midRef(importUrl.size()))
+ if (fileName == QStringView{baseUrl}.mid(importUrl.size()))
return false;
}
@@ -390,41 +285,40 @@ 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;
- const int importMajorVersion = import->majversion;
- const int importMinorVersion = import->minversion;
- auto shouldSkipSingleton = [importMajorVersion, importMinorVersion](int singletonMajorVersion, int singletonMinorVersion) -> bool {
- return importMajorVersion != -1 &&
- (singletonMajorVersion > importMajorVersion || (singletonMajorVersion == importMajorVersion && singletonMinorVersion > importMinorVersion));
+ const QTypeRevision importVersion = import->version;
+ auto shouldSkipSingleton = [importVersion](QTypeRevision singletonVersion) -> bool {
+ return importVersion.hasMajorVersion() &&
+ (singletonVersion.majorVersion() > importVersion.majorVersion()
+ || (singletonVersion.majorVersion() == importVersion.majorVersion()
+ && singletonVersion.minorVersion() > importVersion.minorVersion()));
};
ConstIterator cend = components.constEnd();
for (ConstIterator cit = components.constBegin(); cit != cend; ++cit) {
if (cit->singleton && excludeBaseUrl(import->url, cit->fileName, baseUrl.toString())) {
- if (shouldSkipSingleton(cit->majorVersion, cit->minorVersion))
+ if (shouldSkipSingleton(cit->version))
continue;
QQmlImports::CompositeSingletonReference ref;
ref.typeName = cit->typeName;
ref.prefix = set.prefix;
- ref.majorVersion = cit->majorVersion;
- ref.minorVersion = cit->minorVersion;
+ ref.version = cit->version;
resultList.append(ref);
}
}
- if (QQmlTypeModule *module = QQmlMetaType::typeModule(import->uri, import->majversion)) {
+ if (QQmlTypeModule *module = QQmlMetaType::typeModule(import->uri, import->version)) {
module->walkCompositeSingletons([&resultList, &set, &shouldSkipSingleton](const QQmlType &singleton) {
- if (shouldSkipSingleton(singleton.majorVersion(), singleton.minorVersion()))
+ if (shouldSkipSingleton(singleton.version()))
return;
QQmlImports::CompositeSingletonReference ref;
ref.typeName = singleton.elementName();
ref.prefix = set.prefix;
- ref.majorVersion = singleton.majorVersion();
- ref.minorVersion = singleton.minorVersion();
+ ref.version = singleton.version();
resultList.append(ref);
});
}
@@ -444,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());
}
@@ -461,9 +355,9 @@ QList<QQmlImports::CompositeSingletonReference> QQmlImports::resolvedCompositeSi
if (lhs.typeName != rhs.typeName)
return lhs.typeName < rhs.typeName;
- return lhs.majorVersion != rhs.majorVersion
- ? lhs.majorVersion < rhs.majorVersion
- : lhs.minorVersion < rhs.minorVersion;
+ return lhs.version.majorVersion() != rhs.version.majorVersion()
+ ? lhs.version.majorVersion() < rhs.version.majorVersion()
+ : lhs.version.minorVersion() < rhs.version.minorVersion();
});
return compositeSingletons;
@@ -479,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) {
@@ -492,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) {
@@ -511,17 +405,6 @@ QList<QQmlImports::ScriptReference> QQmlImports::resolvedScripts() const
return scripts;
}
-static QString joinStringRefs(const QVector<QStringRef> &refs, const QChar &sep)
-{
- QString str;
- for (auto it = refs.cbegin(); it != refs.cend(); ++it) {
- if (it != refs.cbegin())
- str += sep;
- str += *it;
- }
- return str;
-}
-
/*!
Forms complete paths to a qmldir file, from a base URL, a module URI and version specification.
@@ -532,47 +415,23 @@ static QString joinStringRefs(const QVector<QStringRef> &refs, const QChar &sep)
- base/QtQml.2/Models/qmldir
- base/QtQml/Models/qmldir
*/
-QStringList QQmlImports::completeQmldirPaths(const QString &uri, const QStringList &basePaths, int vmaj, int vmin)
+QStringList QQmlImports::completeQmldirPaths(const QString &uri, const QStringList &basePaths,
+ QTypeRevision version)
{
- const QVector<QStringRef> parts = uri.splitRef(Dot, QString::SkipEmptyParts);
-
- QStringList qmlDirPathsPaths;
- // fully & partially versioned parts + 1 unversioned for each base path
- qmlDirPathsPaths.reserve(basePaths.count() * (2 * parts.count() + 1));
-
- for (int version = FullyVersioned; version <= Unversioned; ++version) {
- const QString ver = versionString(vmaj, vmin, static_cast<QQmlImports::ImportVersion>(version));
-
- for (const QString &path : basePaths) {
- QString dir = path;
- if (!dir.endsWith(Slash) && !dir.endsWith(Backslash))
- dir += Slash;
-
- // append to the end
- qmlDirPathsPaths += dir + joinStringRefs(parts, Slash) + ver + Slash_qmldir;
-
- if (version != Unversioned) {
- // insert in the middle
- for (int index = parts.count() - 2; index >= 0; --index) {
- qmlDirPathsPaths += dir + joinStringRefs(parts.mid(0, index + 1), Slash)
- + ver + Slash
- + joinStringRefs(parts.mid(index + 1), Slash) + Slash_qmldir;
- }
- }
- }
- }
-
- return qmlDirPathsPaths;
+ QStringList paths = qQmlResolveImportPaths(uri, basePaths, version);
+ for (QString &path : paths)
+ path += Slash_qmldir;
+ return paths;
}
-QString QQmlImports::versionString(int vmaj, int vmin, ImportVersion version)
+QString QQmlImports::versionString(QTypeRevision version, ImportVersion versionMode)
{
- if (version == QQmlImports::FullyVersioned) {
+ if (versionMode == QQmlImports::FullyVersioned) {
// extension with fully encoded version number (eg. MyModule.3.2)
- return QString::asprintf(".%d.%d", vmaj, vmin);
- } else if (version == QQmlImports::PartiallyVersioned) {
+ return QString::asprintf(".%d.%d", version.majorVersion(), version.minorVersion());
+ } else if (versionMode == QQmlImports::PartiallyVersioned) {
// extension with encoded version major (eg. MyModule.3)
- return QString::asprintf(".%d", vmaj);
+ return QString::asprintf(".%d", version.majorVersion());
} // else extension without version number (eg. MyModule)
return QString();
}
@@ -590,30 +449,31 @@ QString QQmlImports::versionString(int vmaj, int vmin, ImportVersion version)
\sa addFileImport(), addLibraryImport
*/
-bool QQmlImports::resolveType(const QHashedStringRef &type,
- QQmlType *type_return, int *vmaj, int *vmin,
- QQmlImportNamespace** ns_return, QList<QQmlError> *errors,
- QQmlType::RegistrationType registrationType,
- QQmlImport::RecursionRestriction recursionRestriction) 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, vmaj, vmin, type_return, errors, registrationType,
- recursionRestriction)) {
- 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())
RESOLVE_TYPE_DEBUG << type_return->typeName() << ' ' << type_return->sourceUrl() << " TYPE/URL-SINGLETON";
else if (type_return->isComposite())
RESOLVE_TYPE_DEBUG << type_return->typeName() << ' ' << type_return->sourceUrl() << " TYPE/URL";
+ else if (type_return->isInlineComponentType())
+ RESOLVE_TYPE_DEBUG << type_return->typeName() << ' ' << type_return->sourceUrl() << " TYPE(INLINECOMPONENT)";
else
RESOLVE_TYPE_DEBUG << type_return->typeName() << " TYPE";
}
@@ -625,11 +485,12 @@ bool QQmlImports::resolveType(const QHashedStringRef &type,
return false;
}
-bool QQmlImportInstance::setQmldirContent(const QString &resolvedUrl, const QQmlTypeLoaderQmldirContent &qmldir, QQmlImportNamespace *nameSpace, QList<QQmlError> *errors)
+bool QQmlImportInstance::setQmldirContent(const QString &resolvedUrl,
+ const QQmlTypeLoaderQmldirContent &qmldir,
+ QQmlImportNamespace *nameSpace, QList<QQmlError> *errors)
{
Q_ASSERT(resolvedUrl.endsWith(Slash));
url = resolvedUrl;
- localDirectoryPath = QQmlFile::urlToLocalFileOrQrc(url);
qmlDirComponents = qmldir.components();
@@ -640,30 +501,35 @@ bool QQmlImportInstance::setQmldirContent(const QString &resolvedUrl, const QQml
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;
}
}
- qmlDirScripts = getVersionedScripts(scripts, majversion, minversion);
+ qmlDirScripts = getVersionedScripts(scripts, version);
}
return true;
}
-QQmlDirScripts QQmlImportInstance::getVersionedScripts(const QQmlDirScripts &qmldirscripts, int vmaj, int vmin)
+QQmlDirScripts QQmlImportInstance::getVersionedScripts(const QQmlDirScripts &qmldirscripts,
+ QTypeRevision version)
{
QMap<QString, QQmlDirParser::Script> versioned;
for (QList<QQmlDirParser::Script>::const_iterator sit = qmldirscripts.constBegin();
sit != qmldirscripts.constEnd(); ++sit) {
// Only include scripts that match our requested version
- if (((vmaj == -1) || (sit->majorVersion == vmaj)) &&
- ((vmin == -1) || (sit->minorVersion <= vmin))) {
+ if ((!version.hasMajorVersion() || (sit->version.majorVersion() == version.majorVersion()))
+ && (!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() || (vit->minorVersion < sit->minorVersion)) {
+ const auto vit = versioned.constFind(sit->nameSpace);
+ if (vit == versioned.cend()
+ || (vit->version.minorVersion() < sit->version.minorVersion())) {
versioned.insert(sit->nameSpace, *sit);
}
}
@@ -673,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
@@ -682,38 +549,37 @@ 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, int *vmaj, int *vmin,
- QQmlType::RegistrationType registrationType) const
-{
- return ns->resolveType(d->typeLoader, type, vmaj, vmin, type_return, nullptr, nullptr, registrationType);
-}
bool QQmlImportInstance::resolveType(QQmlTypeLoader *typeLoader, const QHashedStringRef& type,
- int *vmajor, int *vminor, QQmlType *type_return, QString *base,
- bool *typeRecursionDetected,
+ QTypeRevision *version_return, QQmlType *type_return,
+ const QString *base, bool *typeRecursionDetected,
QQmlType::RegistrationType registrationType,
QQmlImport::RecursionRestriction recursionRestriction,
QList<QQmlError> *errors) const
{
- if (majversion >= 0 && minversion >= 0) {
- QQmlType t = QQmlMetaType::qmlType(type, uri, majversion, minversion);
- if (t.isValid()) {
- if (vmajor)
- *vmajor = majversion;
- if (vminor)
- *vminor = minversion;
- if (type_return)
- *type_return = t;
- return true;
- }
+ QQmlType t = QQmlMetaType::qmlType(type, uri, version);
+ if (t.isValid()) {
+ if (version_return)
+ *version_return = version;
+ if (type_return)
+ *type_return = t;
+ return true;
}
const QString typeStr = type.toString();
+ if (isInlineComponent) {
+ Q_ASSERT(type_return);
+ bool ret = uri == typeStr;
+ if (ret) {
+ Q_ASSERT(!type_return->isValid());
+ *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;
@@ -730,30 +596,35 @@ bool QQmlImportInstance::resolveType(QQmlTypeLoader *typeLoader, const QHashedSt
break;
}
- // importing version -1 means import ALL versions
- if ((majversion == -1) ||
- (implicitlyImported && c.internal) || // allow the implicit import of internal types
- (c.majorVersion == majversion && c.minorVersion <= minversion)) {
+ // importing invalid version means import ALL versions
+ if (!version.hasMajorVersion() || (implicitlyImported && c.internal)
+ // allow the implicit import of internal types
+ || (c.version.majorVersion() == version.majorVersion()
+ && c.version.minorVersion() <= version.minorVersion())) {
// Is this better than the previous candidate?
- if ((candidate == end) ||
- (c.majorVersion > candidate->majorVersion) ||
- ((c.majorVersion == candidate->majorVersion) && (c.minorVersion > candidate->minorVersion))) {
+ if ((candidate == end)
+ || (c.version.majorVersion() > candidate->version.majorVersion())
+ || ((c.version.majorVersion() == candidate->version.majorVersion())
+ && (c.version.minorVersion() > candidate->version.minorVersion()))) {
if (base) {
componentUrl = resolveLocalUrl(QString(url + c.typeName + dotqml_string), c.fileName);
if (c.internal) {
if (resolveLocalUrl(*base, c.fileName) != componentUrl)
continue; // failed attempt to access an internal type
}
- if (recursionRestriction == QQmlImport::PreventRecursion && *base == componentUrl) {
- if (typeRecursionDetected)
- *typeRecursionDetected = true;
+
+ const bool recursion = *base == componentUrl;
+ if (typeRecursionDetected)
+ *typeRecursionDetected = recursion;
+
+ if (recursionRestriction == QQmlImport::PreventRecursion && recursion) {
continue; // no recursion
}
}
// This is our best candidate so far
candidate = it;
- isCompositeSingleton = c.singleton;
+ lookupMode = c.singleton ? QQmlMetaType::Singleton : QQmlMetaType::NonSingleton;
}
}
}
@@ -761,18 +632,20 @@ 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,
- nullptr, candidate->majorVersion,
- candidate->minorVersion);
- if (vmajor)
- *vmajor = candidate->majorVersion;
- if (vminor)
- *vminor = candidate->minorVersion;
+ QQmlType returnType = QQmlMetaType::typeForUrl(componentUrl, type, lookupMode,
+ nullptr, candidate->version);
+ if (version_return)
+ *version_return = candidate->version;
if (type_return)
*type_return = returnType;
return returnType.isValid();
}
- } else if (!isLibrary && !localDirectoryPath.isEmpty()) {
+ } else if (!isLibrary) {
+ // the base path of the import if it's a local file
+ const QString localDirectoryPath = QQmlFile::urlToLocalFileOrQrc(url);
+ if (localDirectoryPath.isEmpty())
+ return false;
+
QString qmlUrl;
bool exists = false;
@@ -803,12 +676,15 @@ bool QQmlImportInstance::resolveType(QQmlTypeLoader *typeLoader, const QHashedSt
}
if (exists) {
- if (recursionRestriction == QQmlImport::PreventRecursion && base && (*base == qmlUrl)) { // no recursion
- if (typeRecursionDetected)
- *typeRecursionDetected = true;
- } else {
+ const bool recursion = base && *base == qmlUrl;
+ if (typeRecursionDetected)
+ *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();
@@ -819,52 +695,91 @@ bool QQmlImportInstance::resolveType(QQmlTypeLoader *typeLoader, const QHashedSt
return false;
}
-bool QQmlImportsPrivate::resolveType(const QHashedStringRef& type, int *vmajor, int *vminor,
- QQmlType *type_return, QList<QQmlError> *errors,
- QQmlType::RegistrationType registrationType,
- QQmlImport::RecursionRestriction recursionRestriction)
+bool QQmlImports::resolveType(
+ QQmlTypeLoader *typeLoader, const QHashedStringRef &type, QTypeRevision *version_return,
+ QQmlType *type_return, QList<QQmlError> *errors,
+ QQmlType::RegistrationType registrationType, bool *typeRecursionDetected) const
{
- QQmlImportNamespace *s = nullptr;
- int dot = type.indexOf(Dot);
- if (dot >= 0) {
- QHashedStringRef namespaceName(type.constData(), dot);
- s = findQualifiedNamespace(namespaceName);
- if (!s) {
- if (errors) {
- QQmlError error;
- error.setDescription(QQmlImportDatabase::tr("- %1 is not a namespace").arg(namespaceName.toString()));
- errors->prepend(error);
- }
- return false;
- }
- int ndot = type.indexOf(Dot,dot+1);
- if (ndot > 0) {
- if (errors) {
- QQmlError error;
- error.setDescription(QQmlImportDatabase::tr("- nested namespaces not allowed"));
- errors->prepend(error);
- }
- return false;
- }
- } else {
- s = &unqualifiedset;
- }
- QHashedStringRef unqualifiedtype = dot < 0 ? type : QHashedStringRef(type.constData()+dot+1, type.length()-dot-1);
- if (s) {
- if (s->resolveType(typeLoader, unqualifiedtype, vmajor, vminor, type_return, &base, errors,
- registrationType, recursionRestriction))
+ 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, &m_base, errors,
+ registrationType, typeRecursionDetected))
return true;
- if (s->imports.count() == 1 && !s->imports.at(0)->isLibrary && type_return && s != &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(s->imports.at(0)->url,
+ resolveLocalUrl(nameSpace->imports.at(0)->url,
unqualifiedtype.toString() + QLatin1String(".qml")),
- type, false, errors);
+ type, QQmlMetaType::NonSingleton, errors);
return type_return->isValid();
}
+ return false;
+ };
+ switch (splitName.size()) {
+ case 1: {
+ // must be a simple type
+ return resolveTypeInNamespace(type, &m_unqualifiedset, errors);
}
-
- return false;
+ case 2: {
+ // either namespace + simple type OR simple type + inline component
+ QQmlImportNamespace *s = findQualifiedNamespace(splitName.at(0));
+ if (s) {
+ // namespace + simple type
+ return resolveTypeInNamespace(splitName.at(1), s, errors);
+ } else {
+ if (resolveTypeInNamespace(splitName.at(0), &m_unqualifiedset, nullptr)) {
+ // either simple type + inline component
+ *type_return = QQmlMetaType::inlineComponentType(
+ *type_return, splitName.at(1).toString());
+ return true;
+ } else {
+ // or a failure
+ if (errors) {
+ QQmlError error;
+ error.setDescription(QQmlImportDatabase::tr("- %1 is neither a type nor a namespace").arg(splitName.at(0).toString()));
+ errors->prepend(error);
+ }
+ return false;
+ }
+ }
+ }
+ case 3: {
+ // must be namespace + simple type + inline component
+ QQmlImportNamespace *s = findQualifiedNamespace(splitName.at(0));
+ QQmlError error;
+ if (!s) {
+ error.setDescription(QQmlImportDatabase::tr("- %1 is not a namespace").arg(splitName.at(0).toString()));
+ } else {
+ if (resolveTypeInNamespace(splitName.at(1), s, nullptr)) {
+ *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()));
+ }
+ }
+ if (errors) {
+ errors->prepend(error);
+ }
+ return false;
+ }
+ default: {
+ // all other numbers suggest a user error
+ if (errors) {
+ QQmlError error;
+ error.setDescription(QQmlImportDatabase::tr("- nested namespaces not allowed"));
+ errors->prepend(error);
+ }
+ return false;
+ }
+ }
+ Q_UNREACHABLE();
}
QQmlImportInstance *QQmlImportNamespace::findImport(const QString &uri) const
@@ -877,37 +792,50 @@ QQmlImportInstance *QQmlImportNamespace::findImport(const QString &uri) const
}
bool QQmlImportNamespace::resolveType(QQmlTypeLoader *typeLoader, const QHashedStringRef &type,
- int *vmajor, int *vminor, QQmlType *type_return,
- QString *base, QList<QQmlError> *errors,
+ QTypeRevision *version_return, QQmlType *type_return,
+ const QString *base, QList<QQmlError> *errors,
QQmlType::RegistrationType registrationType,
- QQmlImport::RecursionRestriction recursionRestriction)
+ bool *typeRecursionDetected)
{
- bool typeRecursionDetected = false;
- for (int i=0; i<imports.count(); ++i) {
+ QQmlImport::RecursionRestriction recursionRestriction =
+ typeRecursionDetected ? QQmlImport::AllowRecursion : QQmlImport::PreventRecursion;
+
+ bool localTypeRecursionDetected = false;
+ 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.size(); ++i) {
const QQmlImportInstance *import = imports.at(i);
- if (import->resolveType(typeLoader, type, vmajor, vminor, type_return, base,
- &typeRecursionDetected, registrationType, recursionRestriction, errors)) {
+ 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, vmajor, vminor, nullptr, base,
+ if (import2->resolveType(typeLoader, type, version_return, nullptr, base,
nullptr, registrationType)) {
if (errors) {
QString u1 = import->url;
QString u2 = import2->url;
if (base) {
- QStringRef b(base);
+ QStringView b(*base);
int dot = b.lastIndexOf(Dot);
if (dot >= 0) {
b = b.left(dot+1);
- QStringRef l = b.left(dot);
+ QStringView l = b.left(dot);
if (u1.startsWith(b))
- u1 = u1.mid(b.count());
+ u1 = u1.mid(b.size());
else if (u1 == l)
u1 = QQmlImportDatabase::tr("local directory");
if (u2.startsWith(b))
- u2 = u2.mid(b.count());
+ u2 = u2.mid(b.size());
else if (u2 == l)
u2 = QQmlImportDatabase::tr("local directory");
}
@@ -915,12 +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->majversion).arg(import->minversion)
- .arg(import2->majversion).arg(import2->minversion));
+ 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);
}
@@ -933,7 +869,7 @@ bool QQmlImportNamespace::resolveType(QQmlTypeLoader *typeLoader, const QHashedS
}
if (errors) {
QQmlError error;
- if (typeRecursionDetected)
+ if (*typeRecursionDetected)
error.setDescription(QQmlImportDatabase::tr("is instantiated recursively"));
else
error.setDescription(QQmlImportDatabase::tr("is not a type"));
@@ -942,19 +878,9 @@ bool QQmlImportNamespace::resolveType(QQmlTypeLoader *typeLoader, const QHashedS
return false;
}
-QQmlImportsPrivate::QQmlImportsPrivate(QQmlTypeLoader *loader)
-: ref(1), typeLoader(loader) {
-}
-
-QQmlImportsPrivate::~QQmlImportsPrivate()
-{
- while (QQmlImportNamespace *ns = qualifiedSets.takeFirst())
- delete ns;
-}
-
-QQmlImportNamespace *QQmlImportsPrivate::findQualifiedNamespace(const QHashedStringRef &prefix) const
+QQmlImportNamespace *QQmlImports::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;
}
@@ -962,234 +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, int vmaj, int vmin)
-{
- QStringList result;
- for (int version = QQmlImports::FullyVersioned; version <= QQmlImports::Unversioned; ++version) {
- int index = uri.length();
- do {
- QString versionUri = uri;
- versionUri.insert(index, QQmlImports::versionString(vmaj, vmin, static_cast<QQmlImports::ImportVersion>(version)));
- result += versionUri;
-
- index = uri.lastIndexOf(Dot, index - 1);
- } while (index > 0 && version != 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.
-
-\a qmldirFilePath is a raw file path.
*/
-bool QQmlImportsPrivate::importExtension(const QString &qmldirFilePath,
- const QString &uri,
- int vmaj, int vmin,
- 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());
- 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 false;
+ return QTypeRevision();
}
- int qmldirPluginCount = qmldir.plugins().count();
- if (qmldirPluginCount == 0)
- return true;
+ 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;
-
-#if QT_CONFIG(library)
- const auto qmldirPlugins = qmldir.plugins();
- for (const QQmlDirParser::Plugin &plugin : qmldirPlugins) {
- QString resolvedFilePath = database->resolvePlugin(typeLoader, qmldirPath, plugin.path, plugin.name);
- if (!resolvedFilePath.isEmpty()) {
- dynamicPluginsFound++;
- if (!database->importDynamicPlugin(resolvedFilePath, uri, typeNamespace, vmaj, errors)) {
- if (errors) {
- // XXX TODO: should we leave the import plugin error alone?
- // Here, we pop it off the top and coalesce it into this error's message.
- // The reason is that the lower level may add url and line/column numbering information.
- QQmlError error;
- error.setDescription(
- QQmlImportDatabase::tr(
- "plugin cannot be loaded for module \"%1\": %2")
- .arg(uri, errors->takeFirst().description()));
- error.setUrl(QUrl::fromLocalFile(qmldirFilePath));
- errors->prepend(error);
- }
- return false;
- }
- }
- }
-#endif // QT_CONFIG(library)
-
- 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, vmaj, vmin);
- QVector<StaticPluginPair> pluginPairs;
- if (!populatePluginPairVector(pluginPairs, uri, versionUris, qmldirFilePath, errors))
- return false;
+ QQmlPluginImporter importer(
+ uri, version, typeLoader->importDatabase(), qmldir, typeLoader, errors);
+ return importer.importPlugins();
+}
- 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();
- if (!database->importStaticPlugin(instance, basePath, uri, typeNamespace, vmaj, errors)) {
- if (errors) {
- 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 false;
- }
- 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 false;
- }
+ QQmlTypeLoaderQmldirContent redirected
+ = typeLoader->qmldirContent(url + QLatin1String("qmldir"));
- database->qmlDirFilesForWhichPluginsHaveBeenLoaded.insert(qmldirFilePath);
- }
- return true;
+ // 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))
@@ -1200,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;
}
}
@@ -1224,89 +991,48 @@ 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.
-*/
-bool QQmlImportsPrivate::locateQmldir(const QString &uri, int vmaj, int vmin, QQmlImportDatabase *database,
- QString *outQmldirFilePath, QString *outQmldirPathUrl)
-{
- Q_ASSERT(vmaj >= 0 && vmin >= 0); // Versions are always specified for libraries
-
- // 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->versionMajor == vmaj && cache->versionMinor == vmin) {
- *outQmldirFilePath = cache->qmldirFilePath;
- *outQmldirPathUrl = cache->qmldirPathUrl;
- return !cache->qmldirFilePath.isEmpty();
- }
- cache = cache->next;
- }
- }
- }
+/*!
+ \internal
- QQmlTypeLoader &typeLoader = QQmlEnginePrivate::get(database->engine)->typeLoader;
+ \fn template<typename Callback>
+ QQmlImportDatabase::LocalQmldirResult QQmlImportDatabase::locateLocalQmldir(
+ const QString &uri, QTypeRevision version, const Callback &callback)
- // Interceptor might redirect remote files to local ones.
- QQmlAbstractUrlInterceptor *interceptor = typeLoader.engine()->urlInterceptor();
- QStringList localImportPaths = database->importPathList(
- interceptor ? QQmlImportDatabase::LocalOrRemote : QQmlImportDatabase::Local);
+ 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.
- // Search local import paths for a matching version
- const QStringList qmlDirPaths = QQmlImports::completeQmldirPaths(uri, localImportPaths, vmaj, vmin);
- for (QString qmldirPath : qmlDirPaths) {
- if (interceptor) {
- qmldirPath = QQmlFile::urlToLocalFileOrQrc(
- interceptor->intercept(QQmlImports::urlFromLocalFileOrQrcOrUrl(qmldirPath),
- QQmlAbstractUrlInterceptor::QmldirFile));
- }
+ If at least one callback invocation returned \c false and there are no qmldir
+ files left to check, returns QmldirRejected.
- QString absoluteFilePath = typeLoader.absoluteFilePath(qmldirPath);
- if (!absoluteFilePath.isEmpty()) {
- QString url;
- const QStringRef absolutePath = absoluteFilePath.leftRef(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->versionMajor = vmaj;
- cache->versionMinor = vmin;
- cache->qmldirFilePath = absoluteFilePath;
- cache->qmldirPathUrl = url;
- cache->next = cacheHead;
- database->qmldirCache.insert(uri, cache);
-
- *outQmldirFilePath = absoluteFilePath;
- *outQmldirPathUrl = url;
+ Otherwise, if interception redirects a previously local qmldir URL to a remote
+ one, returns QmldirInterceptedToRemote. Otherwise, returns QmldirNotFound.
+*/
- return true;
+QTypeRevision QQmlImports::matchingQmldirVersion(
+ const QQmlTypeLoaderQmldirContent &qmldir, const QString &uri, QTypeRevision version,
+ QList<QQmlError> *errors)
+{
+ int bestMajorVersion = -1;
+ quint8 lowestMinorVersion = std::numeric_limits<quint8>::max();
+ quint8 highestMinorVersion = 0;
+
+ auto addVersion = [&](QTypeRevision newVersion) {
+ if (!newVersion.hasMajorVersion())
+ return;
+ if (!version.hasMajorVersion() || version.majorVersion() == newVersion.majorVersion()) {
+ if (newVersion.majorVersion() > bestMajorVersion) {
+ bestMajorVersion = newVersion.majorVersion();
+ if (newVersion.hasMinorVersion()) {
+ lowestMinorVersion = newVersion.minorVersion();
+ highestMinorVersion = newVersion.minorVersion();
+ }
+ } else if (newVersion.majorVersion() == bestMajorVersion
+ && newVersion.hasMinorVersion()) {
+ lowestMinorVersion = qMin(lowestMinorVersion, newVersion.minorVersion());
+ highestMinorVersion = qMax(highestMinorVersion, newVersion.minorVersion());
+ }
}
- }
-
- QQmlImportDatabase::QmldirCache *cache = new QQmlImportDatabase::QmldirCache;
- cache->versionMajor = vmaj;
- cache->versionMinor = vmin;
- cache->next = cacheHead;
- database->qmldirCache.insert(uri, cache);
-
- return false;
-}
-
-bool QQmlImportsPrivate::validateQmldirVersion(const QQmlTypeLoaderQmldirContent &qmldir, const QString &uri, int vmaj, int vmin,
- QList<QQmlError> *errors)
-{
- int lowest_min = INT_MAX;
- int highest_min = INT_MIN;
+ };
typedef QQmlDirComponents::const_iterator ConstIterator;
const QQmlDirComponents &components = qmldir.components();
@@ -1314,22 +1040,20 @@ bool QQmlImportsPrivate::validateQmldirVersion(const QQmlTypeLoaderQmldirContent
ConstIterator cend = components.constEnd();
for (ConstIterator cit = components.constBegin(); cit != cend; ++cit) {
for (ConstIterator cit2 = components.constBegin(); cit2 != cit; ++cit2) {
- if ((cit2->typeName == cit->typeName) &&
- (cit2->majorVersion == cit->majorVersion) &&
- (cit2->minorVersion == cit->minorVersion)) {
+ 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->majorVersion).arg(cit->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 false;
+ return QTypeRevision();
}
}
- if (cit->majorVersion == vmaj) {
- lowest_min = qMin(lowest_min, cit->minorVersion);
- highest_min = qMax(highest_min, cit->minorVersion);
- }
+ addVersion(cit->version);
}
typedef QList<QQmlDirParser::Script>::const_iterator SConstIterator;
@@ -1338,57 +1062,63 @@ bool QQmlImportsPrivate::validateQmldirVersion(const QQmlTypeLoaderQmldirContent
SConstIterator send = scripts.constEnd();
for (SConstIterator sit = scripts.constBegin(); sit != send; ++sit) {
for (SConstIterator sit2 = scripts.constBegin(); sit2 != sit; ++sit2) {
- if ((sit2->nameSpace == sit->nameSpace) &&
- (sit2->majorVersion == sit->majorVersion) &&
- (sit2->minorVersion == sit->minorVersion)) {
+ if (sit2->nameSpace == sit->nameSpace && sit2->version == sit->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(sit->nameSpace).arg(sit->majorVersion).arg(sit->minorVersion).arg(uri));
+ .arg(sit->nameSpace).arg(sit->version.majorVersion())
+ .arg(sit->version.minorVersion()).arg(uri));
errors->prepend(error);
- return false;
+ return QTypeRevision();
}
}
- if (sit->majorVersion == vmaj) {
- lowest_min = qMin(lowest_min, sit->minorVersion);
- highest_min = qMax(highest_min, sit->minorVersion);
- }
+ addVersion(sit->version);
}
- if (lowest_min > vmin || highest_min < vmin) {
- QQmlError error;
- error.setDescription(QQmlImportDatabase::tr("module \"%1\" version %2.%3 is not installed").arg(uri).arg(vmaj).arg(vmin));
- errors->prepend(error);
- return false;
+ // Failure to find a match is only an error if we were asking for a specific version ...
+ if (version.hasMajorVersion()
+ && (bestMajorVersion < 0
+ || (version.hasMinorVersion()
+ && (lowestMinorVersion > version.minorVersion()
+ || highestMinorVersion < version.minorVersion())))) {
+ errors->prepend(moduleNotFoundError(uri, version));
+ return QTypeRevision();
}
- return true;
+ // ... otherwise, anything is valid.
+ if (bestMajorVersion < 0)
+ return validVersion();
+
+ return QTypeRevision::fromVersion(
+ bestMajorVersion,
+ (version.hasMajorVersion() && version.hasMinorVersion())
+ ? version.minorVersion()
+ : 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(QQmlImportNamespace *nameSpace,
- const QString &uri, const QString &url, int vmaj, int vmin,
- QV4::CompiledData::Import::ImportType type,
- QList<QQmlError> *errors, bool lowPrecedence)
+static QQmlImportInstance *addImportToNamespace(
+ QQmlImportNamespace *nameSpace, const QString &uri, const QString &url, QTypeRevision version,
+ QV4::CompiledData::Import::ImportType type, QList<QQmlError> *errors, quint16 precedence)
{
Q_ASSERT(nameSpace);
Q_ASSERT(errors);
@@ -1398,75 +1128,135 @@ QQmlImportInstance *QQmlImportsPrivate::addImportToNamespace(QQmlImportNamespace
QQmlImportInstance *import = new QQmlImportInstance;
import->uri = uri;
import->url = url;
- import->localDirectoryPath = QQmlFile::urlToLocalFileOrQrc(url);
- import->majversion = vmaj;
- import->minversion = vmin;
+ import->version = version;
import->isLibrary = (type == QV4::CompiledData::Import::ImportLibrary);
+ import->precedence = precedence;
+ import->implicitlyImported = precedence >= QQmlImportInstance::Implicit;
- if (lowPrecedence)
- nameSpace->imports.append(import);
- 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;
}
-bool QQmlImportsPrivate::addLibraryImport(const QString& uri, const QString &prefix,
- int vmaj, int vmin, const QString &qmldirIdentifier, const QString &qmldirUrl, bool incomplete,
- 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, vmaj, vmin, QV4::CompiledData::Import::ImportLibrary, errors);
+ QQmlImportInstance *inserted = addImportToNamespace(
+ nameSpace, uri, qmldirUrl, version,
+ QV4::CompiledData::Import::ImportLibrary, errors,
+ precedence);
Q_ASSERT(inserted);
- if (!incomplete) {
+ if (!(flags & QQmlImports::ImportIncomplete)) {
QQmlTypeLoaderQmldirContent qmldir;
if (!qmldirIdentifier.isEmpty()) {
- if (!getQmldirContent(qmldirIdentifier, uri, &qmldir, errors))
- return false;
+ if (!getQmldirContent(typeLoader, qmldirIdentifier, uri, &qmldir, errors))
+ return QTypeRevision();
if (qmldir.hasContent()) {
- if (!importExtension(qmldir.pluginLocation(), uri, vmaj, vmin, database, qmldir, errors))
- return false;
+ version = importExtension(typeLoader, uri, version, &qmldir, errors);
+ if (!version.isValid())
+ return QTypeRevision();
+
+ const QString resolvedUrl = qmldir.hasRedirection()
+ ? redirectQmldirContent(typeLoader, &qmldir)
+ : qmldirUrl;
- if (!inserted->setQmldirContent(qmldirUrl, qmldir, nameSpace, errors))
- return false;
+ if (!inserted->setQmldirContent(resolvedUrl, qmldir, nameSpace, errors))
+ return QTypeRevision();
}
}
// Ensure that we are actually providing something
- if ((vmaj < 0) || (vmin < 0) || !QQmlMetaType::isModule(uri, vmaj, vmin)) {
- if (inserted->qmlDirComponents.isEmpty() && inserted->qmlDirScripts.isEmpty()) {
- QQmlError error;
- if (QQmlMetaType::isAnyModule(uri))
- error.setDescription(QQmlImportDatabase::tr("module \"%1\" version %2.%3 is not installed").arg(uri).arg(vmaj).arg(vmin));
- else
- error.setDescription(QQmlImportDatabase::tr("module \"%1\" is not installed").arg(uri));
- errors->prepend(error);
- return false;
- } else if ((vmaj >= 0) && (vmin >= 0) && qmldir.hasContent()) {
- // Verify that the qmldir content is valid for this version
- if (!validateQmldirVersion(qmldir, uri, vmaj, vmin, errors))
- return false;
+ const QTypeRevision matchingVersion = QQmlMetaType::matchingModuleVersion(uri, version);
+ if (matchingVersion.isValid())
+ return matchingVersion;
+
+ if (inserted->qmlDirComponents.isEmpty() && inserted->qmlDirScripts.isEmpty()) {
+ 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()) {
+ // Verify that the qmldir content is valid for this version
+ version = matchingQmldirVersion(qmldir, uri, version, errors);
+ if (!version.isValid())
+ return QTypeRevision();
}
}
- return true;
+ return validVersion(version);
}
-bool QQmlImportsPrivate::addFileImport(const QString& uri, const QString &prefix,
- int vmaj, int vmin,
- bool isImplicitImport, bool incomplete, 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);
@@ -1475,13 +1265,11 @@ bool QQmlImportsPrivate::addFileImport(const QString& uri, const QString &prefix
// 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));
- if (QQmlAbstractUrlInterceptor *interceptor = typeLoader->engine()->urlInterceptor()) {
- qmldirUrl = interceptor->intercept(QUrl(qmldirUrl),
- QQmlAbstractUrlInterceptor::QmldirFile).toString();
- }
+ qmldirUrl = typeLoader->engine()->interceptUrl(
+ QUrl(qmldirUrl), QQmlAbstractUrlInterceptor::QmldirFile).toString();
QString qmldirIdentifier;
if (QQmlFile::isLocalFile(qmldirUrl)) {
@@ -1491,39 +1279,51 @@ bool QQmlImportsPrivate::addFileImport(const QString& uri, const QString &prefix
const QString dir = localFileOrQrc.left(localFileOrQrc.lastIndexOf(Slash) + 1);
if (!typeLoader->directoryExists(dir)) {
- if (!isImplicitImport) {
+ if (precedence < QQmlImportInstance::Implicit) {
QQmlError error;
error.setDescription(QQmlImportDatabase::tr("\"%1\": no such directory").arg(uri));
error.setUrl(QUrl(qmldirUrl));
errors->prepend(error);
}
- return false;
+ return QTypeRevision();
}
// 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() && !incomplete) {
+ } else if (nameSpace->prefix.isEmpty() && !(flags & QQmlImports::ImportIncomplete)) {
- if (!isImplicitImport) {
+ if (precedence < QQmlImportInstance::Implicit) {
QQmlError error;
error.setDescription(QQmlImportDatabase::tr("import \"%1\" has no qmldir and no namespace").arg(importUri));
error.setUrl(QUrl(qmldirUrl));
errors->prepend(error);
}
- return false;
+ return QTypeRevision();
}
// 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;
@@ -1531,72 +1331,96 @@ bool QQmlImportsPrivate::addFileImport(const QString& uri, const QString &prefix
// 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 (isImplicitImport) {
+ if (precedence >= QQmlImportInstance::Implicit) {
for (QList<QQmlImportInstance *>::const_iterator it = nameSpace->imports.constBegin();
it != nameSpace->imports.constEnd(); ++it) {
if ((*it)->url == url) {
(*it)->implicitlyImported = true;
- return true;
+ return validVersion(version);
}
}
}
- QQmlImportInstance *inserted = addImportToNamespace(nameSpace, importUri, url, vmaj, vmin, QV4::CompiledData::Import::ImportFile, errors, isImplicitImport);
- Q_ASSERT(inserted);
-
- if (!incomplete && !qmldirIdentifier.isEmpty()) {
+ if (!(flags & QQmlImports::ImportIncomplete) && !qmldirIdentifier.isEmpty()) {
QQmlTypeLoaderQmldirContent qmldir;
- if (!getQmldirContent(qmldirIdentifier, importUri, &qmldir, errors))
- return false;
+ if (!getQmldirContent(typeLoader, qmldirIdentifier, importUri, &qmldir, errors))
+ return QTypeRevision();
if (qmldir.hasContent()) {
- if (!importExtension(qmldir.pluginLocation(), importUri, vmaj, vmin, database, qmldir, errors))
- return false;
+ // 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 false;
+ return QTypeRevision();
+
+ return validVersion(version);
}
}
- return true;
+ QQmlImportInstance *inserted = addImportToNamespace(
+ nameSpace, importUri, url, version, QV4::CompiledData::Import::ImportFile,
+ errors, precedence);
+ Q_ASSERT(inserted);
+ return validVersion(version);
}
-bool 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))
- return false;
+ if (!getQmldirContent(typeLoader, qmldirIdentifier, uri, &qmldir, errors))
+ return QTypeRevision();
if (qmldir.hasContent()) {
- int vmaj = import->majversion;
- int vmin = import->minversion;
- if (!importExtension(qmldir.pluginLocation(), uri, vmaj, vmin, database, qmldir, errors))
- return false;
+ 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::isModule(uri, vmaj, vmin)) {
- QQmlError error;
- if (QQmlMetaType::isAnyModule(uri))
- error.setDescription(QQmlImportDatabase::tr("module \"%1\" version %2.%3 is not installed").arg(uri).arg(vmaj).arg(vmin));
- else
- error.setDescription(QQmlImportDatabase::tr("module \"%1\" is not installed").arg(uri));
- errors->prepend(error);
- return false;
+ if (uri != QLatin1String(".") && !QQmlMetaType::matchingModuleVersion(uri, version).isValid()) {
+ errors->prepend(moduleNotFoundError(uri, relevantVersion(uri, version)));
+ return QTypeRevision();
}
- } else if ((vmaj >= 0) && (vmin >= 0)) {
+ } else {
// Verify that the qmldir content is valid for this version
- if (!validateQmldirVersion(qmldir, uri, vmaj, vmin, errors))
- return false;
+ version = matchingQmldirVersion(qmldir, uri, version, errors);
+ if (!version.isValid())
+ return QTypeRevision();
}
- return true;
+ return validVersion(version);
}
}
}
@@ -1607,10 +1431,11 @@ bool QQmlImportsPrivate::updateQmldirContent(const QString &uri, const QString &
errors->prepend(error);
}
- return false;
+ return QTypeRevision();
}
/*!
+ \fn QQmlImports::addImplicitImport(QQmlTypeLoader *typeLoader, QString *localQmldir, QList<QQmlError> *errors)
\internal
Adds an implicit "." file import. This is equivalent to calling addFileImport(), but error
@@ -1618,96 +1443,20 @@ bool QQmlImportsPrivate::updateQmldirContent(const QString &uri, const QString &
Additionally, this will add the import with lowest instead of highest precedence.
*/
-bool QQmlImports::addImplicitImport(QQmlImportDatabase *importDb, QList<QQmlError> *errors)
-{
- Q_ASSERT(errors);
-
- if (qmlImportTrace())
- qDebug().nospace() << "QQmlImports(" << qPrintable(baseUrl().toString())
- << ")::addImplicitImport";
- bool incomplete = !isLocal(baseUrl());
- return d->addFileImport(QLatin1String("."), QString(), -1, -1, true, incomplete, importDb, errors);
-}
/*!
- \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.
-*/
-bool QQmlImports::addFileImport(QQmlImportDatabase *importDb,
- const QString& uri, const QString& prefix, int vmaj, int vmin,
- bool incomplete, QList<QQmlError> *errors)
-{
- Q_ASSERT(importDb);
- Q_ASSERT(errors);
-
- if (qmlImportTrace())
- qDebug().nospace() << "QQmlImports(" << qPrintable(baseUrl().toString()) << ')' << "::addFileImport: "
- << uri << ' ' << vmaj << '.' << vmin << " as " << prefix;
-
- return d->addFileImport(uri, prefix, vmaj, vmin, false, incomplete, importDb, errors);
-}
-
-bool QQmlImports::addLibraryImport(QQmlImportDatabase *importDb,
- const QString &uri, const QString &prefix, int vmaj, int vmin,
- const QString &qmldirIdentifier, const QString& qmldirUrl, bool incomplete, QList<QQmlError> *errors)
-{
- Q_ASSERT(importDb);
- Q_ASSERT(errors);
-
- if (qmlImportTrace())
- qDebug().nospace() << "QQmlImports(" << qPrintable(baseUrl().toString()) << ')' << "::addLibraryImport: "
- << uri << ' ' << vmaj << '.' << vmin << " as " << prefix;
-
- return d->addLibraryImport(uri, prefix, vmaj, vmin, qmldirIdentifier, qmldirUrl, incomplete, importDb, errors);
-}
-
-bool 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);
-}
-
-bool QQmlImports::locateQmldir(QQmlImportDatabase *importDb,
- const QString& uri, int vmaj, int vmin,
- QString *qmldirFilePath, QString *url)
-{
- return d->locateQmldir(uri, vmaj, vmin, 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();
+ \internal
+ */
+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();
+ m_unqualifiedset.imports.push_back(importInstance);
+ m_unqualifiedset.setNeedsSorting(true);
+ return true;
}
QUrl QQmlImports::urlFromLocalFileOrQrcOrUrl(const QString &file)
@@ -1715,7 +1464,7 @@ 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;
}
@@ -1725,6 +1474,29 @@ void QQmlImports::setDesignerSupportRequired(bool b)
designerSupportRequired = b;
}
+static QStringList parseEnvPath(const QString &envImportPath)
+{
+ if (QDir::listSeparator() == u':') {
+ // Double colons are interpreted as separator + resource path.
+ QStringList paths = envImportPath.split(u':');
+ bool wasEmpty = false;
+ for (auto it = paths.begin(); it != paths.end();) {
+ if (it->isEmpty()) {
+ wasEmpty = true;
+ it = paths.erase(it);
+ } else {
+ if (wasEmpty) {
+ it->prepend(u':');
+ wasEmpty = false;
+ }
+ ++it;
+ }
+ }
+ return paths;
+ } else {
+ return envImportPath.split(QDir::listSeparator(), Qt::SkipEmptyParts);
+ }
+}
/*!
\class QQmlImportDatabase
@@ -1735,169 +1507,65 @@ QQmlImportDatabase::QQmlImportDatabase(QQmlEngine *e)
: engine(e)
{
filePluginPath << QLatin1String(".");
- // Search order is applicationDirPath(), qrc:/qt-project.org/imports, $QML2_IMPORT_PATH, QLibraryInfo::Qml2ImportsPath
-
- QString installImportsPath = QLibraryInfo::location(QLibraryInfo::Qml2ImportsPath);
- addImportPath(installImportsPath);
+ // 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
+
+ const auto paths = QLibraryInfo::paths(QLibraryInfo::QmlImportsPath);
+ for (const auto &installImportsPath: paths)
+ addImportPath(installImportsPath);
+
+ auto addEnvImportPath = [this](const char *var) {
+ if (Q_UNLIKELY(!qEnvironmentVariableIsEmpty(var))) {
+ const QStringList paths = parseEnvPath(qEnvironmentVariable(var));
+ for (int ii = paths.size() - 1; ii >= 0; --ii)
+ addImportPath(paths.at(ii));
+ }
+ };
// env import paths
- if (Q_UNLIKELY(!qEnvironmentVariableIsEmpty("QML2_IMPORT_PATH"))) {
- const QString envImportPath = qEnvironmentVariable("QML2_IMPORT_PATH");
-#if defined(Q_OS_WIN)
- QLatin1Char pathSep(';');
-#else
- QLatin1Char pathSep(':');
-#endif
- QStringList paths = envImportPath.split(pathSep, QString::SkipEmptyParts);
- for (int ii = paths.count() - 1; ii >= 0; --ii)
- addImportPath(paths.at(ii));
- }
+ 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, QString::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)
-{
- 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;
- auto bundledPath = resolvedPath + QLatin1String("lib") + pluginName.replace(QLatin1Char('/'), QLatin1Char('_'));
- 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)
-{
-#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
-# endif
- QLatin1String(".dll")
- };
-#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
}
/*!
@@ -1905,9 +1573,7 @@ QStringList QQmlImportDatabase::pluginPathList() const
*/
void QQmlImportDatabase::setPluginPathList(const QStringList &paths)
{
- if (qmlImportTrace())
- qDebug().nospace() << "QQmlImportDatabase::setPluginPathList: " << paths;
-
+ qCDebug(lcQmlImport) << "setPluginPathList:" << paths;
filePluginPath = paths;
}
@@ -1916,12 +1582,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 {
@@ -1929,13 +1594,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;
@@ -1951,7 +1620,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 {
@@ -1959,9 +1628,12 @@ void QQmlImportDatabase::addImportPath(const QString& path)
cPath.replace(Backslash, Slash);
}
- if (!cPath.isEmpty()
- && !fileImportPath.contains(cPath))
- fileImportPath.prepend(cPath);
+ if (!cPath.isEmpty()) {
+ if (fileImportPath.contains(cPath))
+ fileImportPath.move(fileImportPath.indexOf(cPath), 0);
+ else
+ fileImportPath.prepend(cPath);
+ }
}
/*!
@@ -1987,8 +1659,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)
@@ -2001,181 +1672,37 @@ void QQmlImportDatabase::setImportPathList(const QStringList &paths)
/*!
\internal
*/
-static bool registerPluginTypes(QObject *instance, const QString &basePath, const QString &uri,
- const QString &typeNamespace, int vmaj, QList<QQmlError> *errors)
+QTypeRevision QQmlImportDatabase::lockModule(const QString &uri, const QString &typeNamespace,
+ QTypeRevision version, QList<QQmlError> *errors)
{
- if (qmlImportTrace())
- qDebug().nospace() << "QQmlImportDatabase::registerPluginTypes: " << uri << " from " << basePath;
-
- if (!QQmlMetaType::registerPluginTypes(instance, basePath, uri, typeNamespace, vmaj, errors))
- return false;
-
- if (vmaj >= 0 && !typeNamespace.isEmpty() && !QQmlMetaType::protectModule(uri, vmaj)) {
- QQmlError error;
- error.setDescription(
- QString::fromLatin1("Cannot protect module %1 %2 as it was never registered")
- .arg(uri).arg(vmaj));
- errors->append(error);
- return false;
+ if (!version.hasMajorVersion()) {
+ version = QQmlMetaType::latestModuleVersion(uri);
+ if (!version.isValid())
+ errors->prepend(moduleNotFoundError(uri, version));
}
-
- return true;
-}
-
-/*!
- \internal
-*/
-bool QQmlImportDatabase::importStaticPlugin(QObject *instance, const QString &basePath,
- const QString &uri, const QString &typeNamespace, int vmaj, QList<QQmlError> *errors)
-{
- // 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);
- {
- StringRegisteredPluginMap *plugins = qmlEnginePluginsWithRegisteredTypes();
- QMutexLocker lock(&plugins->mutex);
-
- // Plugin types are global across all engines and should only be
- // registered once. But each engine still needs to be initialized.
- bool typesRegistered = plugins->contains(uniquePluginID);
-
- if (typesRegistered) {
- Q_ASSERT_X(plugins->value(uniquePluginID).uri == uri,
- "QQmlImportDatabase::importStaticPlugin",
- "Internal error: Static plugin imported previously with different uri");
- } else {
- RegisteredPlugin plugin;
- plugin.uri = uri;
- plugin.loader = nullptr;
- plugins->insert(uniquePluginID, plugin);
-
- if (!registerPluginTypes(instance, basePath, uri, typeNamespace, vmaj, errors))
- return false;
- }
-
- // 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 true;
-}
-
-#if QT_CONFIG(library)
-/*!
- \internal
-*/
-bool QQmlImportDatabase::importDynamicPlugin(const QString &filePath, const QString &uri,
- const QString &typeNamespace, int vmaj, QList<QQmlError> *errors)
-{
- QFileInfo fileInfo(filePath);
- const QString absoluteFilePath = fileInfo.absoluteFilePath();
-
- QObject *instance = nullptr;
- bool engineInitialized = initializedPlugins.contains(absoluteFilePath);
- {
- StringRegisteredPluginMap *plugins = qmlEnginePluginsWithRegisteredTypes();
- QMutexLocker lock(&plugins->mutex);
- bool typesRegistered = plugins->contains(absoluteFilePath);
-
- if (typesRegistered) {
- Q_ASSERT_X(plugins->value(absoluteFilePath).uri == uri,
- "QQmlImportDatabase::importDynamicPlugin",
- "Internal error: Plugin imported previously with different uri");
- }
-
- 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 false;
- }
-
- QPluginLoader* loader = nullptr;
- if (!typesRegistered) {
- loader = new QPluginLoader(absoluteFilePath);
-
- if (!loader->load()) {
- if (errors) {
- QQmlError error;
- error.setDescription(loader->errorString());
- errors->prepend(error);
- }
- delete loader;
- return false;
- }
- } else {
- loader = plugins->value(absoluteFilePath).loader;
- }
-
- instance = loader->instance();
-
- if (!typesRegistered) {
- RegisteredPlugin plugin;
- plugin.uri = uri;
- plugin.loader = loader;
- plugins->insert(absoluteFilePath, plugin);
-
- // Continue with shared code path for dynamic and static plugins:
- if (!registerPluginTypes(instance, fileInfo.absolutePath(), uri, typeNamespace, vmaj, errors))
- return false;
- }
- }
-
- // 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 (version.hasMajorVersion() && !typeNamespace.isEmpty()
+ && !QQmlMetaType::protectModule(uri, version, true)) {
+ // Not being able to protect the module means there are not types registered for it,
+ // means the plugin we loaded didn't provide any, means we didn't find the module.
+ // We output the generic error message as depending on the load order of imports we may
+ // hit this path or another one that only figures "plugin is already loaded but module
+ // unavailable" and doesn't try to protect it anymore.
+ errors->prepend(moduleNotFoundError(uri, version));
+ return QTypeRevision();
}
- if (!engineInitialized)
- finalizePlugin(instance, absoluteFilePath, uri);
-
- return true;
+ return version;
}
-bool QQmlImportDatabase::removeDynamicPlugin(const QString &filePath)
+bool QQmlImportDatabase::removeDynamicPlugin(const QString &pluginId)
{
- StringRegisteredPluginMap *plugins = qmlEnginePluginsWithRegisteredTypes();
- QMutexLocker lock(&plugins->mutex);
-
- auto it = plugins->find(QFileInfo(filePath).absoluteFilePath());
- if (it == plugins->end())
- return false;
-
- QPluginLoader *loader = it->loader;
- if (!loader)
- return false;
-
- if (!loader->unload()) {
- qWarning("Unloading %s failed: %s", qPrintable(it->uri),
- qPrintable(loader->errorString()));
- }
-
- delete loader;
- plugins->erase(it);
- return true;
+ return QQmlPluginImporter::removePlugin(pluginId);
}
QStringList QQmlImportDatabase::dynamicPlugins() const
{
- StringRegisteredPluginMap *plugins = qmlEnginePluginsWithRegisteredTypes();
- QMutexLocker lock(&plugins->mutex);
- QStringList results;
- for (auto it = plugins->constBegin(), end = plugins->constEnd(); it != end; ++it) {
- if (it->loader != nullptr)
- results.append(it.key());
- }
- return results;
+ return QQmlPluginImporter::plugins();
}
-#endif // QT_CONFIG(library)
void QQmlImportDatabase::clearDirCache()
{
@@ -2193,20 +1720,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 30d7c56a3e..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,24 +47,36 @@ 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
- QString localDirectoryPath; // the base path of the import if it's a local file
- int majversion; // the major version imported
- int minversion; // the minor version imported
+ 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
bool setQmldirContent(const QString &resolvedUrl, const QQmlTypeLoaderQmldirContent &qmldir,
QQmlImportNamespace *nameSpace, QList<QQmlError> *errors);
- static QQmlDirScripts getVersionedScripts(const QQmlDirScripts &qmldirscripts, int vmaj, int vmin);
+ static QQmlDirScripts getVersionedScripts(const QQmlDirScripts &qmldirscripts,
+ QTypeRevision version);
bool resolveType(QQmlTypeLoader *typeLoader, const QHashedStringRef &type,
- int *vmajor, int *vminor, QQmlType* type_return,
- QString *base = nullptr, bool *typeRecursionDetected = nullptr,
+ QTypeRevision *version_return, QQmlType* type_return,
+ const QString *base = nullptr, bool *typeRecursionDetected = nullptr,
QQmlType::RegistrationType = QQmlType::AnyRegistrationType,
QQmlImport::RecursionRestriction recursionRestriction = QQmlImport::PreventRecursion,
QList<QQmlError> *errors = nullptr) const;
@@ -111,62 +93,85 @@ public:
QQmlImportInstance *findImport(const QString &uri) const;
bool resolveType(QQmlTypeLoader *typeLoader, const QHashedStringRef& type,
- int *vmajor, int *vminor, QQmlType* type_return,
- QString *base = nullptr, QList<QQmlError> *errors = nullptr,
+ QTypeRevision *version_return, QQmlType* type_return,
+ const QString *base = nullptr, QList<QQmlError> *errors = nullptr,
QQmlType::RegistrationType registrationType = QQmlType::AnyRegistrationType,
- QQmlImport::RecursionRestriction recursionRestriction = QQmlImport::PreventRecursion);
+ bool *typeRecursionDeteced = nullptr);
// Prefix when used as a qualified import. Otherwise empty.
QHashedString prefix;
- // Used by QQmlImportsPrivate::qualifiedSets
- QQmlImportNamespace *nextNamespace;
+ // 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 = 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 };
- 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,
- int *version_major, int *version_minor,
- QQmlImportNamespace **ns_return,
- QList<QQmlError> *errors = nullptr,
- QQmlType::RegistrationType registrationType = QQmlType::AnyRegistrationType,
- QQmlImport::RecursionRestriction recursionRestriction
- = QQmlImport::PreventRecursion) const;
- bool resolveType(QQmlImportNamespace *,
- const QHashedStringRef& type,
- QQmlType *type_return, int *version_major, int *version_minor,
- 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(
+ QQmlTypeLoader *typeLoader, QString *localQmldir, QList<QQmlError> *errors)
+ {
+ Q_ASSERT(errors);
+ qCDebug(lcQmlImport) << "addImplicitImport:" << qPrintable(baseUrl().toString());
- bool addImplicitImport(QQmlImportDatabase *importDb, QList<QQmlError> *errors);
+ const ImportFlags flags =
+ ImportFlags(!isLocal(baseUrl()) ? ImportIncomplete : ImportNoFlag);
+ return addFileImport(
+ typeLoader, QLatin1String("."), QString(), QTypeRevision(), flags,
+ QQmlImportInstance::Implicit, localQmldir, errors);
+ }
- bool addFileImport(QQmlImportDatabase *,
- const QString& uri, const QString& prefix, int vmaj, int vmin, bool incomplete,
- QList<QQmlError> *errors);
+ bool addInlineComponentImport(
+ QQmlImportInstance *const importInstance, const QString &name, const QUrl importUrl);
- bool addLibraryImport(QQmlImportDatabase *importDb,
- const QString &uri, const QString &prefix, int vmaj, int vmin,
- const QString &qmldirIdentifier, const QString &qmldirUrl, bool incomplete, QList<QQmlError> *errors);
+ QTypeRevision addFileImport(
+ QQmlTypeLoader *typeLoader, const QString &uri, const QString &prefix,
+ QTypeRevision version, ImportFlags flags, quint16 precedence, QString *localQmldir,
+ QList<QQmlError> *errors);
- bool updateQmldirContent(QQmlImportDatabase *importDb,
- const QString &uri, const QString &prefix,
- const QString &qmldirIdentifier, const QString &qmldirUrl, QList<QQmlError> *errors);
+ QTypeRevision addLibraryImport(
+ QQmlTypeLoader *typeLoader, const QString &uri, const QString &prefix,
+ QTypeRevision version, const QString &qmldirIdentifier, const QString &qmldirUrl,
+ ImportFlags flags, quint16 precedence, QList<QQmlError> *errors);
- bool locateQmldir(QQmlImportDatabase *,
- const QString &uri, int vmaj, int vmin,
- QString *qmldirFilePath, QString *url);
+ QTypeRevision updateQmldirContent(
+ QQmlTypeLoader *typeLoader, const QString &uri, const QString &prefix,
+ const QString &qmldirIdentifier, const QString &qmldirUrl, QList<QQmlError> *errors);
void populateCache(QQmlTypeNameCache *cache) const;
@@ -183,83 +188,261 @@ public:
{
QString typeName;
QString prefix;
- int majorVersion;
- int minorVersion;
+ QTypeRevision version;
};
QList<CompositeSingletonReference> resolvedCompositeSingletons() const;
- static QStringList completeQmldirPaths(const QString &uri, const QStringList &basePaths, int vmaj, int vmin);
- static QString versionString(int vmaj, int vmin, ImportVersion 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)
+ {
+ return !QQmlFile::urlToLocalFileOrQrc(url).isEmpty();
+ }
+
+ static bool isLocal(const QUrl &url)
+ {
+ return !QQmlFile::urlToLocalFileOrQrc(url).isEmpty();
+ }
- static bool isLocal(const QString &url);
- static bool isLocal(const QUrl &url);
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(); }
-#if QT_CONFIG(library)
- bool importDynamicPlugin(const QString &filePath, const QString &uri, const QString &importNamespace, int vmaj, QList<QQmlError> *errors);
- bool removeDynamicPlugin(const QString &filePath);
+ bool removeDynamicPlugin(const QString &pluginId);
QStringList dynamicPlugins() const;
-#endif
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);
+ 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());
- QString resolvePlugin(QQmlTypeLoader *typeLoader,
- const QString &qmldirPath, const QString &qmldirPluginPath,
- const QString &baseName);
- bool importStaticPlugin(QObject *instance, const QString &basePath, const QString &uri,
- const QString &typeNamespace, int vmaj, 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 {
- int versionMajor;
- int versionMinor;
+ QTypeRevision version;
QString qmldirFilePath;
QString qmldirPathUrl;
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 f0ef5360b0..5c18230450 100644
--- a/src/qml/qml/qqmlincubator.cpp
+++ b/src/qml/qml/qqmlincubator.cpp
@@ -1,51 +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 "qqmlincubator.h"
#include "qqmlcomponent.h"
#include "qqmlincubator_p.h"
-#include "qqmlexpression_p.h"
#include "qqmlobjectcreator_p.h"
#include <private/qqmlcomponent_p.h>
-void QQmlEnginePrivate::incubate(QQmlIncubator &i, QQmlContextData *forContext)
+void QQmlEnginePrivate::incubate(
+ QQmlIncubator &i, const QQmlRefPointer<QQmlContextData> &forContext)
{
QExplicitlySharedDataPointer<QQmlIncubatorPrivate> p(i.d);
@@ -59,13 +23,13 @@ void QQmlEnginePrivate::incubate(QQmlIncubator &i, QQmlContextData *forContext)
// Need to find the first constructing context and see if it is asynchronous
QExplicitlySharedDataPointer<QQmlIncubatorPrivate> parentIncubator;
- QQmlContextData *cctxt = forContext;
+ QQmlRefPointer<QQmlContextData> cctxt = forContext;
while (cctxt) {
- if (!cctxt->hasExtraObject && cctxt->incubator) {
- parentIncubator = cctxt->incubator;
+ if (QQmlIncubatorPrivate *incubator = cctxt->incubator()) {
+ parentIncubator = incubator;
break;
}
- cctxt = cctxt->parent;
+ cctxt = cctxt->parent();
}
if (parentIncubator && parentIncubator->isAsynchronous) {
@@ -139,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--;
@@ -149,9 +116,9 @@ void QQmlIncubatorPrivate::clear()
}
enginePriv = nullptr;
if (!rootContext.isNull()) {
- if (!rootContext->hasExtraObject)
- rootContext->incubator = nullptr;
- rootContext = nullptr;
+ if (rootContext->incubator())
+ rootContext->setIncubator(nullptr);
+ rootContext.setContextData({});
}
if (nextWaitingFor.isInList()) {
@@ -210,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.
+
*/
/*!
@@ -262,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)
@@ -279,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);
@@ -299,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());
@@ -330,9 +319,9 @@ void QQmlIncubatorPrivate::incubate(QQmlInstantiationInterrupt &i)
ddata->rootObjectInCreation = false;
if (q) {
q->setInitialState(result);
- if (!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);
}
}
@@ -360,10 +349,8 @@ void QQmlIncubatorPrivate::incubate(QQmlInstantiationInterrupt &i)
if (watcher.hasRecursed())
return;
- QQmlContextData *ctxt = nullptr;
- ctxt = creator->finalize(i);
- if (ctxt) {
- rootContext = ctxt;
+ if (creator->finalize(i)) {
+ rootContext = creator->rootContext();
progress = QQmlIncubatorPrivate::Completed;
goto finishIncubate;
}
@@ -396,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)
@@ -403,27 +421,31 @@ void QQmlIncubationController::incubateFor(int msecs)
if (!d || !d->incubatorCount)
return;
- QQmlInstantiationInterrupt i(msecs * 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());
}
/*!
-Incubate objects while the bool pointed to by \a flag is true, or until there are no
-more objects to incubate, or up to \a msecs if \a msecs is not zero.
+\since 5.15
+
+Incubate objects while the atomic bool pointed to by \a flag is true,
+or until there are no more objects to incubate, or up to \a msecs if \a
+msecs is not zero.
Generally this method is used in conjunction with a thread or a UNIX signal that sets
the bool pointed to by \a flag to false when it wants incubation to be interrupted.
+
+\note \a flag is read using acquire memory ordering.
*/
-void QQmlIncubationController::incubateWhile(volatile bool *flag, int msecs)
+void QQmlIncubationController::incubateWhile(std::atomic<bool> *flag, int msecs)
{
if (!d || !d->incubatorCount)
return;
- QQmlInstantiationInterrupt i(flag, msecs * 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());
@@ -441,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
@@ -679,26 +713,33 @@ 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;
}
/*!
-Stores a mapping from property names to initial values with which the incubated
-component will be initialized
+Stores a mapping from property names to initial values, contained in
+\a initialProperties, with which the incubated component will be initialized.
\sa QQmlComponent::setInitialProperties
\since 5.15
@@ -719,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 f075407e73..c2389fc878 100644
--- a/src/qml/qml/qqmlincubator.h
+++ b/src/qml/qml/qqmlincubator.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) 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
#include <QtQml/qtqmlglobal.h>
#include <QtQml/qqmlerror.h>
+#include <atomic>
QT_BEGIN_NAMESPACE
@@ -49,7 +14,6 @@ QT_BEGIN_NAMESPACE
class QQmlEngine;
class QQmlPropertyData;
class QVariant;
-using QVariantMap = QMap<QString, QVariant>;
class QQmlIncubatorPrivate;
class Q_QML_EXPORT QQmlIncubator
@@ -112,7 +76,7 @@ public:
int incubatingObjectCount() const;
void incubateFor(int msecs);
- void incubateWhile(volatile bool *flag, int msecs=0);
+ void incubateWhile(std::atomic<bool> *flag, int msecs = 0);
protected:
virtual void incubatingObjectCountChanged(int);
diff --git a/src/qml/qml/qqmlincubator_p.h b/src/qml/qml/qqmlincubator_p.h
index aadb147bd5..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
@@ -46,7 +10,9 @@
#include <private/qqmlvme_p.h>
#include <private/qrecursionwatcher_p.h>
#include <private/qqmlengine_p.h>
-#include <private/qqmlcontext_p.h>
+#include <private/qqmlguardedcontextdata_p.h>
+
+#include <QtCore/qpointer.h>
//
// W A R N I N G
@@ -61,12 +27,10 @@
QT_BEGIN_NAMESPACE
-class QQmlPropertyData;
-struct RequiredPropertyInfo;
-using RequiredProperties = QHash<QQmlPropertyData*, RequiredPropertyInfo>;
+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);
@@ -74,6 +38,7 @@ public:
inline static QQmlIncubatorPrivate *get(QQmlIncubator *incubator) { return incubator->d; }
+ int subComponentToCreate;
QQmlIncubator *q;
QQmlIncubator::Status calculateStatus() const;
@@ -82,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;
@@ -107,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 2bfd2d5bb4..159a519bdc 100644
--- a/src/qml/qml/qqmlinfo.cpp
+++ b/src/qml/qml/qqmlinfo.cpp
@@ -1,63 +1,33 @@
-/****************************************************************************
-**
-** 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"
#include <QCoreApplication>
QT_BEGIN_NAMESPACE
/*!
- \namespace QtQml
+ \class QQmlInfo
\inmodule QtQml
- \brief Provides functions for producing logging messages for QML types.
+ \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 QtQml::qmlDebug(const QObject *object)
- \relates QtQml
+ \fn QQmlInfo qmlDebug(const QObject *object)
+ \relates QQmlInfo
\since 5.9
Prints debug messages that include the file and line number for the
@@ -86,12 +56,12 @@ QT_BEGIN_NAMESPACE
QML MyCustomType (unknown location): Internal state: 42
\endcode
- \sa QtQml::qmlInfo, QtQml::qmlWarning
+ \sa qmlInfo, qmlWarning
*/
/*!
- \fn QQmlInfo QtQml::qmlInfo(const QObject *object)
- \relates QtQml
+ \fn QQmlInfo qmlInfo(const QObject *object)
+ \relates QQmlInfo
Prints informational messages that include the file and line number for the
specified QML \a object.
@@ -114,12 +84,12 @@ QT_BEGIN_NAMESPACE
QtMsgType. For Qt 5.9 and above, qmlInfo uses an info QtMsgType. To send
warnings, use qmlWarning.
- \sa QtQml::qmlDebug, QtQml::qmlWarning
+ \sa qmlDebug, qmlWarning
*/
/*!
- \fn QQmlInfo QtQml::qmlWarning(const QObject *object)
- \relates QtQml
+ \fn QQmlInfo qmlWarning(const QObject *object)
+ \relates QQmlInfo
\since 5.9
Prints warning messages that include the file and line number for the
@@ -139,36 +109,36 @@ QT_BEGIN_NAMESPACE
QML MyCustomType (unknown location): property cannot be set to 0
\endcode
- \sa QtQml::qmlDebug, QtQml::qmlInfo
+ \sa qmlDebug, qmlInfo
*/
/*!
- \fn QQmlInfo QtQml::qmlDebug(const QObject *object, const QQmlError &error)
+ \fn QQmlInfo qmlDebug(const QObject *object, const QQmlError &error)
\internal
*/
/*!
- \fn QQmlInfo QtQml::qmlDebug(const QObject *object, const QList<QQmlError> &errors)
+ \fn QQmlInfo qmlDebug(const QObject *object, const QList<QQmlError> &errors)
\internal
*/
/*!
- \fn QQmlInfo QtQml::qmlInfo(const QObject *object, const QQmlError &error)
+ \fn QQmlInfo qmlInfo(const QObject *object, const QQmlError &error)
\internal
*/
/*!
- \fn QQmlInfo QtQml::qmlInfo(const QObject *object, const QList<QQmlError> &errors)
+ \fn QQmlInfo qmlInfo(const QObject *object, const QList<QQmlError> &errors)
\internal
*/
/*!
- \fn QQmlInfo QtQml::qmlWarning(const QObject *object, const QQmlError &error)
+ \fn QQmlInfo qmlWarning(const QObject *object, const QQmlError &error)
\internal
*/
/*!
- \fn QQmlInfo QtQml::qmlWarning(const QObject *object, const QList<QQmlError> &errors)
+ \fn QQmlInfo qmlWarning(const QObject *object, const QList<QQmlError> &errors)
\internal
*/
@@ -214,15 +184,28 @@ QQmlInfo::~QQmlInfo()
QObject *object = const_cast<QObject *>(d->object);
if (object) {
- engine = qmlEngine(d->object);
+ // Some objects (e.g. like attached objects created in C++) won't have an associated engine,
+ // but we can still try to look for a parent object that does.
+ QObject *objectWithEngine = object;
+ while (objectWithEngine) {
+ engine = qmlEngine(objectWithEngine);
+ if (engine)
+ break;
+ objectWithEngine = objectWithEngine->parent();
+ }
- d->buffer.prepend(QLatin1String("QML ") + QQmlMetaType::prettyTypeName(object) + QLatin1String(": "));
+ if (!objectWithEngine || objectWithEngine == object) {
+ d->buffer.prepend(QLatin1String("QML ") + QQmlMetaType::prettyTypeName(object) + QLatin1String(": "));
+ } else {
+ d->buffer.prepend(QLatin1String("QML ") + QQmlMetaType::prettyTypeName(objectWithEngine)
+ + QLatin1String(" (parent or ancestor of ") + QQmlMetaType::prettyTypeName(object) + QLatin1String("): "));
+ }
- QQmlData *ddata = QQmlData::get(object, false);
+ QQmlData *ddata = QQmlData::get(objectWithEngine ? objectWithEngine : object, false);
if (ddata && ddata->outerContext) {
error.setUrl(ddata->outerContext->url());
- error.setLine(ddata->lineNumber);
- error.setColumn(ddata->columnNumber);
+ error.setLine(qmlConvertSourceCoordinate<quint16, int>(ddata->lineNumber));
+ error.setColumn(qmlConvertSourceCoordinate<quint16, int>(ddata->columnNumber));
}
}
@@ -237,8 +220,6 @@ QQmlInfo::~QQmlInfo()
}
}
-namespace QtQml {
-
#define MESSAGE_FUNCS(FuncName, MessageLevel) \
QQmlInfo FuncName(const QObject *me) \
{ \
@@ -265,28 +246,4 @@ MESSAGE_FUNCS(qmlDebug, QtMsgType::QtDebugMsg)
MESSAGE_FUNCS(qmlInfo, QtMsgType::QtInfoMsg)
MESSAGE_FUNCS(qmlWarning, QtMsgType::QtWarningMsg)
-
-} // namespace QtQml
-
-#if QT_DEPRECATED_SINCE(5, 1)
-
-// Also define symbols outside namespace to keep binary compatibility with Qt 5.0
-
-QQmlInfo qmlInfo(const QObject *me)
-{
- return QtQml::qmlInfo(me);
-}
-
-QQmlInfo qmlInfo(const QObject *me, const QQmlError &error)
-{
- return QtQml::qmlInfo(me, error);
-}
-
-QQmlInfo qmlInfo(const QObject *me, const QList<QQmlError> &errors)
-{
- return QtQml::qmlInfo(me, errors);
-}
-
-#endif // QT_DEPRECATED_SINCE(5, 1)
-
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlinfo.h b/src/qml/qml/qqmlinfo.h
index faa112d4af..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
@@ -49,25 +13,17 @@ QT_BEGIN_NAMESPACE
class QQmlInfo;
-// declared in namespace to avoid symbol conflicts with QtDeclarative
-namespace QtQml {
- Q_QML_EXPORT QQmlInfo qmlDebug(const QObject *me);
- Q_QML_EXPORT QQmlInfo qmlDebug(const QObject *me, const QQmlError &error);
- Q_QML_EXPORT QQmlInfo qmlDebug(const QObject *me, const QList<QQmlError> &errors);
+Q_QML_EXPORT QQmlInfo qmlDebug(const QObject *me);
+Q_QML_EXPORT QQmlInfo qmlDebug(const QObject *me, const QQmlError &error);
+Q_QML_EXPORT QQmlInfo qmlDebug(const QObject *me, const QList<QQmlError> &errors);
- Q_QML_EXPORT QQmlInfo qmlInfo(const QObject *me);
- Q_QML_EXPORT QQmlInfo qmlInfo(const QObject *me, const QQmlError &error);
- Q_QML_EXPORT QQmlInfo qmlInfo(const QObject *me, const QList<QQmlError> &errors);
+Q_QML_EXPORT QQmlInfo qmlInfo(const QObject *me);
+Q_QML_EXPORT QQmlInfo qmlInfo(const QObject *me, const QQmlError &error);
+Q_QML_EXPORT QQmlInfo qmlInfo(const QObject *me, const QList<QQmlError> &errors);
- Q_QML_EXPORT QQmlInfo qmlWarning(const QObject *me);
- Q_QML_EXPORT QQmlInfo qmlWarning(const QObject *me, const QQmlError &error);
- Q_QML_EXPORT QQmlInfo qmlWarning(const QObject *me, const QList<QQmlError> &errors);
-}
-QT_WARNING_PUSH
-QT_WARNING_DISABLE_CLANG("-Wheader-hygiene")
-// This is necessary to allow for QtQuick1 and QtQuick2 scenes in a single application.
-using namespace QtQml;
-QT_WARNING_POP
+Q_QML_EXPORT QQmlInfo qmlWarning(const QObject *me);
+Q_QML_EXPORT QQmlInfo qmlWarning(const QObject *me, const QQmlError &error);
+Q_QML_EXPORT QQmlInfo qmlWarning(const QObject *me, const QList<QQmlError> &errors);
class QQmlInfoPrivate;
class Q_QML_EXPORT QQmlInfo : public QDebug
@@ -91,7 +47,7 @@ public:
inline QQmlInfo &operator<<(double t) { QDebug::operator<<(t); return *this; }
inline QQmlInfo &operator<<(const char* t) { QDebug::operator<<(t); return *this; }
inline QQmlInfo &operator<<(const QString & t) { QDebug::operator<<(t.toLocal8Bit().constData()); return *this; }
- inline QQmlInfo &operator<<(const QStringRef & t) { return operator<<(t.toString()); }
+ inline QQmlInfo &operator<<(QStringView t) { return operator<<(t.toString()); }
inline QQmlInfo &operator<<(const QLatin1String &t) { QDebug::operator<<(t.latin1()); return *this; }
inline QQmlInfo &operator<<(const QByteArray & t) { QDebug::operator<<(t); return *this; }
inline QQmlInfo &operator<<(const void * t) { QDebug::operator<<(t); return *this; }
@@ -102,15 +58,15 @@ public:
#endif
private:
- friend Q_QML_EXPORT QQmlInfo QtQml::qmlDebug(const QObject *me);
- friend Q_QML_EXPORT QQmlInfo QtQml::qmlDebug(const QObject *me, const QQmlError &error);
- friend Q_QML_EXPORT QQmlInfo QtQml::qmlDebug(const QObject *me, const QList<QQmlError> &errors);
- friend Q_QML_EXPORT QQmlInfo QtQml::qmlInfo(const QObject *me);
- friend Q_QML_EXPORT QQmlInfo QtQml::qmlInfo(const QObject *me, const QQmlError &error);
- friend Q_QML_EXPORT QQmlInfo QtQml::qmlInfo(const QObject *me, const QList<QQmlError> &errors);
- friend Q_QML_EXPORT QQmlInfo QtQml::qmlWarning(const QObject *me);
- friend Q_QML_EXPORT QQmlInfo QtQml::qmlWarning(const QObject *me, const QQmlError &error);
- friend Q_QML_EXPORT QQmlInfo QtQml::qmlWarning(const QObject *me, const QList<QQmlError> &errors);
+ friend Q_QML_EXPORT QQmlInfo qmlDebug(const QObject *me);
+ friend Q_QML_EXPORT QQmlInfo qmlDebug(const QObject *me, const QQmlError &error);
+ friend Q_QML_EXPORT QQmlInfo qmlDebug(const QObject *me, const QList<QQmlError> &errors);
+ friend Q_QML_EXPORT QQmlInfo qmlInfo(const QObject *me);
+ friend Q_QML_EXPORT QQmlInfo qmlInfo(const QObject *me, const QQmlError &error);
+ friend Q_QML_EXPORT QQmlInfo qmlInfo(const QObject *me, const QList<QQmlError> &errors);
+ friend Q_QML_EXPORT QQmlInfo qmlWarning(const QObject *me);
+ friend Q_QML_EXPORT QQmlInfo qmlWarning(const QObject *me, const QQmlError &error);
+ friend Q_QML_EXPORT QQmlInfo qmlWarning(const QObject *me, const QList<QQmlError> &errors);
QQmlInfo(QQmlInfoPrivate *);
QQmlInfoPrivate *d;
diff --git a/src/qml/qml/qqmlirloader.cpp b/src/qml/qml/qqmlirloader.cpp
index 82cad8eba8..e1019b804f 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,12 +22,73 @@ void QQmlIRLoader::load()
for (quint32 i = 0; i < qmlUnit->nImports; ++i)
output->imports << qmlUnit->importAt(i);
- if (unit->flags & QV4::CompiledData::Unit::IsSingleton) {
- 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 = QmlIR::Pragma::PragmaSingleton;
+ 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(Pragma::Singleton);
+ if (unit->flags & QV4::CompiledData::Unit::IsStrict)
+ 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 (unit->flags & QV4::CompiledData::Unit::ValueTypesAssertable)
+ valueTypeBehavior |= Pragma::Assertable;
+ if (valueTypeBehavior)
+ createValueTypePragma(Pragma::ValueTypeBehavior, valueTypeBehavior);
for (uint i = 0; i < qmlUnit->nObjects; ++i) {
const QV4::CompiledData::Object *serializedObject = qmlUnit->objectAt(i);
@@ -78,26 +103,26 @@ struct FakeExpression : public QQmlJS::AST::NullExpression
: location(start, length)
{}
- virtual QQmlJS::AST::SourceLocation firstSourceLocation() const
+ QQmlJS::SourceLocation firstSourceLocation() const override
{ return location; }
- virtual QQmlJS::AST::SourceLocation lastSourceLocation() const
+ QQmlJS::SourceLocation lastSourceLocation() const override
{ return location; }
private:
- QQmlJS::AST::SourceLocation location;
+ QQmlJS::SourceLocation location;
};
QmlIR::Object *QQmlIRLoader::loadObject(const QV4::CompiledData::Object *serializedObject)
{
QmlIR::Object *object = pool->New<QmlIR::Object>();
- object->init(pool, serializedObject->inheritedTypeNameIndex, serializedObject->idNameIndex);
+ object->init(pool, serializedObject->inheritedTypeNameIndex, serializedObject->idNameIndex,
+ serializedObject->location);
object->indexOfDefaultPropertyOrAlias = serializedObject->indexOfDefaultPropertyOrAlias;
- object->defaultPropertyIsAlias = serializedObject->defaultPropertyIsAlias;
- object->flags = serializedObject->flags;
- object->id = serializedObject->id;
- object->location = serializedObject->location;
+ object->defaultPropertyIsAlias = serializedObject->hasAliasAsDefaultProperty();
+ object->flags = serializedObject->flags();
+ object->id = serializedObject->objectId();
object->locationOfIdProperty = serializedObject->locationOfIdProperty;
QVector<int> functionIndices;
@@ -107,9 +132,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;
@@ -117,9 +142,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
@@ -129,7 +154,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);
@@ -185,7 +210,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;
@@ -200,6 +225,20 @@ QmlIR::Object *QQmlIRLoader::loadObject(const QV4::CompiledData::Object *seriali
object->runtimeFunctionIndices.allocate(pool, functionIndices);
+ const QV4::CompiledData::InlineComponent *serializedInlineComponent = serializedObject->inlineComponentTable();
+ for (uint i = 0; i < serializedObject->nInlineComponents; ++i, ++serializedInlineComponent) {
+ QmlIR::InlineComponent *ic = pool->New<QmlIR::InlineComponent>();
+ *static_cast<QV4::CompiledData::InlineComponent*>(ic) = *serializedInlineComponent;
+ object->inlineComponents->append(ic);
+ }
+
+ const QV4::CompiledData::RequiredPropertyExtraData *serializedRequiredPropertyExtraData = serializedObject->requiredPropertyExtraDataTable();
+ for (uint i = 0u; i < serializedObject->nRequiredPropertyExtraData; ++i, ++serializedRequiredPropertyExtraData) {
+ QmlIR::RequiredPropertyExtraData *extra = pool->New<QmlIR::RequiredPropertyExtraData>();
+ *static_cast<QV4::CompiledData::RequiredPropertyExtraData *>(extra) = *serializedRequiredPropertyExtraData;
+ object->requiredPropertyExtraDatas->append(extra);
+ }
+
return object;
}
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 8661ebcc13..d7cf38984b 100644
--- a/src/qml/qml/qqmljavascriptexpression.cpp
+++ b/src/qml/qml/qqmljavascriptexpression.cpp
@@ -1,43 +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 "qqmljavascriptexpression_p.h"
+#include "qqmljavascriptexpression_p.h"
#include <private/qqmlexpression_p.h>
#include <private/qv4context_p.h>
@@ -50,6 +15,10 @@
#include <private/qqmlglobal_p.h>
#include <private/qv4qobjectwrapper_p.h>
#include <private/qqmlbuiltinfunctions_p.h>
+#include <private/qqmlsourcecoordinate_p.h>
+#include <private/qqmlabstractbinding_p.h>
+#include <private/qqmlpropertybinding_p.h>
+#include <private/qproperty_p.h>
QT_BEGIN_NAMESPACE
@@ -72,8 +41,8 @@ bool QQmlDelayedError::addError(QQmlEnginePrivate *e)
void QQmlDelayedError::setErrorLocation(const QQmlSourceLocation &sourceLocation)
{
m_error.setUrl(QUrl(sourceLocation.sourceFile));
- m_error.setLine(sourceLocation.line);
- m_error.setColumn(sourceLocation.column);
+ m_error.setLine(qmlConvertSourceCoordinate<quint16, int>(sourceLocation.line));
+ m_error.setColumn(qmlConvertSourceCoordinate<quint16, int>(sourceLocation.column));
}
void QQmlDelayedError::setErrorDescription(const QString &description)
@@ -108,15 +77,33 @@ QQmlJavaScriptExpression::~QQmlJavaScriptExpression()
m_nextExpression->m_prevExpression = m_prevExpression;
}
+ while (qpropertyChangeTriggers) {
+ auto current = qpropertyChangeTriggers;
+ qpropertyChangeTriggers = current->next;
+ QRecyclePool<TriggerList>::Delete(current);
+ }
+
clearActiveGuards();
clearError();
if (m_scopeObject.isT2()) // notify DeleteWatcher of our deletion.
m_scopeObject.asT2()->_s = nullptr;
}
+QString QQmlJavaScriptExpression::expressionIdentifier() const
+{
+ if (auto f = function()) {
+ QString url = f->sourceFile();
+ uint lineNumber = f->compiledFunction->location.line();
+ uint columnNumber = f->compiledFunction->location.column();
+ return url + QString::asprintf(":%u:%u", lineNumber, columnNumber);
+ }
+
+ return QStringLiteral("[native code]");
+}
+
void QQmlJavaScriptExpression::setNotifyOnValueChanged(bool v)
{
- activeGuards.setFlagValue(v);
+ activeGuards.setTag(v ? NotifyOnValueChanged : NoGuardTag);
if (!v)
clearActiveGuards();
}
@@ -133,7 +120,7 @@ QQmlSourceLocation QQmlJavaScriptExpression::sourceLocation() const
return QQmlSourceLocation();
}
-void QQmlJavaScriptExpression::setContext(QQmlContextData *context)
+void QQmlJavaScriptExpression::setContext(const QQmlRefPointer<QQmlContextData> &context)
{
if (m_prevExpression) {
*m_prevExpression = m_nextExpression;
@@ -143,20 +130,10 @@ void QQmlJavaScriptExpression::setContext(QQmlContextData *context)
m_nextExpression = nullptr;
}
- m_context = context;
-
- if (context) {
- m_nextExpression = context->expressions;
- if (m_nextExpression)
- m_nextExpression->m_prevExpression = &m_nextExpression;
- m_prevExpression = &context->expressions;
- context->expressions = this;
- }
-}
+ m_context = context.data();
-QV4::Function *QQmlJavaScriptExpression::function() const
-{
- return m_v4Function;
+ if (context)
+ context->addExpression(this);
}
void QQmlJavaScriptExpression::refresh()
@@ -165,87 +142,136 @@ 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();
+ }
+
+ QV4::Scope scope(qmlengine->handle());
+ QV4::JSCallArguments jsCall(scope);
- return evaluate(jsCall.callData(), isUndefined);
+ 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)
@@ -281,6 +307,99 @@ void QQmlPropertyCapture::captureProperty(QObject *o, int c, int n, bool doNotif
return;
Q_ASSERT(expression);
+
+ // If c < 0 we won't find any property. We better leave the metaobjects alone in that case.
+ // QQmlListModel expects us _not_ to trigger the creation of dynamic metaobjects from here.
+ if (c >= 0) {
+ const QQmlData *ddata = QQmlData::get(o, /*create=*/false);
+ const QMetaObject *metaObjectForBindable = nullptr;
+ if (auto const propCache = (ddata ? ddata->propertyCache.data() : nullptr)) {
+ Q_ASSERT(propCache->property(c));
+ if (propCache->property(c)->isBindable())
+ metaObjectForBindable = propCache->metaObject();
+ } else {
+ const QMetaObject *m = o->metaObject();
+ if (m->property(c).isBindable())
+ metaObjectForBindable = m;
+ }
+ if (metaObjectForBindable) {
+ 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;
@@ -290,11 +409,9 @@ void QQmlPropertyCapture::captureProperty(QObject *o, int c, int n, bool doNotif
errorString->append(preamble);
}
- const QMetaObject *metaObj = o->metaObject();
- QMetaProperty metaProp = metaObj->property(c);
-
+ const QMetaProperty metaProp = o->metaObject()->property(c);
QString error = QLatin1String(" ") +
- QString::fromUtf8(metaObj->className()) +
+ QString::fromUtf8(o->metaObject()->className()) +
QLatin1String("::") +
QString::fromUtf8(metaProp.name());
errorString->append(error);
@@ -336,10 +453,11 @@ QQmlDelayedError *QQmlJavaScriptExpression::delayedError()
}
QV4::ReturnedValue
-QQmlJavaScriptExpression::evalFunction(QQmlContextData *ctxt, QObject *scopeObject,
- const QString &code, const QString &filename, quint16 line)
+QQmlJavaScriptExpression::evalFunction(
+ const QQmlRefPointer<QQmlContextData> &ctxt, QObject *scopeObject,
+ const QString &code, const QString &filename, quint16 line)
{
- QQmlEngine *engine = ctxt->engine;
+ QQmlEngine *engine = ctxt->engine();
QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine);
QV4::ExecutionEngine *v4 = engine->handle();
@@ -366,10 +484,11 @@ QQmlJavaScriptExpression::evalFunction(QQmlContextData *ctxt, QObject *scopeObje
return result->asReturnedValue();
}
-void QQmlJavaScriptExpression::createQmlBinding(QQmlContextData *ctxt, QObject *qmlScope,
- const QString &code, const QString &filename, quint16 line)
+void QQmlJavaScriptExpression::createQmlBinding(
+ const QQmlRefPointer<QQmlContextData> &ctxt, QObject *qmlScope, const QString &code,
+ const QString &filename, quint16 line)
{
- QQmlEngine *engine = ctxt->engine;
+ QQmlEngine *engine = ctxt->engine();
QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine);
QV4::ExecutionEngine *v4 = engine->handle();
@@ -395,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)
@@ -403,6 +522,32 @@ void QQmlJavaScriptExpression::setCompilationUnit(const QQmlRefPointer<QV4::Exec
m_compilationUnit = compilationUnit;
}
+void QPropertyChangeTrigger::trigger(QPropertyObserver *observer, QUntypedPropertyData *) {
+ auto This = static_cast<QPropertyChangeTrigger *>(observer);
+ 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 );
+ trigger->target = target;
+ trigger->propertyIndex = propertyIndex;
+ auto oldHead = qpropertyChangeTriggers;
+ trigger->next = oldHead;
+ qpropertyChangeTriggers = trigger;
+ return trigger;
+}
+
void QQmlJavaScriptExpression::clearActiveGuards()
{
while (QQmlJavaScriptExpressionGuard *g = activeGuards.takeFirst())
diff --git a/src/qml/qml/qqmljavascriptexpression_p.h b/src/qml/qml/qqmljavascriptexpression_p.h
index eecee08062..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
@@ -52,8 +16,10 @@
//
#include <QtCore/qglobal.h>
+#include <QtCore/qtaggedpointer.h>
#include <QtQml/qqmlerror.h>
#include <private/qqmlengine_p.h>
+#include <QtQml/private/qbipointer_p.h>
QT_BEGIN_NAMESPACE
@@ -96,17 +62,19 @@ private:
QQmlDelayedError **prevError;
};
-class Q_QML_PRIVATE_EXPORT QQmlJavaScriptExpression
+class Q_QML_EXPORT QQmlJavaScriptExpression
{
+ Q_DISABLE_COPY_MOVE(QQmlJavaScriptExpression)
public:
QQmlJavaScriptExpression();
virtual ~QQmlJavaScriptExpression();
- virtual QString expressionIdentifier() const = 0;
+ virtual QString expressionIdentifier() const;
virtual void expressionChanged() = 0;
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;
@@ -118,12 +86,23 @@ public:
virtual QQmlSourceLocation sourceLocation() const;
- bool isValid() const { return context() != nullptr; }
+ bool hasContext() const { return m_context != nullptr; }
+ bool hasValidContext() const { return m_context && m_context->isValid(); }
+ QQmlContext *publicContext() const { return m_context ? m_context->asQQmlContext() : nullptr; }
- QQmlContextData *context() const { return m_context; }
- void setContext(QQmlContextData *context);
+ QQmlRefPointer<QQmlContextData> context() const { return m_context; }
+ void setContext(const QQmlRefPointer<QQmlContextData> &context);
- QV4::Function *function() const;
+ void insertIntoList(QQmlJavaScriptExpression **listHead)
+ {
+ m_nextExpression = *listHead;
+ if (m_nextExpression)
+ m_nextExpression->m_prevExpression = &m_nextExpression;
+ m_prevExpression = listHead;
+ *listHead = this;
+ }
+
+ QV4::Function *function() const { return m_v4Function; }
virtual void refresh();
@@ -145,12 +124,21 @@ 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,
+ const QString &filename, quint16 line);
+
+ 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);
- static QV4::ReturnedValue evalFunction(QQmlContextData *ctxt, QObject *scope,
- const QString &code, const QString &filename,
- quint16 line);
protected:
- void createQmlBinding(QQmlContextData *ctxt, QObject *scope, const QString &code, const QString &filename, quint16 line);
+ void createQmlBinding(const QQmlRefPointer<QQmlContextData> &ctxt, QObject *scope,
+ const QString &code, const QString &filename, quint16 line);
void setupFunction(QV4::ExecutionContext *qmlContext, QV4::Function *f);
void setCompilationUnit(const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit);
@@ -159,30 +147,45 @@ protected:
// activeGuards:flag1 - notifyOnValueChanged
// activeGuards:flag2 - useSharedContext
QBiPointer<QObject, DeleteWatcher> m_scopeObject;
- QForwardFieldList<QQmlJavaScriptExpressionGuard, &QQmlJavaScriptExpressionGuard::next> activeGuards;
- void setTranslationsCaptured(bool captured) { m_error.setFlagValue(captured); }
- bool translationsCaptured() const { return m_error.flag(); }
+ enum GuardTag {
+ NoGuardTag,
+ NotifyOnValueChanged
+ };
+
+ QForwardFieldList<QQmlJavaScriptExpressionGuard, &QQmlJavaScriptExpressionGuard::next, GuardTag> activeGuards;
+
+ enum Tag {
+ NoTag,
+ InEvaluationLoop
+ };
+
+ QTaggedPointer<QQmlDelayedError, Tag> m_error;
private:
friend class QQmlContextData;
friend class QQmlPropertyCapture;
friend void QQmlJavaScriptExpressionGuard_callback(QQmlNotifierEndpoint *, void **);
- friend class QQmlTranslationBinding;
-
- // m_error:flag1 translationsCapturedDuringEvaluation
- QFlagPointer<QQmlDelayedError> m_error;
+ friend class QQmlTranslationBindingFromBinding;
+ friend class QQmlTranslationBindingFromTranslationInfo;
+ friend class QQmlJavaScriptExpressionCapture;
+ // Not refcounted as the context will clear the expressions when destructed.
QQmlContextData *m_context;
+
QQmlJavaScriptExpression **m_prevExpression;
QQmlJavaScriptExpression *m_nextExpression;
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)
@@ -195,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;
- QFieldList<QQmlJavaScriptExpressionGuard, &QQmlJavaScriptExpressionGuard::next> guards;
+ 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)
@@ -232,7 +239,7 @@ bool QQmlJavaScriptExpression::DeleteWatcher::wasDeleted() const
bool QQmlJavaScriptExpression::notifyOnValueChanged() const
{
- return activeGuards.flag();
+ return activeGuards.tag() == NotifyOnValueChanged;
}
QObject *QQmlJavaScriptExpression::scopeObject() const
diff --git a/src/qml/qml/qqmllist.cpp b/src/qml/qml/qqmllist.cpp
index 5425bf498c..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 = p?p->listType(propType):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,34 +87,83 @@ 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
+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.
+
+The \a engine is unused.
+*/
+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.
-Passing \a engine is required to access some QML created list properties. If in doubt, and an engine
-is available, pass it.
+The \a engine is unused.
*/
-QQmlListReference::QQmlListReference(QObject *object, const char *property, QQmlEngine *engine)
-: d(nullptr)
+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;
+
+ d = new QQmlListReferencePrivate;
+ d->propertyType = t;
+
+ d->property.~QQmlListProperty();
+ t.construct(&d->property, variant.constData());
+
+ d->object = d->property.object;
+}
+
+/*!
+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.
+*/
+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 = p?p->listType(data->propType()):QQmlMetaType::listType(data->propType());
- if (listType == -1) return;
-
d = new QQmlListReferencePrivate;
d->object = object;
- d->elementType = p ? p->rawMetaObjectForType(listType) : QQmlMetaType::qmlType(listType).baseMetaObject();
d->propertyType = data->propType();
void *args[] = { &d->property, nullptr };
@@ -197,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;
}
/*!
@@ -250,10 +266,37 @@ bool QQmlListReference::canCount() const
}
/*!
- Return true if at(), count(), append() and clear() are implemented, so you can manipulate
- the list.
+Returns true if items in the list property can be replaced, otherwise false.
+Returns false if the reference is invalid.
-\sa isReadable(), at(), count(), append(), clear()
+\sa replace()
+*/
+bool QQmlListReference::canReplace() const
+{
+ return (isValid() && d->property.replace);
+}
+
+/*!
+Returns true if the last item can be removed from the list property, otherwise false.
+Returns false if the reference is invalid.
+
+\sa removeLast()
+*/
+bool QQmlListReference::canRemoveLast() const
+{
+ return (isValid() && d->property.removeLast);
+}
+
+/*!
+ Return true if at(), count(), append(), and either clear() or removeLast()
+ are implemented, so you can manipulate the list.
+
+ Mind that replace() and removeLast() can be emulated by stashing all
+ items and rebuilding the list using clear() and append(). Therefore,
+ they are not required for the list to be manipulable. Furthermore,
+ clear() can be emulated using removeLast().
+
+\sa isReadable(), at(), count(), append(), clear(), replace(), removeLast()
*/
bool QQmlListReference::isManipulable() const
{
@@ -284,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);
@@ -297,7 +340,7 @@ Returns the list element at \a index, or 0 if the operation failed.
\sa canAt()
*/
-QObject *QQmlListReference::at(int index) const
+QObject *QQmlListReference::at(qsizetype index) const
{
if (!canAt()) return nullptr;
@@ -321,7 +364,7 @@ bool QQmlListReference::clear() const
/*!
Returns the number of objects in the list, or 0 if the operation failed.
*/
-int QQmlListReference::count() const
+qsizetype QQmlListReference::count() const
{
if (!canCount()) return 0;
@@ -329,6 +372,45 @@ int 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.
+
+\sa canReplace()
+*/
+bool QQmlListReference::replace(qsizetype index, QObject *object) const
+{
+ if (!canReplace())
+ return false;
+
+ if (!isObjectCompatible(object, d))
+ return false;
+
+ d->property.replace(&d->property, index, object);
+ return true;
+}
+
+/*!
+Removes the last item in the list.
+Returns true if the operation succeeded, otherwise false.
+
+\sa canRemoveLast()
+*/
+bool QQmlListReference::removeLast() const
+{
+ if (!canRemoveLast())
+ return false;
+
+ d->property.removeLast(&d->property);
+ return true;
+}
+
+/*!
\class QQmlListProperty
\since 5.0
\inmodule QtQml
@@ -365,7 +447,54 @@ 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}
+*/
+
+/*!
+ \macro QML_LIST_PROPERTY_ASSIGN_BEHAVIOR_APPEND
+ \relates QQmlListProperty
+
+ This macro defines the behavior of the list properties of this class to Append.
+ When assigning the property in a derived type, the values are appended
+ to those of the base class. This is the default behavior.
+
+ \snippet code/src_qml_qqmllist.cpp 0
+
+ \sa QML_LIST_PROPERTY_ASSIGN_BEHAVIOR_REPLACE_IF_NOT_DEFAULT
+ \sa QML_LIST_PROPERTY_ASSIGN_BEHAVIOR_REPLACE
+ \sa {Defining Object Types through QML Documents}
+*/
+
+/*!
+ \macro QML_LIST_PROPERTY_ASSIGN_BEHAVIOR_REPLACE_IF_NOT_DEFAULT
+ \relates QQmlListProperty
+
+ This macro defines the behavior of the list properties of this class to
+ ReplaceIfNotDefault.
+ When assigning the property in a derived type, the values replace those of
+ the base class unless it's the default property.
+ In the case of the default property, values are appended to those of the base class.
+
+ \snippet code/src_qml_qqmllist.cpp 1
+
+ \sa QML_LIST_PROPERTY_ASSIGN_BEHAVIOR_APPEND
+ \sa QML_LIST_PROPERTY_ASSIGN_BEHAVIOR_REPLACE
+ \sa {Defining Object Types through QML Documents}
+*/
+
+/*!
+ \macro QML_LIST_PROPERTY_ASSIGN_BEHAVIOR_REPLACE
+ \relates QQmlListProperty
+
+ This macro defines the behavior of the list properties of this class to Replace.
+ When assigning the property in a derived type, the values replace those
+ of the base class.
+
+ \snippet code/src_qml_qqmllist.cpp 2
+
+ \sa QML_LIST_PROPERTY_ASSIGN_BEHAVIOR_APPEND
+ \sa QML_LIST_PROPERTY_ASSIGN_BEHAVIOR_REPLACE_IF_NOT_DEFAULT
+ \sa {Defining Object Types through QML Documents}
*/
/*!
@@ -375,14 +504,25 @@ QML list properties are type-safe - in this case \c {Fruit} is a QObject type th
/*!
\fn template<typename T> QQmlListProperty<T>::QQmlListProperty(QObject *object, QList<T *> &list)
+\deprecated
Convenience constructor for making a QQmlListProperty value from an existing
QList \a list. The \a list reference must remain valid for as long as \a object
exists. \a object must be provided.
-Generally this constructor should not be used in production code, as a
-writable QList violates QML's memory management rules. However, this constructor
-can be very useful while prototyping.
+This constructor synthesizes the removeLast() and replace() methods
+introduced in Qt 5.15, using count(), at(), clear(), and append(). This is slow.
+If you intend to manipulate the list beyond clearing it, you should explicitly
+provide these methods.
+*/
+
+/*!
+\fn template<typename T> QQmlListProperty<T>::QQmlListProperty(QObject *object, QList<T *> *list)
+\since 5.15
+
+Convenience constructor for making a QQmlListProperty value from an existing
+QList \a list. The \a list reference must remain valid for as long as \a object
+exists. \a object must be provided.
*/
/*!
@@ -408,6 +548,39 @@ remains valid while \a object exists.
Null pointers can be passed for any function. If any null pointers are passed in, the list
will be neither designable nor alterable by the debugger. It is recommended to provide valid
pointers for all functions.
+
+\note The resulting QQmlListProperty will synthesize the removeLast() and
+replace() methods using \a count, \a at, \a clear, and \a append if all of those
+are given. This is slow. If you intend to manipulate the list beyond clearing it,
+you should explicitly provide these methods.
+*/
+
+/*!
+\fn template<typename T> QQmlListProperty<T>::QQmlListProperty(
+ QObject *object, void *data, AppendFunction append, CountFunction count,
+ AtFunction at, ClearFunction clear, ReplaceFunction replace,
+ RemoveLastFunction removeLast)
+
+Construct a QQmlListProperty from a set of operation functions \a append,
+\a count, \a at, \a clear, \a replace, and \removeLast. An opaque \a data handle
+may be passed which can be accessed from within the operation functions. The
+list property remains valid while \a object exists.
+
+Null pointers can be passed for any function, causing the respective function to
+be synthesized using the others, if possible. QQmlListProperty can synthesize
+\list
+ \li \a clear using \a count and \a removeLast
+ \li \a replace using \a count, \a at, \a clear, and \a append
+ \li \a replace using \a count, \a at, \a removeLast, and \a append
+ \li \a removeLast using \a count, \a at, \a clear, and \a append
+\endlist
+if those are given. This is slow, but if your list does not natively provide
+faster options for these primitives, you may want to use the synthesized ones.
+
+Furthermore, if either of \a count, \a at, \a append, and \a clear are neither
+given explicitly nor synthesized, the list will be neither designable nor
+alterable by the debugger. It is recommended to provide enough valid pointers
+to avoid this situation.
*/
/*!
@@ -421,7 +594,7 @@ Append the \a value to the list \a property.
/*!
\typedef QQmlListProperty::CountFunction
-Synonym for \c {int (*)(QQmlListProperty<T> *property)}.
+Synonym for \c {qsizetype (*)(QQmlListProperty<T> *property)}.
Return the number of elements in the list \a property.
*/
@@ -435,7 +608,7 @@ Returns true if this QQmlListProperty is equal to \a other, otherwise false.
/*!
\typedef QQmlListProperty::AtFunction
-Synonym for \c {T *(*)(QQmlListProperty<T> *property, int index)}.
+Synonym for \c {T *(*)(QQmlListProperty<T> *property, qsizetype index)}.
Return the element at position \a index in the list \a property.
*/
@@ -448,4 +621,31 @@ Synonym for \c {void (*)(QQmlListProperty<T> *property)}.
Clear the list \a property.
*/
+/*!
+\typedef QQmlListProperty::ReplaceFunction
+
+Synonym for \c {void (*)(QQmlListProperty<T> *property, qsizetype index, T *value)}.
+
+Replace the element at position \a index in the list \a property with \a value.
+*/
+
+/*!
+\typedef QQmlListProperty::RemoveLastFunction
+
+Synonym for \c {void (*)(QQmlListProperty<T> *property)}.
+
+Remove the last element from the list \a property.
+*/
+
+/*!
+\fn bool QQmlListReference::operator==(const QQmlListReference &other) const
+
+Compares this QQmlListReference to \a other, and returns \c true if they are
+equal. The two are only considered equal if one was created from the other
+via copy assignment or copy construction.
+
+\note Independently created references to the same object are not considered
+to be equal.
+*/
+
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmllist.h b/src/qml/qml/qqmllist.h
index 90ec57c911..6f2c077764 100644
--- a/src/qml/qml/qqmllist.h
+++ b/src/qml/qml/qqmllist.h
@@ -1,76 +1,44 @@
-/****************************************************************************
-**
-** 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>
QT_BEGIN_NAMESPACE
-
class QObject;
struct QMetaObject;
-#ifndef QQMLLISTPROPERTY
-#define QQMLLISTPROPERTY
+#define QML_LIST_PROPERTY_ASSIGN_BEHAVIOR_APPEND Q_CLASSINFO("QML.ListPropertyAssignBehavior", "Append")
+#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")
+
template<typename T>
class QQmlListProperty {
public:
- typedef void (*AppendFunction)(QQmlListProperty<T> *, T*);
- typedef int (*CountFunction)(QQmlListProperty<T> *);
- typedef T *(*AtFunction)(QQmlListProperty<T> *, int);
- typedef void (*ClearFunction)(QQmlListProperty<T> *);
-
- QQmlListProperty()
- : append(nullptr),
- count(nullptr),
- at(nullptr),
- clear(nullptr)
- {}
- QQmlListProperty(QObject *o, QList<T *> &list)
- : object(o), data(&list), append(qlist_append), count(qlist_count), at(qlist_at),
- clear(qlist_clear)
+ using value_type = T*;
+
+ using AppendFunction = void (*)(QQmlListProperty<T> *, T *);
+ using CountFunction = qsizetype (*)(QQmlListProperty<T> *);
+ using AtFunction = T *(*)(QQmlListProperty<T> *, qsizetype);
+ using ClearFunction = void (*)(QQmlListProperty<T> *);
+ using ReplaceFunction = void (*)(QQmlListProperty<T> *, qsizetype, T *);
+ using RemoveLastFunction = void (*)(QQmlListProperty<T> *);
+ QQmlListProperty() = default;
+
+ QQmlListProperty(QObject *o, QList<T *> *list)
+ : object(o), data(list), append(qlist_append), count(qlist_count), at(qlist_at),
+ clear(qlist_clear), replace(qlist_replace), removeLast(qlist_removeLast)
{}
+
QQmlListProperty(QObject *o, void *d, AppendFunction a, CountFunction c, AtFunction t,
ClearFunction r )
: object(o),
@@ -78,53 +46,136 @@ public:
append(a),
count(c),
at(t),
- clear(r)
-
+ clear(r),
+ replace((a && c && t && r) ? qslow_replace : nullptr),
+ removeLast((a && c && t && r) ? qslow_removeLast : nullptr)
{}
- QQmlListProperty(QObject *o, void *d, CountFunction c, AtFunction t)
+
+ QQmlListProperty(QObject *o, void *d, AppendFunction a, CountFunction c, AtFunction t,
+ ClearFunction r, ReplaceFunction s, RemoveLastFunction p)
: object(o),
data(d),
- append(nullptr),
- count(c), at(t),
- clear(nullptr)
+ append(a),
+ count(c),
+ at(t),
+ clear((!r && p && c) ? qslow_clear : r),
+ replace((!s && a && c && t && (r || p)) ? qslow_replace : s),
+ removeLast((!p && a && c && t && r) ? qslow_removeLast : p)
{}
+
+ QQmlListProperty(QObject *o, void *d, CountFunction c, AtFunction a)
+ : object(o), data(d), count(c), at(a)
+ {}
+
bool operator==(const QQmlListProperty &o) const {
return object == o.object &&
data == o.data &&
append == o.append &&
count == o.count &&
at == o.at &&
- clear == o.clear;
+ clear == o.clear &&
+ replace == o.replace &&
+ removeLast == o.removeLast;
}
QObject *object = nullptr;
void *data = nullptr;
- AppendFunction append;
+ AppendFunction append = nullptr;
+ CountFunction count = nullptr;
+ AtFunction at = nullptr;
+ ClearFunction clear = nullptr;
+ 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);
+ }
- CountFunction count;
- AtFunction at;
+ const qsizetype size = count(this);
- ClearFunction clear;
+ List result;
+ if constexpr (QContainerInfo::has_reserve_v<List>)
+ result.reserve(size);
- void *dummy1 = nullptr;
- void *dummy2 = nullptr;
+ 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 int qlist_count(QQmlListProperty *p) {
- return reinterpret_cast<QList<T *> *>(p->data)->count();
+ static qsizetype qlist_count(QQmlListProperty *p) {
+ return static_cast<QList<T *> *>(p->data)->size();
}
- static T *qlist_at(QQmlListProperty *p, int idx) {
- return reinterpret_cast<QList<T *> *>(p->data)->at(idx);
+ static T *qlist_at(QQmlListProperty *p, qsizetype 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 static_cast<QList<T *> *>(p->data)->replace(idx, v);
+ }
+ static void qlist_removeLast(QQmlListProperty *p) {
+ return static_cast<QList<T *> *>(p->data)->removeLast();
+ }
+
+ static void qslow_replace(QQmlListProperty<T> *list, qsizetype idx, T *v)
+ {
+ const qsizetype length = list->count(list);
+ if (idx < 0 || idx >= length)
+ return;
+
+ QVector<T *> stash;
+ if (list->clear != qslow_clear) {
+ stash.reserve(length);
+ for (qsizetype i = 0; i < length; ++i)
+ stash.append(i == idx ? v : list->at(list, i));
+ list->clear(list);
+ for (T *item : std::as_const(stash))
+ list->append(list, item);
+ } else {
+ stash.reserve(length - idx - 1);
+ for (qsizetype i = length - 1; i > idx; --i) {
+ stash.append(list->at(list, i));
+ list->removeLast(list);
+ }
+ list->removeLast(list);
+ list->append(list, v);
+ while (!stash.isEmpty())
+ list->append(list, stash.takeLast());
+ }
+ }
+
+ static void qslow_clear(QQmlListProperty<T> *list)
+ {
+ for (qsizetype i = 0, end = list->count(list); i < end; ++i)
+ list->removeLast(list);
+ }
+
+ static void qslow_removeLast(QQmlListProperty<T> *list)
+ {
+ const qsizetype length = list->count(list) - 1;
+ if (length < 0)
+ return;
+ QVector<T *> stash;
+ stash.reserve(length);
+ for (qsizetype i = 0; i < length; ++i)
+ stash.append(list->at(list, i));
+ list->clear(list);
+ for (T *item : std::as_const(stash))
+ list->append(list, item);
}
};
-#endif
class QQmlEngine;
class QQmlListReferencePrivate;
@@ -132,7 +183,17 @@ class Q_QML_EXPORT QQmlListReference
{
public:
QQmlListReference();
- 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();
@@ -146,20 +207,31 @@ public:
bool canAt() const;
bool canClear() const;
bool canCount() const;
+ bool canReplace() const;
+ bool canRemoveLast() const;
bool isManipulable() const;
bool isReadable() const;
bool append(QObject *) const;
- QObject *at(int) const;
+ QObject *at(qsizetype) const;
bool clear() const;
- int count() 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;}
private:
friend class QQmlListReferencePrivate;
QQmlListReferencePrivate* d;
};
+namespace QtPrivate {
+template<typename T>
+inline constexpr bool IsQmlListType<QQmlListProperty<T>> = true;
+}
+
QT_END_NAMESPACE
Q_DECLARE_METATYPE(QQmlListReference)
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 5349572921..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,35 +177,66 @@ 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)
*hasProperty = false;
return Value::undefinedValue().asReturnedValue();
- } else if (id.isString()) {
- if (id == v4->id_length()->propertyKey() && !w->d()->object.isNull()) {
- 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)
{
- // doesn't do anything. Should we throw?
- Q_UNUSED(m);
- Q_UNUSED(id);
- Q_UNUSED(value);
- Q_UNUSED(receiver);
- return false;
+ Q_ASSERT(m->as<QmlListWrapper>());
+
+ const auto *w = static_cast<const QmlListWrapper *>(m);
+ QV4::ExecutionEngine *v4 = w->engine();
+
+ QQmlListProperty<QObject> *prop = w->d()->property();
+
+ if (id.isArrayIndex()) {
+ if (!prop->count || !prop->replace)
+ return false;
+
+ const uint index = id.asArrayIndex();
+ const int count = prop->count(prop);
+ 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>()) {
+ prop->replace(prop, index, wrapper->object());
+ return true;
+ }
+
+ return false;
+ }
+
+ return Object::virtualPut(m, id, value, receiver);
}
struct QmlListWrapperOwnPropertyKeyIterator : ObjectOwnPropertyKeyIterator
@@ -150,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)
@@ -170,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)
@@ -184,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());
}
- return Encode::undefined();
+
+ 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();
+ }
+
+ 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 c185122ad9..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();
- QQmlQPointer<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 dca13ac8d4..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(QDateTime(date)));
+ 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(QDateTime(dt)));
+ 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,254 +434,164 @@ 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_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());
-}
+ 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_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();
+ mismatched0 = true;
+ }
- return QV4::Encode(locale->textDirection());
-}
+ // Anything can be coerced to a number, for better or worse ...
+ Q_ASSERT(argc >= 2);
-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 arg1(scope, (*args)[1]);
+ if (!arg1->isInteger()) {
+ doThrow(QLatin1String(
+ "Locale: formattedDataSize(): Invalid argument ('precision' must be an int)"));
+ return;
+ }
+
+ if (mismatched0) {
+ if (argc == 2) {
+ const QString result = locale.formattedDataSize(
+ qint64(arg0->toInteger()), arg1->integerValue());
+ args->setReturnValue(scope.engine->newString(result)->asReturnedValue());
+ return;
+ }
+
+ 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);
-
- prototype.set(engine, o);
-}
+ // toString(QDateTime, QString)
+ Q_ASSERT(!arg1->isString());
-QV4LocaleDataDeletable::~QV4LocaleDataDeletable()
-{
-}
+ // toString(QDateTime, QLocale::FormatType)
+ Q_ASSERT(!arg1->isNumber());
+
+ doThrow(QLatin1String("Locale: the second argument to the toString overloads whose "
+ "first argument is a Date should be a string or FormatType"));
+ return;
+ }
-V4_DEFINE_EXTENSION(QV4LocaleDataDeletable, localeV4Data);
+ doThrow(QLatin1String("Locale: toString() expects either an int, double, "
+ "or Date as its first argument"));
+}
/*!
\qmltype Locale
- \instantiates QQmlLocale
+ //! \instantiates QQmlLocale
\inqmlmodule QtQml
\brief Provides locale specific properties and formatted data.
@@ -767,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
@@ -805,31 +681,18 @@ V4_DEFINE_EXTENSION(QV4LocaleDataDeletable, localeV4Data);
\sa Date, Number
*/
-QQmlLocale::QQmlLocale()
-{
-}
-
-QQmlLocale::~QQmlLocale()
-{
-}
-
QV4::ReturnedValue QQmlLocale::locale(ExecutionEngine *engine, const QString &localeName)
{
- QLocale qlocale;
- if (!localeName.isEmpty())
- 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)
@@ -854,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.
*/
/*!
@@ -873,6 +736,16 @@ ReturnedValue QQmlLocale::method_localeCompare(const QV4::FunctionObject *b, con
*/
/*!
+ \qmlproperty enumeration QtQml::Locale::numberOptions
+
+ Holds a set of options for number-to-string and
+ string-to-number conversions.
+
+ \sa Number::toLocaleString()
+ \sa Number::fromLocaleString()
+*/
+
+/*!
\qmlproperty string QtQml::Locale::percent
Holds the percent character of this locale.
@@ -931,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
@@ -985,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.
@@ -1009,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
@@ -1024,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.
*/
/*!
@@ -1046,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()
*/
@@ -1060,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.
@@ -1073,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 10e0dfcc38..82c65ccf82 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);
@@ -90,36 +54,15 @@ private:
static QV4::ReturnedValue method_toLocaleCurrencyString(const QV4::FunctionObject *, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
};
-
-class Q_QML_PRIVATE_EXPORT QQmlLocale
+// This needs to be a struct so that we can derive from QLocale and inherit its enums. Then we can
+// use it as extension in QQmlLocaleEnums and expose all the enums in one go, without duplicating
+// any in different qmltypes files.
+struct Q_QML_EXPORT QQmlLocale : public QLocale
{
Q_GADGET
- QML_NAMED_ELEMENT(Locale)
- QML_UNCREATABLE("Locale cannot be instantiated. Use Qt.locale().")
- QML_ADDED_IN_MINOR_VERSION(2)
-
+ QML_ANONYMOUS
public:
- ~QQmlLocale();
- enum MeasurementSystem {
- MetricSystem = QLocale::MetricSystem,
- ImperialSystem = QLocale::ImperialSystem,
- ImperialUSSystem = QLocale::ImperialUSSystem,
- ImperialUKSystem = QLocale::ImperialUKSystem
- };
- Q_ENUM(MeasurementSystem)
- enum FormatType {
- LongFormat = QLocale::LongFormat,
- ShortFormat = QLocale::ShortFormat,
- NarrowFormat = QLocale::NarrowFormat
- };
- Q_ENUM(FormatType)
- enum CurrencySymbolFormat {
- CurrencyIsoCode = QLocale::CurrencyIsoCode,
- CurrencySymbol = QLocale::CurrencySymbol,
- CurrencyDisplayName = QLocale::CurrencyDisplayName
- };
- Q_ENUM(CurrencySymbolFormat)
// Qt defines Sunday as 7, but JS Date assigns Sunday 0
enum DayOfWeek {
Sunday = 0,
@@ -133,76 +76,173 @@ public:
Q_ENUM(DayOfWeek)
static QV4::ReturnedValue locale(QV4::ExecutionEngine *engine, const QString &localeName);
- static QV4::ReturnedValue wrap(QV4::ExecutionEngine *engine, const QLocale &locale);
-
static void registerStringLocaleCompare(QV4::ExecutionEngine *engine);
+ static QV4::ReturnedValue method_localeCompare(
+ const QV4::FunctionObject *, const QV4::Value *thisObject,
+ const QV4::Value *argv, int argc);
+};
-private:
- QQmlLocale();
-
- static QV4::ReturnedValue method_localeCompare(const QV4::FunctionObject *, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
+struct DayOfWeekList
+{
+ Q_GADGET
+ QML_ANONYMOUS
+ QML_FOREIGN(QList<QQmlLocale::DayOfWeek>)
+ QML_SEQUENTIAL_CONTAINER(QQmlLocale::DayOfWeek)
};
-namespace QV4 {
+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)
-namespace Heap {
+ Q_GADGET
+ QML_ANONYMOUS
+ QML_FOREIGN(QLocale)
+ QML_EXTENDED(QQmlLocaleValueType)
+ QML_CONSTRUCTIBLE_VALUE
+
+public:
+ Q_INVOKABLE QQmlLocaleValueType(const QString &name) : locale(name) {}
-struct QQmlLocaleData : Object {
- inline void init() { locale = new QLocale; }
- void destroy() {
- delete locale;
- Object::destroy();
+ 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);
-};
+ 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
deleted file mode 100644
index b59a26e17e..0000000000
--- a/src/qml/qml/qqmlloggingcategory.cpp
+++ /dev/null
@@ -1,160 +0,0 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
-
-#include "qqmlloggingcategory_p.h"
-
-#include <QtQml/qqmlinfo.h>
-
-/*!
- \qmltype LoggingCategory
- \ingroup qml-utility-elements
- \inqmlmodule QtQml
- \brief Defines a logging category in QML.
- \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.
-
- \qml
- import QtQuick 2.8
-
- Item {
- LoggingCategory {
- id: category
- name: "com.qt.category"
- defaultLogLevel: LoggingCategory.Warning
- }
-
- Component.onCompleted: {
- console.log(category, "message");
- }
- }
- \endqml
-
- \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.
-
- \sa QLoggingCategory
-*/
-
-/*!
- \qmlproperty string QtQml::LoggingCategory::name
-
- Holds the name of the logging category.
-
- \note This property needs to be set when declaring the LoggingCategory
- and cannot be changed later.
-
- \sa QLoggingCategory::categoryName()
-*/
-
-/*!
- \qmlproperty enumeration QtQml::LoggingCategory::defaultLogLevel
- \since 5.12
-
- Holds the default log level of the logging category. By default it is
- created with the LoggingCategory.Debug log level.
-
- \note This property needs to be set when declaring the LoggingCategory
- and cannot be changed later.
-*/
-
-QQmlLoggingCategory::QQmlLoggingCategory(QObject *parent)
- : QObject(parent)
- , m_initialized(false)
-{
-}
-
-QQmlLoggingCategory::~QQmlLoggingCategory()
-{
-}
-
-QString QQmlLoggingCategory::name() const
-{
- return QString::fromUtf8(m_name);
-}
-
-QQmlLoggingCategory::DefaultLogLevel QQmlLoggingCategory::defaultLogLevel() const
-{
- return m_defaultLogLevel;
-}
-
-QLoggingCategory *QQmlLoggingCategory::category() const
-{
- return m_category.data();
-}
-
-void QQmlLoggingCategory::classBegin()
-{
-}
-
-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 !");
- } else {
- QScopedPointer<QLoggingCategory> category(new QLoggingCategory(m_name.constData(), QtMsgType(m_defaultLogLevel)));
- m_category.swap(category);
- }
-}
-
-void QQmlLoggingCategory::setDefaultLogLevel(DefaultLogLevel defaultLogLevel)
-{
- if (m_initialized) {
- qmlWarning(this) << QLatin1String("The defaultLogLevel of a LoggingCategory cannot be changed after the Item is created");
- return;
- }
-
- m_defaultLogLevel = defaultLogLevel;
-}
-
-
-void QQmlLoggingCategory::setName(const QString &name)
-{
- if (m_initialized) {
- qmlWarning(this) << QLatin1String("The name of a LoggingCategory cannot be changed after the Item is created");
- return;
- }
-
- m_name = name.toUtf8();
-}
-
-#include "moc_qqmlloggingcategory_p.cpp"
diff --git a/src/qml/qml/qqmlloggingcategory_p.h b/src/qml/qml/qqmlloggingcategory_p.h
deleted file mode 100644
index c7377528b4..0000000000
--- a/src/qml/qml/qqmlloggingcategory_p.h
+++ /dev/null
@@ -1,105 +0,0 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
-
-#ifndef QQMLLOGGINGCATEGORY_P_H
-#define QQMLLOGGINGCATEGORY_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/qobject.h>
-#include <QtCore/qstring.h>
-#include <QtCore/qloggingcategory.h>
-
-#include <QtQml/qqmlparserstatus.h>
-#include <QtQml/qqml.h>
-
-QT_BEGIN_NAMESPACE
-
-class QQmlLoggingCategory : public QObject, public QQmlParserStatus
-{
- Q_OBJECT
- Q_INTERFACES(QQmlParserStatus)
-
- Q_PROPERTY(QString name READ name WRITE setName)
- Q_PROPERTY(DefaultLogLevel defaultLogLevel READ defaultLogLevel WRITE setDefaultLogLevel REVISION 12)
- QML_NAMED_ELEMENT(LoggingCategory)
- QML_ADDED_IN_MINOR_VERSION(8)
-
-public:
- enum DefaultLogLevel {
- Debug = QtDebugMsg,
- Info = QtInfoMsg,
- Warning = QtWarningMsg,
- Critical = QtCriticalMsg,
- Fatal = QtFatalMsg
- };
- Q_ENUM(DefaultLogLevel);
-
- QQmlLoggingCategory(QObject *parent = nullptr);
- virtual ~QQmlLoggingCategory();
-
- DefaultLogLevel defaultLogLevel() const;
- void setDefaultLogLevel(DefaultLogLevel defaultLogLevel);
- QString name() const;
- void setName(const QString &name);
-
- QLoggingCategory *category() const;
-
- void classBegin() override;
- void componentComplete() override;
-
-private:
- QByteArray m_name;
- QScopedPointer<QLoggingCategory> m_category;
- DefaultLogLevel m_defaultLogLevel = Debug;
- bool m_initialized;
-};
-
-QT_END_NAMESPACE
-
-#endif // QQMLLOGGINGCATEGORY_H
diff --git a/src/qml/qml/qqmlloggingcategorybase_p.h b/src/qml/qml/qqmlloggingcategorybase_p.h
new file mode 100644
index 0000000000..4a3c4cf6aa
--- /dev/null
+++ b/src/qml/qml/qqmlloggingcategorybase_p.h
@@ -0,0 +1,47 @@
+// Copyright (C) 2024 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 QQMLLOGGINGCATEGORYBASE_P_H
+#define QQMLLOGGINGCATEGORYBASE_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/qqml.h>
+
+#include <QtCore/qobject.h>
+#include <QtCore/qloggingcategory.h>
+
+#include <memory>
+
+QT_BEGIN_NAMESPACE
+
+class Q_QML_EXPORT QQmlLoggingCategoryBase : public QObject
+{
+ Q_OBJECT
+ QML_ANONYMOUS
+
+public:
+ QQmlLoggingCategoryBase(QObject *parent = nullptr) : QObject(parent) {}
+
+ const QLoggingCategory *category() const { return m_category.get(); }
+ void setCategory(const char *name, QtMsgType type)
+ {
+ m_category = std::make_unique<QLoggingCategory>(name, type);
+ }
+
+private:
+ std::unique_ptr<QLoggingCategory> m_category;
+};
+
+QT_END_NAMESPACE
+
+#endif // QQMLLOGGINGCATEGORYBASE_P_H
diff --git a/src/qml/qml/qqmlmetaobject.cpp b/src/qml/qml/qqmlmetaobject.cpp
index a967f46b12..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,100 +8,6 @@
QT_BEGIN_NAMESPACE
-struct StaticQtMetaObject : public QObject
-{
- static const QMetaObject *get()
- { return &staticQtMetaObject; }
-};
-
-static bool isNamedEnumeratorInScope(const QMetaObject *resolvedMetaObject, const QByteArray &scope,
- const QByteArray &name)
-{
- for (int i = resolvedMetaObject->enumeratorCount() - 1; i >= 0; --i) {
- QMetaEnum m = resolvedMetaObject->enumerator(i);
- if ((m.name() == name) && (scope.isEmpty() || (m.scope() == scope)))
- return true;
- }
- return false;
-}
-
-static bool isNamedEnumerator(const QMetaObject *metaObj, const QByteArray &scopedName)
-{
- QByteArray scope;
- QByteArray name;
- int scopeIdx = scopedName.lastIndexOf("::");
- if (scopeIdx != -1) {
- scope = scopedName.left(scopeIdx);
- name = scopedName.mid(scopeIdx + 2);
- } else {
- name = scopedName;
- }
-
- if (scope == "Qt")
- return isNamedEnumeratorInScope(StaticQtMetaObject::get(), scope, name);
-
- if (isNamedEnumeratorInScope(metaObj, scope, name))
- return true;
-
- if (metaObj->d.relatedMetaObjects && !scope.isEmpty()) {
- for (auto related = metaObj->d.relatedMetaObjects; *related; ++related) {
- if (isNamedEnumeratorInScope(*related, scope, name))
- return true;
- }
- }
-
- return false;
-}
-
-// 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());
-
- struct I { static bool equal(const QMetaObject *lhs, const QMetaObject *rhs) {
- return lhs == rhs || (lhs && rhs && lhs->d.stringdata == rhs->d.stringdata);
- } };
-
- const QMetaObject *tom = to._m.isT1()?to._m.asT1()->metaObject():to._m.asT2();
- if (tom == &QObject::staticMetaObject) return true;
-
- if (from._m.isT1() && to._m.isT1()) { // QQmlPropertyCache -> QQmlPropertyCache
- QQmlPropertyCache *fromp = from._m.asT1();
- QQmlPropertyCache *top = to._m.asT1();
-
- while (fromp) {
- if (fromp == top) return true;
- fromp = fromp->parent();
- }
- } else if (from._m.isT1() && to._m.isT2()) { // QQmlPropertyCache -> QMetaObject
- QQmlPropertyCache *fromp = from._m.asT1();
-
- while (fromp) {
- const QMetaObject *fromm = fromp->metaObject();
- if (fromm && I::equal(fromm, tom)) return true;
- fromp = fromp->parent();
- }
- } else if (from._m.isT2() && to._m.isT1()) { // QMetaObject -> QQmlPropertyCache
- const QMetaObject *fromm = from._m.asT2();
-
- if (!tom) return false;
-
- while (fromm) {
- if (I::equal(fromm, tom)) return true;
- fromm = fromm->superClass();
- }
- } else { // QMetaObject -> QMetaObject
- const QMetaObject *fromm = from._m.asT2();
-
- while (fromm) {
- if (I::equal(fromm, tom)) return true;
- fromm = fromm->superClass();
- }
- }
-
- return false;
-}
-
void QQmlMetaObject::resolveGadgetMethodOrPropertyIndex(QMetaObject::Call type, const QMetaObject **metaObject, int *index)
{
int offset;
@@ -146,11 +16,6 @@ void QQmlMetaObject::resolveGadgetMethodOrPropertyIndex(QMetaObject::Call type,
case QMetaObject::ReadProperty:
case QMetaObject::WriteProperty:
case QMetaObject::ResetProperty:
- case QMetaObject::QueryPropertyDesignable:
- case QMetaObject::QueryPropertyEditable:
- case QMetaObject::QueryPropertyScriptable:
- case QMetaObject::QueryPropertyStored:
- case QMetaObject::QueryPropertyUser:
offset = (*metaObject)->propertyOffset();
while (*index < offset) {
*metaObject = (*metaObject)->superClass();
@@ -173,155 +38,22 @@ void QQmlMetaObject::resolveGadgetMethodOrPropertyIndex(QMetaObject::Call type,
*index -= offset;
}
-QQmlPropertyCache *QQmlMetaObject::propertyCache(QQmlEnginePrivate *e) const
+QMetaType QQmlMetaObject::methodReturnType(const QQmlPropertyData &data, QByteArray *unknownTypeError) const
{
- if (_m.isNull()) return nullptr;
- if (_m.isT1()) return _m.asT1();
- else return e->cache(_m.asT2());
-}
-
-int QQmlMetaObject::methodReturnType(const QQmlPropertyData &data, QByteArray *unknownTypeError) const
-{
- Q_ASSERT(!_m.isNull() && data.coreIndex() >= 0);
-
- int type = data.propType();
-
- const char *propTypeName = nullptr;
+ Q_ASSERT(_m && data.coreIndex() >= 0);
- if (type == QMetaType::UnknownType) {
+ QMetaType type = data.propType();
+ if (!type.isValid()) {
// Find the return type name from the method info
- QMetaMethod m;
-
- if (_m.isT1()) {
- QQmlPropertyCache *c = _m.asT1();
- Q_ASSERT(data.coreIndex() < c->methodIndexCacheStart + c->methodIndexCache.count());
-
- while (data.coreIndex() < c->methodIndexCacheStart)
- c = c->_parent;
-
- const QMetaObject *metaObject = c->createMetaObject();
- Q_ASSERT(metaObject);
- m = metaObject->method(data.coreIndex());
- } else {
- m = _m.asT2()->method(data.coreIndex());
- }
-
- type = m.returnType();
- propTypeName = m.typeName();
- }
-
- if (QMetaType::sizeOf(type) <= int(sizeof(int))) {
- if (QMetaType::typeFlags(type) & QMetaType::IsEnumeration)
- return QMetaType::Int;
-
- if (isNamedEnumerator(metaObject(), propTypeName))
- return QMetaType::Int;
-
- if (type == QMetaType::UnknownType) {
- if (unknownTypeError)
- *unknownTypeError = propTypeName;
- }
- } // else we know that it's a known type, as sizeOf(UnknownType) == 0
-
- return type;
-}
-
-int *QQmlMetaObject::methodParameterTypes(int index, ArgTypeStorage *argStorage,
- QByteArray *unknownTypeError) const
-{
- Q_ASSERT(!_m.isNull() && index >= 0);
-
- if (_m.isT1()) {
- typedef QQmlPropertyCacheMethodArguments A;
-
- QQmlPropertyCache *c = _m.asT1();
- Q_ASSERT(index < c->methodIndexCacheStart + c->methodIndexCache.count());
-
- while (index < c->methodIndexCacheStart)
- c = c->_parent;
-
- QQmlPropertyData *rv = const_cast<QQmlPropertyData *>(&c->methodIndexCache.at(index - c->methodIndexCacheStart));
-
- if (rv->arguments() && static_cast<A *>(rv->arguments())->argumentsValid)
- return static_cast<A *>(rv->arguments())->arguments;
-
- const QMetaObject *metaObject = c->createMetaObject();
- Q_ASSERT(metaObject);
- QMetaMethod m = metaObject->method(index);
-
- int argc = m.parameterCount();
- if (!rv->arguments()) {
- A *args = c->createArgumentsObject(argc, m.parameterNames());
- rv->setArguments(args);
- }
- A *args = static_cast<A *>(rv->arguments());
-
- QList<QByteArray> argTypeNames; // Only loaded if needed
-
- for (int ii = 0; ii < argc; ++ii) {
- int type = m.parameterType(ii);
-
- if (QMetaType::sizeOf(type) > int(sizeof(int))) {
- // Cannot be passed as int
- // We know that it's a known type, as sizeOf(UnknownType) == 0
- } else if (QMetaType::typeFlags(type) & QMetaType::IsEnumeration) {
- type = QMetaType::Int;
- } else {
- if (argTypeNames.isEmpty())
- argTypeNames = m.parameterTypes();
- if (isNamedEnumerator(metaObject, argTypeNames.at(ii))) {
- type = QMetaType::Int;
- } else if (type == QMetaType::UnknownType){
- if (unknownTypeError)
- *unknownTypeError = argTypeNames.at(ii);
- return nullptr;
- }
-
- }
- args->arguments[ii + 1] = type;
- }
- args->argumentsValid = true;
- return static_cast<A *>(rv->arguments())->arguments;
-
- } else {
- QMetaMethod m = _m.asT2()->method(index);
- return methodParameterTypes(m, argStorage, unknownTypeError);
-
- }
-}
-
-int *QQmlMetaObject::methodParameterTypes(const QMetaMethod &m, ArgTypeStorage *argStorage,
- QByteArray *unknownTypeError) const
-{
- Q_ASSERT(argStorage);
-
- int argc = m.parameterCount();
- argStorage->resize(argc + 1);
- argStorage->operator[](0) = argc;
- QList<QByteArray> argTypeNames; // Only loaded if needed
-
- for (int ii = 0; ii < argc; ++ii) {
- int type = m.parameterType(ii);
- if (QMetaType::sizeOf(type) > int(sizeof(int))) {
- // Cannot be passed as int
- // We know that it's a known type, as sizeOf(UnknownType) == 0
- } else if (QMetaType::typeFlags(type) & QMetaType::IsEnumeration) {
- type = QMetaType::Int;
- } else {
- if (argTypeNames.isEmpty())
- argTypeNames = m.parameterTypes();
- if (isNamedEnumerator(_m.asT2(), argTypeNames.at(ii))) {
- type = QMetaType::Int;
- } else if (type == QMetaType::UnknownType) {
- if (unknownTypeError)
- *unknownTypeError = argTypeNames.at(ii);
- return nullptr;
- }
- }
- argStorage->operator[](ii + 1) = type;
- }
-
- return argStorage->data();
+ type = _m->method(data.coreIndex()).returnMetaType();
+ }
+ if (type.flags().testFlag(QMetaType::IsEnumeration))
+ type = type.underlyingType();
+ if (type.isValid())
+ return type;
+ else if (unknownTypeError)
+ *unknownTypeError = _m->method(data.coreIndex()).typeName();
+ return QMetaType();
}
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlmetaobject_p.h b/src/qml/qml/qqmlmetaobject_p.h
index 65d6361b90..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<int, 9> ArgTypeStorage;
+ template<qsizetype Prealloc>
+ using ArgTypeStorage = QVarLengthArray<QMetaType, Prealloc>;
- inline QQmlMetaObject();
- inline QQmlMetaObject(QObject *);
+ 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 &);
@@ -87,39 +50,131 @@ public:
inline const char *className() const;
inline int propertyCount() const;
- inline bool hasMetaObject() const;
inline const QMetaObject *metaObject() const;
- QQmlPropertyCache *propertyCache(QQmlEnginePrivate *) 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.
+ */
+ 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.
+ */
+ template<typename ArgTypeStorage>
+ bool constructorParameterTypes(
+ int index, ArgTypeStorage *dummy, QByteArray *unknownTypeError) const
+ {
+ QMetaMethod m = _m->constructor(index);
+ return methodParameterTypes(m, dummy, unknownTypeError);
+ }
- int methodReturnType(const QQmlPropertyData &data, QByteArray *unknownTypeError) const;
- int *methodParameterTypes(int index, ArgTypeStorage *argStorage,
- QByteArray *unknownTypeError) const;
- 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:
- QBiPointer<QQmlPropertyCache, const QMetaObject> _m;
- int *methodParameterTypes(const QMetaMethod &method, ArgTypeStorage *argStorage,
- QByteArray *unknownTypeError) const;
+ 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;
+ }
-};
-QQmlMetaObject::QQmlMetaObject()
-{
-}
+ const QMetaObject *_m = nullptr;
+
+};
-QQmlMetaObject::QQmlMetaObject(QObject *o)
+QQmlMetaObject::QQmlMetaObject(const QObject *o)
{
- if (o) {
- QQmlData *ddata = QQmlData::get(o, false);
- if (ddata && ddata->propertyCache) _m = ddata->propertyCache;
- else _m = o->metaObject();
- }
+ if (o)
+ _m = o->metaObject();
}
QQmlMetaObject::QQmlMetaObject(const QMetaObject *m)
@@ -127,9 +182,10 @@ QQmlMetaObject::QQmlMetaObject(const QMetaObject *m)
{
}
-QQmlMetaObject::QQmlMetaObject(QQmlPropertyCache *m)
- : _m(m)
+QQmlMetaObject::QQmlMetaObject(const QQmlPropertyCache::ConstPtr &m)
{
+ if (m)
+ _m = m->createMetaObject();
}
QQmlMetaObject::QQmlMetaObject(const QQmlMetaObject &o)
@@ -145,41 +201,26 @@ QQmlMetaObject &QQmlMetaObject::operator=(const QQmlMetaObject &o)
bool QQmlMetaObject::isNull() const
{
- return _m.isNull();
+ return !_m;
}
const char *QQmlMetaObject::className() const
{
- if (_m.isNull()) {
+ if (!_m)
return nullptr;
- } else if (_m.isT1()) {
- return _m.asT1()->className();
- } else {
- return _m.asT2()->className();
- }
+ return metaObject()->className();
}
int QQmlMetaObject::propertyCount() const
{
- if (_m.isNull()) {
+ if (!_m)
return 0;
- } else if (_m.isT1()) {
- return _m.asT1()->propertyCount();
- } else {
- return _m.asT2()->propertyCount();
- }
-}
-
-bool QQmlMetaObject::hasMetaObject() const
-{
- return _m.isT2() || (!_m.isNull() && _m.asT1()->metaObject());
+ return metaObject()->propertyCount();
}
const QMetaObject *QQmlMetaObject::metaObject() const
{
- if (_m.isNull()) return nullptr;
- if (_m.isT1()) return _m.asT1()->createMetaObject();
- else return _m.asT2();
+ return _m;
}
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlmetatype.cpp b/src/qml/qml/qqmlmetatype.cpp
index c21247bb95..1175bde3db 100644
--- a/src/qml/qml/qqmlmetatype.cpp
+++ b/src/qml/qml/qqmlmetatype.cpp
@@ -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
#include "qqmlmetatype_p.h"
+#include <private/qqmlextensionplugin_p.h>
#include <private/qqmlmetatypedata_p.h>
-#include <private/qqmltypemodule_p_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>
#include <QtCore/qcoreapplication.h>
@@ -51,6 +17,7 @@
#include <QtCore/qloggingcategory.h>
Q_DECLARE_LOGGING_CATEGORY(DBG_DISK_CACHE)
+Q_LOGGING_CATEGORY(lcTypeRegistration, "qt.qml.typeregistration")
QT_BEGIN_NAMESPACE
@@ -62,6 +29,12 @@ struct LockedData : private QQmlMetaTypeData
Q_GLOBAL_STATIC(LockedData, metaTypeData)
Q_GLOBAL_STATIC(QRecursiveMutex, metaTypeDataLock)
+struct ModuleUri : public QString
+{
+ ModuleUri(const QString &string) : QString(string) {}
+ ModuleUri(const std::unique_ptr<QQmlTypeModule> &module) : QString(module->module()) {}
+};
+
class QQmlMetaTypeDataPtr
{
Q_DISABLE_COPY_MOVE(QQmlMetaTypeDataPtr)
@@ -80,7 +53,7 @@ public:
bool isValid() const { return data != nullptr; }
private:
- QMutexLocker locker;
+ QMutexLocker<QRecursiveMutex> locker;
LockedData *data = nullptr;
};
@@ -88,45 +61,35 @@ 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 = true;
- d->version_maj = 0;
- d->version_min = 0;
+ 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);
d->setName(QString::fromUtf8(type.uri), elementName);
- d->version_maj = type.versionMajor;
- d->version_min = type.versionMinor;
-
- if (type.qobjectApi || (type.version >= 3 && type.generalizedQobjectApi)) {
- if (type.version >= 1) // static metaobject added in version 1
- d->baseMetaObject = type.instanceMetaObject;
- if (type.version >= 2) // typeId added in version 2
- d->typeId = type.typeId;
- if (type.version >= 2) // revisions added in version 2
- d->revision = type.revision;
- }
+ d->version = type.version;
- d->extraData.sd->singletonInstanceInfo = new QQmlType::SingletonInstanceInfo;
- d->extraData.sd->singletonInstanceInfo->scriptCallback = type.scriptApi;
- if (type.version >= 3) {
- d->extraData.sd->singletonInstanceInfo->qobjectCallback = type.generalizedQobjectApi;
- } else {
- d->extraData.sd->singletonInstanceInfo->qobjectCallback = type.qobjectApi;
+ if (type.qObjectApi) {
+ d->baseMetaObject = type.instanceMetaObject;
+ d->typeId = type.typeId;
+ d->revision = type.revision;
}
- d->extraData.sd->singletonInstanceInfo->typeName = QString::fromUtf8(type.typeName);
- d->extraData.sd->singletonInstanceInfo->instanceMetaObject
- = ((type.qobjectApi || (type.version >= 3 && type.generalizedQobjectApi) ) && type.version >= 1) ? type.instanceMetaObject : nullptr;
+
+ d->extraData.singletonTypeData->singletonInstanceInfo = siinfo;
+ d->extraData.singletonTypeData->extFunc = type.extensionObjectCreate;
+ d->extraData.singletonTypeData->extMetaObject = type.extensionMetaObject;
return d;
}
@@ -138,72 +101,111 @@ static QQmlTypePrivate *createQQmlType(QQmlMetaTypeData *data, const QString &el
data->registerType(d);
d->setName(QString::fromUtf8(type.uri), elementName);
- d->version_maj = type.versionMajor;
- d->version_min = type.versionMinor;
- if (type.version >= 1) // revisions added in version 1
- d->revision = type.revision;
+ d->version = type.version;
+ d->revision = type.revision;
d->typeId = type.typeId;
d->listId = type.listId;
- d->extraData.cd->allocationSize = type.objectSize;
- d->extraData.cd->newFunc = type.create;
- d->extraData.cd->noCreationReason = type.noCreationReason;
+ 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_maj = type.versionMajor;
- d->version_min = type.versionMinor;
-
- d->extraData.fd->url = QQmlTypeLoader::normalize(type.url);
+ d->version = type.version;
+ 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_maj = type.versionMajor;
- d->version_min = type.versionMinor;
+ 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) {
@@ -217,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);
@@ -267,21 +270,32 @@ void QQmlMetaType::clone(QMetaObjectBuilder &builder, const QMetaObject *mo,
}
}
-void QQmlMetaType::qmlInsertModuleRegistration(const QString &uri, int majorVersion,
- void (*registerFunction)())
+void QQmlMetaType::qmlInsertModuleRegistration(const QString &uri, void (*registerFunction)())
{
- const QQmlMetaTypeData::VersionedUri versionedUri(uri, majorVersion);
QQmlMetaTypeDataPtr data;
- if (data->moduleTypeRegistrationFunctions.contains(versionedUri))
- qFatal("Canot add multiple registrations for %s %d", qPrintable(uri), majorVersion);
+ if (data->moduleTypeRegistrationFunctions.contains(uri))
+ qFatal("Cannot add multiple registrations for %s", qPrintable(uri));
else
- data->moduleTypeRegistrationFunctions.insert(versionedUri, registerFunction);
+ data->moduleTypeRegistrationFunctions.insert(uri, registerFunction);
}
-void QQmlMetaType::qmlRegisterModuleTypes(const QString &uri, int majorVersion)
+void QQmlMetaType::qmlRemoveModuleRegistration(const QString &uri)
{
QQmlMetaTypeDataPtr data;
- data->registerModuleTypes(QQmlMetaTypeData::VersionedUri(uri, majorVersion));
+
+ if (!data.isValid())
+ return; // shutdown/deletion race. Not a problem.
+
+ if (!data->moduleTypeRegistrationFunctions.contains(uri))
+ qFatal("Cannot remove multiple registrations for %s", qPrintable(uri));
+ else
+ data->moduleTypeRegistrationFunctions.remove(uri);
+}
+
+bool QQmlMetaType::qmlRegisterModuleTypes(const QString &uri)
+{
+ QQmlMetaTypeDataPtr data;
+ return data->registerModuleTypes(uri);
}
void QQmlMetaType::clearTypeRegistrations()
@@ -289,9 +303,7 @@ void QQmlMetaType::clearTypeRegistrations()
//Only cleans global static, assumed no running engine
QQmlMetaTypeDataPtr data;
- for (QQmlMetaTypeData::TypeModules::const_iterator i = data->uriToModule.constBegin(), cend = data->uriToModule.constEnd(); i != cend; ++i)
- delete *i;
-
+ data->uriToModule.clear();
data->types.clear();
data->idToType.clear();
data->nameToType.clear();
@@ -299,17 +311,33 @@ void QQmlMetaType::clearTypeRegistrations()
data->typePropertyCaches.clear();
data->urlToNonFileImportType.clear();
data->metaObjectToType.clear();
- data->uriToModule.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 &autoparent)
+int QQmlMetaType::registerAutoParentFunction(const QQmlPrivate::RegisterAutoParent &function)
{
+ if (function.structVersion > 1)
+ qFatal("qmlRegisterType(): Cannot mix incompatible QML versions.");
+
QQmlMetaTypeDataPtr data;
- data->parentFunctions.append(autoparent.function);
+ data->parentFunctions.append(function.function);
- return data->parentFunctions.count() - 1;
+ return data->parentFunctions.size() - 1;
}
void QQmlMetaType::unregisterAutoParentFunction(const QQmlPrivate::AutoParentFunction &function)
@@ -320,30 +348,23 @@ void QQmlMetaType::unregisterAutoParentFunction(const QQmlPrivate::AutoParentFun
QQmlType QQmlMetaType::registerInterface(const QQmlPrivate::RegisterInterface &type)
{
- if (type.version > 0)
+ if (type.structVersion > 1)
qFatal("qmlRegisterType(): Cannot mix incompatible QML versions.");
QQmlMetaTypeDataPtr data;
QQmlTypePrivate *priv = createQQmlType(data, type);
Q_ASSERT(priv);
- data->idToType.insert(priv->typeId, priv);
- data->idToType.insert(priv->listId, priv);
- // XXX No insertMulti, so no multi-version interfaces?
- if (!priv->elementName.isEmpty())
- data->nameToType.insert(priv->elementName, priv);
- if (data->interfaces.size() <= type.typeId)
- data->interfaces.resize(type.typeId + 16);
- if (data->lists.size() <= type.listId)
- data->lists.resize(type.listId + 16);
- data->interfaces.setBit(type.typeId, true);
- data->lists.setBit(type.listId, true);
+ data->idToType.insert(priv->typeId.id(), priv);
+ data->idToType.insert(priv->listId.id(), priv);
+
+ data->interfaces.insert(type.typeId.id());
return QQmlType(priv);
}
-QString registrationTypeString(QQmlType::RegistrationType typeType)
+static QString registrationTypeString(QQmlType::RegistrationType typeType)
{
QString typeStr;
if (typeType == QQmlType::CppType)
@@ -352,27 +373,43 @@ QString registrationTypeString(QQmlType::RegistrationType typeType)
typeStr = QStringLiteral("singleton type");
else if (typeType == QQmlType::CompositeSingletonType)
typeStr = QStringLiteral("composite singleton type");
+ else if (typeType == QQmlType::SequentialContainerType)
+ typeStr = QStringLiteral("sequential container type");
else
typeStr = QStringLiteral("type");
return typeStr;
}
// NOTE: caller must hold a QMutexLocker on "data"
-bool checkRegistration(QQmlType::RegistrationType typeType, QQmlMetaTypeData *data,
- const char *uri, const QString &typeName, int majorVersion)
+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()) {
+ 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;
}
- int typeNameLen = typeName.length();
+ if (typeName.at(0).isUpper()
+ && (flags & (QMetaType::IsGadget | QMetaType::PointerToGadget))) {
+ qCWarning(lcTypeRegistration).noquote()
+ << QCoreApplication::translate(
+ "qmlRegisterType",
+ "Invalid QML %1 name \"%2\"; "
+ "value type names should begin with a lowercase letter")
+ .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.size();
for (int ii = 0; ii < typeNameLen; ++ii) {
- if (!(typeName.at(ii).isLetterOrNumber() || typeName.at(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;
}
}
@@ -380,16 +417,15 @@ bool checkRegistration(QQmlType::RegistrationType typeType, QQmlMetaTypeData *da
if (uri && !typeName.isEmpty()) {
QString nameSpace = QString::fromUtf8(uri);
- QQmlMetaTypeData::VersionedUri versionedUri;
- versionedUri.uri = nameSpace;
- versionedUri.majorVersion = majorVersion;
- if (QQmlTypeModule* qqtm = data->uriToModule.value(versionedUri, 0)){
- if (qqtm->isLocked()){
- 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).arg(majorVersion));
- return false;
- }
+ QQmlTypeModule *qqtm = data->findTypeModule(nameSpace, version);
+ 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), typeName, nameSpace)
+ .arg(version.majorVersion()));
+ return false;
}
}
@@ -397,46 +433,40 @@ bool checkRegistration(QQmlType::RegistrationType typeType, QQmlMetaTypeData *da
}
// NOTE: caller must hold a QMutexLocker on "data"
-QQmlTypeModule *getTypeModule(const QHashedString &uri, int majorVersion, QQmlMetaTypeData *data)
+static QQmlTypeModule *getTypeModule(
+ const QHashedString &uri, QTypeRevision version, QQmlMetaTypeData *data)
{
- QQmlMetaTypeData::VersionedUri versionedUri(uri, majorVersion);
- QQmlTypeModule *module = data->uriToModule.value(versionedUri);
- if (!module) {
- module = new QQmlTypeModule(versionedUri.uri, versionedUri.majorVersion);
- data->uriToModule.insert(versionedUri, module);
- }
- return module;
+ if (QQmlTypeModule *module = data->findTypeModule(uri, version))
+ return module;
+ return data->addTypeModule(std::make_unique<QQmlTypeModule>(uri, version.majorVersion()));
}
// NOTE: caller must hold a QMutexLocker on "data"
-void addTypeToData(QQmlTypePrivate *type, QQmlMetaTypeData *data)
+static void addTypeToData(QQmlTypePrivate *type, QQmlMetaTypeData *data)
{
Q_ASSERT(type);
if (!type->elementName.isEmpty())
- data->nameToType.insertMulti(type->elementName, type);
+ data->nameToType.insert(type->elementName, type);
if (type->baseMetaObject)
- data->metaObjectToType.insertMulti(type->baseMetaObject, type);
+ data->metaObjectToType.insert(type->baseMetaObject, type);
- if (type->typeId) {
- data->idToType.insert(type->typeId, type);
- if (data->objects.size() <= type->typeId)
- data->objects.resize(type->typeId + 16);
- data->objects.setBit(type->typeId, true);
- }
+ 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) {
- if (data->lists.size() <= type->listId)
- data->lists.resize(type->listId + 16);
- data->lists.setBit(type->listId, true);
- data->idToType.insert(type->listId, type);
+ if (type->listId.flags().testFlag(QMetaType::IsQmlList))
+ data->idToType.insert(type->listId.id(), type);
}
if (!type->module.isEmpty()) {
const QHashedString &mod = type->module;
- QQmlTypeModule *module = getTypeModule(mod, type->version_maj, data);
+ QQmlTypeModule *module = getTypeModule(mod, type->version, data);
Q_ASSERT(module);
module->add(type);
}
@@ -444,38 +474,52 @@ void addTypeToData(QQmlTypePrivate *type, QQmlMetaTypeData *data)
QQmlType QQmlMetaType::registerType(const QQmlPrivate::RegisterType &type)
{
+ if (type.structVersion > int(QQmlPrivate::RegisterType::CurrentVersion))
+ qFatal("qmlRegisterType(): Cannot mix incompatible QML versions.");
+
QQmlMetaTypeDataPtr data;
QString elementName = QString::fromUtf8(type.elementName);
- if (!checkRegistration(QQmlType::CppType, data, type.uri, elementName, type.versionMajor))
+ if (!checkRegistration(QQmlType::CppType, data, type.uri, elementName, type.version,
+ QMetaType(type.typeId).flags())) {
return QQmlType();
+ }
QQmlTypePrivate *priv = createQQmlType(data, elementName, type);
-
addTypeToData(priv, data);
- if (!type.typeId)
- data->idToType.insert(priv->typeId, priv);
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 > 1)
+ qFatal("qmlRegisterType(): Cannot mix incompatible QML versions.");
+
QQmlMetaTypeDataPtr data;
QString typeName = QString::fromUtf8(type.typeName);
- if (!checkRegistration(QQmlType::SingletonType, data, type.uri, typeName, type.versionMajor))
+ if (!checkRegistration(QQmlType::SingletonType, data, type.uri, typeName, type.version,
+ QMetaType(type.typeId).flags())) {
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 > 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.
QQmlMetaTypeDataPtr data;
@@ -484,21 +528,24 @@ QQmlType QQmlMetaType::registerCompositeSingletonType(const QQmlPrivate::Registe
if (*(type.uri) == '\0')
fileImport = true;
if (!checkRegistration(QQmlType::CompositeSingletonType, data, fileImport ? nullptr : type.uri,
- typeName, type.versionMajor)) {
+ typeName, type.version, {})) {
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->insertMulti(QQmlTypeLoader::normalize(type.url), priv);
+ files->insert(siinfo->url, priv);
return QQmlType(priv);
}
QQmlType QQmlMetaType::registerCompositeType(const QQmlPrivate::RegisterCompositeType &type)
{
+ 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.
QQmlMetaTypeDataPtr data;
@@ -506,61 +553,209 @@ QQmlType QQmlMetaType::registerCompositeType(const QQmlPrivate::RegisterComposit
bool fileImport = false;
if (*(type.uri) == '\0')
fileImport = true;
- if (!checkRegistration(QQmlType::CompositeType, data, fileImport?nullptr:type.uri, typeName, type.versionMajor))
+ if (!checkRegistration(QQmlType::CompositeType, data, fileImport?nullptr:type.uri, typeName,
+ type.version, {})) {
return QQmlType();
+ }
QQmlTypePrivate *priv = createQQmlType(data, typeName, type);
addTypeToData(priv, data);
QQmlMetaTypeData::Files *files = fileImport ? &(data->urlToType) : &(data->urlToNonFileImportType);
- files->insertMulti(QQmlTypeLoader::normalize(type.url), priv);
+ files->insert(QQmlTypeLoader::normalize(type.url), priv);
return QQmlType(priv);
}
-void QQmlMetaType::registerInternalCompositeType(QV4::ExecutableCompilationUnit *compilationUnit)
+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;
+};
+
+
+static QQmlType createTypeForUrl(
+ QQmlMetaTypeData *data, const QUrl &url, const QHashedStringRef &qualifiedType,
+ QQmlMetaType::CompositeTypeLookupMode mode, QList<QQmlError> *errors, QTypeRevision version)
{
- QByteArray name = compilationUnit->rootPropertyCache()->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.
- QByteArray ptr = name + '*';
- QByteArray lst = "QQmlListProperty<" + name + '>';
+ auto *priv = new QQmlTypePrivate(registrationType);
+ addQQmlMetaTypeInterfaces(priv, QQmlPropertyCacheCreatorBase::createClassNameTypeByUrl(url));
+
+ 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;
+ }
- int ptr_type = QMetaType::registerNormalizedType(ptr,
- QtMetaTypePrivate::QMetaTypeFunctionHelper<QObject*>::Destruct,
- QtMetaTypePrivate::QMetaTypeFunctionHelper<QObject*>::Construct,
- sizeof(QObject*),
- static_cast<QFlags<QMetaType::TypeFlag> >(QtPrivate::QMetaTypeTypeFlags<QObject*>::Flags),
- nullptr);
- int lst_type = QMetaType::registerNormalizedType(lst,
- QtMetaTypePrivate::QMetaTypeFunctionHelper<QQmlListProperty<QObject> >::Destruct,
- QtMetaTypePrivate::QMetaTypeFunctionHelper<QQmlListProperty<QObject> >::Construct,
- sizeof(QQmlListProperty<QObject>),
- static_cast<QFlags<QMetaType::TypeFlag> >(QtPrivate::QMetaTypeTypeFlags<QQmlListProperty<QObject> >::Flags),
- static_cast<QMetaObject*>(nullptr));
+ data->registerType(priv);
+ addTypeToData(priv, data);
+ return QQmlType(priv);
+ }
- compilationUnit->metaTypeId = ptr_type;
- compilationUnit->listMetaTypeId = lst_type;
+ // 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, ptr_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(QV4::ExecutableCompilationUnit *compilationUnit)
+static QQmlType doRegisterInlineComponentType(QQmlMetaTypeData *data, const QUrl &url)
{
- int ptr_type = compilationUnit->metaTypeId;
- int lst_type = compilationUnit->listMetaTypeId;
+ 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;
- data->qmlLists.remove(lst_type);
- QMetaType::unregisterType(ptr_type);
- QMetaType::unregisterType(lst_type);
+ // 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);
+ }
+
+ QMetaType::unregisterMetaType(metaType);
+ QMetaType::unregisterMetaType(listMetaType);
+ delete static_cast<const QQmlMetaTypeInterface *>(metaType.iface());
+ delete static_cast<const QQmlListMetaTypeInterface *>(listMetaType.iface());
}
int QQmlMetaType::registerUnitCacheHook(
const QQmlPrivate::RegisterQmlUnitCacheHook &hookRegistration)
{
- if (hookRegistration.version > 0)
+ if (hookRegistration.structVersion > 1)
qFatal("qmlRegisterType(): Cannot mix incompatible QML versions.");
QQmlMetaTypeDataPtr data;
@@ -568,40 +763,135 @@ int QQmlMetaType::registerUnitCacheHook(
return 0;
}
-bool QQmlMetaType::protectModule(const QString &uri, int majVersion)
+QQmlType QQmlMetaType::registerSequentialContainer(
+ const QQmlPrivate::RegisterSequentialContainer &container)
{
+ if (container.structVersion > 1)
+ qFatal("qmlRegisterSequenceContainer(): Cannot mix incompatible QML versions.");
+
QQmlMetaTypeDataPtr data;
- QQmlMetaTypeData::VersionedUri versionedUri;
- versionedUri.uri = uri;
- versionedUri.majorVersion = majVersion;
+ if (!checkRegistration(QQmlType::SequentialContainerType, data, container.uri, QString(),
+ container.version, {})) {
+ return QQmlType();
+ }
+
+ QQmlTypePrivate *priv = new QQmlTypePrivate(QQmlType::SequentialContainerType);
- if (QQmlTypeModule* qqtm = data->uriToModule.value(versionedUri, 0)) {
- qqtm->lock();
- return true;
+ data->registerType(priv);
+ priv->setName(QString::fromUtf8(container.uri), QString());
+ priv->version = container.version;
+ priv->revision = container.revision;
+ priv->typeId = container.metaSequence.valueMetaType();
+ priv->listId = container.typeId;
+ priv->extraData.sequentialContainerTypeData = container.metaSequence;
+
+ addTypeToData(priv, data);
+
+ return QQmlType(priv);
+}
+
+void QQmlMetaType::unregisterSequentialContainer(int id)
+{
+ unregisterType(id);
+}
+
+bool QQmlMetaType::protectModule(const QString &uri, QTypeRevision version,
+ bool weakProtectAllVersions)
+{
+ QQmlMetaTypeDataPtr data;
+ if (version.hasMajorVersion()) {
+ if (QQmlTypeModule *module = data->findTypeModule(uri, version)) {
+ if (!weakProtectAllVersions) {
+ module->setLockLevel(QQmlTypeModule::LockLevel::Strong);
+ return true;
+ }
+ } else {
+ return false;
+ }
}
- return false;
+
+ const auto range = std::equal_range(
+ data->uriToModule.begin(), data->uriToModule.end(), uri,
+ std::less<ModuleUri>());
+
+ for (auto it = range.first; it != range.second; ++it)
+ (*it)->setLockLevel(QQmlTypeModule::LockLevel::Weak);
+
+ return range.first != range.second;
+}
+
+void QQmlMetaType::registerModuleImport(const QString &uri, QTypeRevision moduleVersion,
+ const QQmlDirParser::Import &import)
+{
+ QQmlMetaTypeDataPtr data;
+
+ data->moduleImports.insert(QQmlMetaTypeData::VersionedUri(uri, moduleVersion), import);
}
-void QQmlMetaType::registerModule(const char *uri, int versionMajor, int versionMinor)
+void QQmlMetaType::unregisterModuleImport(const QString &uri, QTypeRevision moduleVersion,
+ const QQmlDirParser::Import &import)
{
QQmlMetaTypeDataPtr data;
+ data->moduleImports.remove(QQmlMetaTypeData::VersionedUri(uri, moduleVersion), import);
+}
- QQmlTypeModule *module = getTypeModule(QString::fromUtf8(uri), versionMajor, data);
+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));
+
+ 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();
+ auto it = unrevisioned.first;
+ if (it == begin)
+ return result;
+
+ const QQmlMetaTypeData::VersionedUri latestVersion = (--it).key();
+ if (latestVersion.uri != uri)
+ return result;
+
+ do {
+ result += *it;
+ } while (it != begin && (--it).key() == latestVersion);
+
+ return result;
+}
+
+void QQmlMetaType::registerModule(const char *uri, QTypeRevision version)
+{
+ QQmlMetaTypeDataPtr data;
+
+ QQmlTypeModule *module = getTypeModule(QString::fromUtf8(uri), version, data);
Q_ASSERT(module);
- module->addMinorVersion(versionMinor);
+ if (version.hasMinorVersion())
+ module->addMinorVersion(version.minorVersion());
}
-int QQmlMetaType::typeId(const char *uri, int versionMajor, int versionMinor, const char *qmlName)
+int QQmlMetaType::typeId(const char *uri, QTypeRevision version, const char *qmlName)
{
QQmlMetaTypeDataPtr data;
- QQmlTypeModule *module = getTypeModule(QString::fromUtf8(uri), versionMajor, data);
+ QQmlTypeModule *module = getTypeModule(QString::fromUtf8(uri), version, data);
if (!module)
return -1;
- QQmlType type = module->type(QHashedStringRef(QString::fromUtf8(qmlName)), versionMinor);
+ QQmlType type = module->type(QHashedStringRef(QString::fromUtf8(qmlName)), version);
if (!type.isValid())
return -1;
@@ -615,40 +905,21 @@ void QQmlMetaType::registerUndeletableType(const QQmlType &dtype)
}
static bool namespaceContainsRegistrations(const QQmlMetaTypeData *data, const QString &uri,
- int majorVersion)
+ QTypeRevision version)
{
// Has any type previously been installed to this namespace?
QHashedString nameSpace(uri);
for (const QQmlType &type : data->types) {
- if (type.module() == nameSpace && type.majorVersion() == majorVersion)
+ if (type.module() == nameSpace && type.version().majorVersion() == version.majorVersion())
return true;
}
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;
-};
-
-
-bool QQmlMetaType::registerPluginTypes(QObject *instance, const QString &basePath,
- const QString &uri, const QString &typeNamespace, int vmaj,
- QList<QQmlError> *errors)
+QQmlMetaType::RegistrationResult QQmlMetaType::registerPluginTypes(
+ QObject *instance, const QString &basePath, const QString &uri,
+ const QString &typeNamespace, QTypeRevision version, QList<QQmlError> *errors)
{
if (!typeNamespace.isEmpty() && typeNamespace != uri) {
// This is an 'identified' module
@@ -657,10 +928,10 @@ bool QQmlMetaType::registerPluginTypes(QObject *instance, const QString &basePat
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 false;
+ return RegistrationResult::Failure;
}
QStringList failures;
@@ -669,7 +940,7 @@ bool QQmlMetaType::registerPluginTypes(QObject *instance, const QString &basePat
QQmlMetaTypeRegistrationFailureRecorder failureRecorder(data, &failures);
if (!typeNamespace.isEmpty()) {
// This is an 'identified' module
- if (namespaceContainsRegistrations(data, typeNamespace, vmaj)) {
+ if (namespaceContainsRegistrations(data, typeNamespace, version)) {
// Other modules have already installed to this namespace
if (errors) {
QQmlError error;
@@ -678,7 +949,7 @@ bool QQmlMetaType::registerPluginTypes(QObject *instance, const QString &basePat
.arg(typeNamespace));
errors->prepend(error);
}
- return false;
+ return RegistrationResult::Failure;
}
} else {
// This is not an identified module - provide a warning
@@ -687,7 +958,7 @@ bool QQmlMetaType::registerPluginTypes(QObject *instance, const QString &basePat
"it cannot be protected from external registrations.").arg(uri));
}
- if (!qobject_cast<QQmlEngineExtensionInterface *>(instance)) {
+ if (instance && !qobject_cast<QQmlEngineExtensionInterface *>(instance)) {
QQmlTypesExtensionInterface *iface = qobject_cast<QQmlTypesExtensionInterface *>(instance);
if (!iface) {
if (errors) {
@@ -697,35 +968,40 @@ bool QQmlMetaType::registerPluginTypes(QObject *instance, const QString &basePat
"QQmlEngineExtensionInterface").arg(typeNamespace));
errors->prepend(error);
}
- return false;
+ 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();
iface->registerTypes(moduleId);
}
- data->registerModuleTypes(QQmlMetaTypeData::VersionedUri(uri, vmaj));
+ if (failures.isEmpty() && !data->registerModuleTypes(uri))
+ return RegistrationResult::NoRegistrationFunction;
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);
}
}
- return false;
+ return RegistrationResult::Failure;
}
}
- return true;
+ return RegistrationResult::Success;
}
/*
@@ -741,8 +1017,8 @@ bool QQmlMetaType::registerPluginTypes(QObject *instance, const QString &basePat
*/
QQmlType QQmlMetaType::typeForUrl(const QString &urlString,
const QHashedStringRef &qualifiedType,
- bool isCompositeSingleton, QList<QQmlError> *errors,
- int majorVersion, int minorVersion)
+ CompositeTypeLookupMode mode, QList<QQmlError> *errors,
+ QTypeRevision version)
{
// ### unfortunate (costly) conversion
const QUrl url = QQmlTypeLoader::normalize(QUrl(urlString));
@@ -759,128 +1035,80 @@ 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, majorVersion)) {
- auto *priv = new QQmlTypePrivate(registrationType);
- priv->setName(QString(), typeName);
- priv->version_maj = majorVersion;
- priv->version_min = minorVersion;
-
- 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.insertMulti(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('\n'));
- errors->prepend(error);
- } else {
- qWarning("%s", failures.join('\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;
}
/*
- Returns true if a module \a uri of any version is installed.
+ Returns the latest version of \a uri installed, or an in valid QTypeRevision().
*/
-bool QQmlMetaType::isAnyModule(const QString &uri)
+QTypeRevision QQmlMetaType::latestModuleVersion(const QString &uri)
{
QQmlMetaTypeDataPtr data;
+ auto upper = std::upper_bound(data->uriToModule.begin(), data->uriToModule.end(), uri,
+ std::less<ModuleUri>());
+ if (upper == data->uriToModule.begin())
+ return QTypeRevision();
- for (QQmlMetaTypeData::TypeModules::ConstIterator iter = data->uriToModule.cbegin();
- iter != data->uriToModule.cend(); ++iter) {
- if ((*iter)->module() == uri)
- return true;
- }
-
- return false;
+ const auto module = (--upper)->get();
+ return (module->module() == uri)
+ ? QTypeRevision::fromVersion(module->majorVersion(), module->maximumMinorVersion())
+ : QTypeRevision();
}
/*
Returns true if a module \a uri of this version is installed and locked;
*/
-bool QQmlMetaType::isLockedModule(const QString &uri, int majVersion)
+bool QQmlMetaType::isStronglyLockedModule(const QString &uri, QTypeRevision version)
{
QQmlMetaTypeDataPtr data;
- QQmlMetaTypeData::VersionedUri versionedUri;
- versionedUri.uri = uri;
- versionedUri.majorVersion = majVersion;
- if (QQmlTypeModule* qqtm = data->uriToModule.value(versionedUri, 0))
- return qqtm->isLocked();
+ if (QQmlTypeModule* qqtm = data->findTypeModule(uri, version))
+ return qqtm->lockLevel() == QQmlTypeModule::LockLevel::Strong;
return false;
}
/*
- Returns true if any type or API has been registered for the given \a module with at least
- versionMajor.versionMinor, or if types have been registered for \a module with at most
- versionMajor.versionMinor.
-
- So if only 4.7 and 4.9 have been registered, 4.7,4.8, and 4.9 are valid, but not 4.6 nor 4.10.
+ Returns the best matching registered version for the given \a module. If \a version is
+ the does not have a major version, returns the latest registered version. Otherwise
+ chooses the same major version and checks if the minor version is within the range
+ of registered minor versions. If so, retuens the original version, otherwise returns
+ an invalid version. If \a version does not have a minor version, chooses the latest one.
*/
-bool QQmlMetaType::isModule(const QString &module, int versionMajor, int versionMinor)
+QTypeRevision QQmlMetaType::matchingModuleVersion(const QString &module, QTypeRevision version)
{
- Q_ASSERT(versionMajor >= 0 && versionMinor >= 0);
+ if (!version.hasMajorVersion())
+ return latestModuleVersion(module);
+
QQmlMetaTypeDataPtr data;
// first, check Types
- QQmlTypeModule *tm =
- data->uriToModule.value(QQmlMetaTypeData::VersionedUri(module, versionMajor));
- if (tm && tm->minimumMinorVersion() <= versionMinor && tm->maximumMinorVersion() >= versionMinor)
- return true;
+ if (QQmlTypeModule *tm = data->findTypeModule(module, version)) {
+ if (!version.hasMinorVersion())
+ return QTypeRevision::fromVersion(version.majorVersion(), tm->maximumMinorVersion());
- return false;
+ if (tm->minimumMinorVersion() <= version.minorVersion()
+ && tm->maximumMinorVersion() >= version.minorVersion()) {
+ return version;
+ }
+ }
+
+ return QTypeRevision();
}
-QQmlTypeModule *QQmlMetaType::typeModule(const QString &uri, int majorVersion)
+QQmlTypeModule *QQmlMetaType::typeModule(const QString &uri, QTypeRevision version)
{
QQmlMetaTypeDataPtr data;
- return data->uriToModule.value(QQmlMetaTypeData::VersionedUri(uri, majorVersion));
+
+ if (version.hasMajorVersion())
+ return data->findTypeModule(uri, version);
+
+ auto range = std::equal_range(data->uriToModule.begin(), data->uriToModule.end(),
+ uri, std::less<ModuleUri>());
+
+ return range.first == range.second ? nullptr : (--range.second)->get();
}
QList<QQmlPrivate::AutoParentFunction> QQmlMetaType::parentFunctions()
@@ -891,7 +1119,7 @@ QList<QQmlPrivate::AutoParentFunction> QQmlMetaType::parentFunctions()
QObject *QQmlMetaType::toQObject(const QVariant &v, bool *ok)
{
- if (!isQObject(v.userType())) {
+ if (!v.metaType().flags().testFlag(QMetaType::PointerToQObject)) {
if (ok) *ok = false;
return nullptr;
}
@@ -901,54 +1129,28 @@ QObject *QQmlMetaType::toQObject(const QVariant &v, bool *ok)
return *(QObject *const *)v.constData();
}
-bool QQmlMetaType::isQObject(int userType)
-{
- if (userType == QMetaType::QObjectStar)
- return true;
-
- QQmlMetaTypeDataPtr data;
- return userType >= 0 && userType < data->objects.size() && data->objects.testBit(userType);
-}
-
/*
Returns the item type for a list of type \a id.
*/
-int QQmlMetaType::listType(int id)
-{
- 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)
- return type->typeId;
- else
- return 0;
-}
-
-#if QT_DEPRECATED_SINCE(5, 14)
-int QQmlMetaType::attachedPropertiesFuncId(QQmlEnginePrivate *engine, const QMetaObject *mo)
-{
- QQmlMetaTypeDataPtr data;
-
- for (auto it = data->metaObjectToType.constFind(mo), end = data->metaObjectToType.constEnd();
- it != end && it.key() == mo; ++it) {
- const QQmlType type(it.value());
- if (type.attachedPropertiesFunction(engine))
- return type.attachedPropertiesId(engine);
+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();
}
- return -1;
-}
-
-QQmlAttachedPropertiesFunc QQmlMetaType::attachedPropertiesFuncById(QQmlEnginePrivate *engine, int id)
-{
- if (id < 0)
- return nullptr;
QQmlMetaTypeDataPtr data;
- return data->types.at(id).attachedPropertiesFunction(engine);
+ Q_ASSERT(data);
+ QQmlTypePrivate *type = data->idToType.value(metaType.id());
+
+ if (type && type->listId == metaType)
+ return type->typeId;
+ else
+ return QMetaType {};
}
-#endif
QQmlAttachedPropertiesFunc QQmlMetaType::attachedPropertiesFunc(QQmlEnginePrivate *engine,
const QMetaObject *mo)
@@ -1011,120 +1213,64 @@ QMetaMethod QQmlMetaType::defaultMethod(QObject *obj)
return defaultMethod(metaObject);
}
-QQmlMetaType::TypeCategory QQmlMetaType::typeCategory(int userType)
-{
- if (userType < 0)
- return Unknown;
- if (userType == QMetaType::QObjectStar)
- return Object;
-
- QQmlMetaTypeDataPtr data;
- if (data->qmlLists.contains(userType))
- return List;
- else if (userType < data->objects.size() && data->objects.testBit(userType))
- return Object;
- else if (userType < data->lists.size() && data->lists.testBit(userType))
- return List;
- else
- return Unknown;
-}
-
/*!
See qmlRegisterInterface() for information about when this will return true.
*/
-bool QQmlMetaType::isInterface(int userType)
+bool QQmlMetaType::isInterface(QMetaType type)
{
const QQmlMetaTypeDataPtr data;
- return userType >= 0 && userType < data->interfaces.size() && data->interfaces.testBit(userType);
+ return data->interfaces.contains(type.id());
}
-const char *QQmlMetaType::interfaceIId(int userType)
-{
-
- QQmlTypePrivate *typePrivate = nullptr;
- {
- QQmlMetaTypeDataPtr data;
- typePrivate = data->idToType.value(userType);
- }
-
- QQmlType type(typePrivate);
- if (type.isInterface() && type.typeId() == userType)
- return type.interfaceIId();
- else
- return nullptr;
-}
-
-bool QQmlMetaType::isList(int userType)
+const char *QQmlMetaType::interfaceIId(QMetaType metaType)
{
const QQmlMetaTypeDataPtr data;
- if (data->qmlLists.contains(userType))
- return true;
- return userType >= 0 && userType < data->lists.size() && data->lists.testBit(userType);
-}
-
-/*!
- 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);
+ const QQmlType type(data->idToType.value(metaType.id()));
+ return (type.isInterface() && type.typeId() == metaType) ? type.interfaceIId() : nullptr;
}
-/*!
- Return the custom string converter for \a type, previously installed through
- registerCustomStringConverter()
- */
-QQmlMetaType::StringConverter QQmlMetaType::customStringConverter(int type)
+bool QQmlMetaType::isList(QMetaType type)
{
- const QQmlMetaTypeDataPtr data;
- return data->stringConverters.value(type);
+ if (type.flags().testFlag(QMetaType::IsQmlList))
+ return true;
+ else
+ return false;
}
/*!
Returns the type (if any) of URI-qualified named \a qualifiedName and version specified
by \a version_major and \a version_minor.
*/
-QQmlType QQmlMetaType::qmlType(const QString &qualifiedName, int version_major, int version_minor)
+QQmlType QQmlMetaType::qmlType(const QString &qualifiedName, QTypeRevision version)
{
int slash = qualifiedName.indexOf(QLatin1Char('/'));
if (slash <= 0)
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_major, version_minor);
+ 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, int version_major, int version_minor)
+QQmlType QQmlMetaType::qmlType(const QHashedStringRef &name, const QHashedStringRef &module,
+ QTypeRevision version)
{
- Q_ASSERT(version_major >= 0 && version_minor >= 0);
const QQmlMetaTypeDataPtr data;
- QQmlMetaTypeData::Names::ConstIterator it = data->nameToType.constFind(name);
+ const QHashedString key(QString::fromRawData(name.constData(), name.length()), name.hash());
+ QQmlMetaTypeData::Names::ConstIterator it = data->nameToType.constFind(key);
while (it != data->nameToType.cend() && it.key() == name) {
QQmlType t(*it);
- // XXX version_major<0 just a kludge for QQmlPropertyPrivate::initProperty
- if (version_major < 0 || module.isEmpty() || t.availableInVersion(module, version_major,version_minor))
+ if (module.isEmpty() || t.availableInVersion(module, version))
return t;
++it;
}
@@ -1133,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)
{
@@ -1147,44 +1293,53 @@ QQmlType QQmlMetaType::qmlType(const QMetaObject *metaObject)
by \a version_major and \a version_minor in module specified by \a uri. Returns null if no
type is registered.
*/
-QQmlType QQmlMetaType::qmlType(const QMetaObject *metaObject, const QHashedStringRef &module, int version_major, int version_minor)
+QQmlType QQmlMetaType::qmlType(const QMetaObject *metaObject, const QHashedStringRef &module,
+ QTypeRevision version)
{
- Q_ASSERT(version_major >= 0 && version_minor >= 0);
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 (version_major < 0 || module.isEmpty() || t.availableInVersion(module, version_major,version_minor))
+ 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 == 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.
@@ -1205,16 +1360,149 @@ QQmlType QQmlMetaType::qmlType(const QUrl &unNormalizedUrl, bool includeNonFileI
return QQmlType();
}
-QQmlPropertyCache *QQmlMetaType::propertyCache(const QMetaObject *metaObject, int minorVersion)
+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
- return data->propertyCache(metaObject, minorVersion);
+ return data->propertyCache(metaObject, version);
}
-QQmlPropertyCache *QQmlMetaType::propertyCache(const QQmlType &type, int minorVersion)
+QQmlPropertyCache::ConstPtr QQmlMetaType::propertyCache(
+ const QQmlType &type, QTypeRevision version)
{
QQmlMetaTypeDataPtr data; // not const: the cache is created on demand
- return data->propertyCache(type, minorVersion);
+ 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)
@@ -1222,6 +1510,8 @@ 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);
@@ -1229,12 +1519,55 @@ void QQmlMetaType::unregisterType(int typeIndex)
removeQQmlTypePrivate(data->metaObjectToType, d);
for (auto & module : data->uriToModule)
module->remove(d);
- data->clearPropertyCachesForMinorVersion(typeIndex);
+ data->clearPropertyCachesForVersion(typeIndex);
data->types[typeIndex] = QQmlType();
data->undeletableTypes.remove(type);
}
}
+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;
@@ -1243,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);
@@ -1261,7 +1612,7 @@ void QQmlMetaType::freeUnusedTypesAndCaches()
for (auto &module : data->uriToModule)
module->remove(d);
- data->clearPropertyCachesForMinorVersion(d->index);
+ data->clearPropertyCachesForVersion(d->index);
*it = QQmlType();
} else {
++it;
@@ -1272,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;
@@ -1296,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);
@@ -1315,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;
@@ -1338,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);
@@ -1346,22 +1693,47 @@ QList<QQmlType> QQmlMetaType::qmlSingletonTypes()
return retn;
}
-const QV4::CompiledData::Unit *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->qmlData;
+ return unit;
}
}
@@ -1409,8 +1781,8 @@ QString QQmlMetaType::prettyTypeName(const QObject *object)
marker = typeName.indexOf(QLatin1String("_QML_"));
if (marker != -1) {
- typeName = typeName.leftRef(marker) + QLatin1Char('*');
- type = QQmlMetaType::qmlType(QMetaType::type(typeName.toLatin1()));
+ typeName = QStringView{typeName}.left(marker) + QLatin1Char('*');
+ type = QQmlMetaType::qmlType(QMetaType::fromName(typeName.toUtf8()));
if (type.isValid()) {
QString qmlTypeName = type.qmlTypeName();
const int lastSlash = qmlTypeName.lastIndexOf(QLatin1Char('/'));
@@ -1432,31 +1804,211 @@ QList<QQmlProxyMetaObject::ProxyData> QQmlMetaType::proxyData(const QMetaObject
QList<QQmlProxyMetaObject::ProxyData> metaObjects;
mo = mo->d.superdata;
- const QQmlMetaTypeDataPtr data;
-
- while (mo) {
- QQmlTypePrivate *t = data->metaObjectToType.value(mo);
- if (t) {
+ if (!mo)
+ return metaObjects;
+
+ auto createProxyMetaObject = [&](QQmlTypePrivate *This,
+ const QMetaObject *superdataBaseMetaObject,
+ const QMetaObject *extMetaObject,
+ QObject *(*extFunc)(QObject *)) {
+ if (!extMetaObject)
+ return;
+
+ QMetaObjectBuilder builder;
+ clone(builder, extMetaObject, superdataBaseMetaObject, baseMetaObject,
+ extFunc ? QQmlMetaType::CloneAll : QQmlMetaType::CloneEnumsOnly);
+ QMetaObject *mmo = builder.toMetaObject();
+ mmo->d.superdata = baseMetaObject;
+ if (!metaObjects.isEmpty())
+ metaObjects.constLast().metaObject->d.superdata = mmo;
+ else if (lastMetaObject)
+ lastMetaObject->d.superdata = mmo;
+ QQmlProxyMetaObject::ProxyData data = { mmo, extFunc, 0, 0 };
+ metaObjects << data;
+ registerMetaObjectForType(mmo, This);
+ };
+
+ 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) {
- if (t->extraData.cd->extFunc) {
- QMetaObjectBuilder builder;
- clone(builder, t->extraData.cd->extMetaObject, t->baseMetaObject, baseMetaObject);
- builder.setFlags(QMetaObjectBuilder::DynamicMetaObject);
- QMetaObject *mmo = builder.toMetaObject();
- mmo->d.superdata = baseMetaObject;
- if (!metaObjects.isEmpty())
- metaObjects.constLast().metaObject->d.superdata = mmo;
- else if (lastMetaObject)
- lastMetaObject->d.superdata = mmo;
- QQmlProxyMetaObject::ProxyData data = { mmo, t->extraData.cd->extFunc, 0, 0 };
- metaObjects << data;
- }
+ createProxyMetaObject(
+ t, t->baseMetaObject, t->extraData.cppTypeData->extMetaObject,
+ t->extraData.cppTypeData->extFunc);
+ } else if (t->regType == QQmlType::SingletonType) {
+ createProxyMetaObject(
+ t, t->baseMetaObject, t->extraData.singletonTypeData->extMetaObject,
+ t->extraData.singletonTypeData->extFunc);
}
}
- mo = mo->d.superdata;
- }
+ };
return metaObjects;
}
+static bool isInternalType(int idx)
+{
+ // Qt internal types
+ switch (idx) {
+ case QMetaType::UnknownType:
+ case QMetaType::QStringList:
+ case QMetaType::QObjectStar:
+ case QMetaType::VoidStar:
+ case QMetaType::Nullptr:
+ case QMetaType::QVariant:
+ case QMetaType::QLocale:
+ case QMetaType::QImage: // scarce type, keep as QVariant
+ case QMetaType::QPixmap: // scarce type, keep as QVariant
+ return true;
+ default:
+ return false;
+ }
+}
+
+bool QQmlMetaType::isValueType(QMetaType type)
+{
+ if (!type.isValid() || isInternalType(type.id()))
+ return false;
+
+ return valueType(type) != nullptr;
+}
+
+const QMetaObject *QQmlMetaType::metaObjectForValueType(QMetaType metaType)
+{
+ switch (metaType.id()) {
+ case QMetaType::QPoint:
+ return &QQmlPointValueType::staticMetaObject;
+ case QMetaType::QPointF:
+ return &QQmlPointFValueType::staticMetaObject;
+ case QMetaType::QSize:
+ return &QQmlSizeValueType::staticMetaObject;
+ case QMetaType::QSizeF:
+ return &QQmlSizeFValueType::staticMetaObject;
+ case QMetaType::QRect:
+ return &QQmlRectValueType::staticMetaObject;
+ case QMetaType::QRectF:
+ return &QQmlRectFValueType::staticMetaObject;
+#if QT_CONFIG(easingcurve)
+ case QMetaType::QEasingCurve:
+ return &QQmlEasingValueType::staticMetaObject;
+#endif
+ default:
+ break;
+ }
+
+ // It doesn't have to be a gadget for a QML type to exist, but we don't want to
+ // call QObject pointers value types. Explicitly registered types also override
+ // the implicit use of gadgets.
+ if (!(metaType.flags() & QMetaType::PointerToQObject)) {
+ 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.
+ if (metaType.flags() & QMetaType::IsGadget)
+ return metaType.metaObject();
+
+ return nullptr;
+}
+
+QQmlValueType *QQmlMetaType::valueType(QMetaType type)
+{
+ QQmlMetaTypeDataPtr data;
+
+ const auto it = data->metaTypeToValueType.constFind(type.id());
+ if (it != data->metaTypeToValueType.constEnd())
+ return *it;
+
+ 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 13ba4d809b..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,42 +15,117 @@
// We mean it.
//
-#include <private/qtqmlglobal_p.h>
-#include <private/qqmltype_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
class QQmlTypeModule;
class QRecursiveMutex;
class QQmlError;
+class QQmlValueType;
-namespace QV4 { class ExecutableCompilationUnit; }
+namespace QV4 {
+namespace CompiledData {
+struct CompilationUnit;
+}
+}
-class Q_QML_PRIVATE_EXPORT QQmlMetaType
+class Q_QML_EXPORT QQmlMetaType
{
+ 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 bool registerPluginTypes(QObject *instance, const QString &basePath,
- const QString &uri, const QString &typeNamespace, int vmaj,
- QList<QQmlError> *errors);
+ 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,
- int majorVersion = -1, int minorVersion = -1);
+ 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 registerInternalCompositeType(QV4::ExecutableCompilationUnit *compilationUnit);
- static void unregisterInternalCompositeType(QV4::ExecutableCompilationUnit *compilationUnit);
+ 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 weakProtectAllVersions = false);
- static void registerModule(const char *uri, int versionMajor, int versionMinor);
- static bool protectModule(const QString &uri, int majVersion);
+ static void registerModuleImport(const QString &uri, QTypeRevision version,
+ const QQmlDirParser::Import &import);
+ static void unregisterModuleImport(const QString &uri, QTypeRevision version,
+ const QQmlDirParser::Import &import);
+ static QList<QQmlDirParser::Import> moduleImports(const QString &uri, QTypeRevision version);
- static int typeId(const char *uri, int versionMajor, int versionMinor, const char *qmlName);
+ static int typeId(const char *uri, QTypeRevision version, const char *qmlName);
static void registerUndeletableType(const QQmlType &dtype);
@@ -95,20 +134,31 @@ public:
static QList<QQmlType> qmlSingletonTypes();
static QList<QQmlType> qmlAllTypes();
- enum class TypeIdCategory {
- MetaType,
- QmlType
- };
-
- static QQmlType qmlType(const QString &qualifiedName, int, int);
- static QQmlType qmlType(const QHashedStringRef &name, const QHashedStringRef &module, int, int);
+ 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, int version_major, int version_minor);
- static QQmlType qmlType(int typeId, TypeIdCategory category = TypeIdCategory::MetaType);
+ static QQmlType qmlType(const QMetaObject *metaObject, const QHashedStringRef &module, QTypeRevision version);
+ 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, int minorVersion = -1);
- static QQmlPropertyCache *propertyCache(const QQmlType &type, int minorVersion);
+ 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();
@@ -117,51 +167,37 @@ public:
static QMetaMethod defaultMethod(const QMetaObject *);
static QMetaMethod defaultMethod(QObject *);
- static bool isQObject(int);
static QObject *toQObject(const QVariant &, bool *ok = nullptr);
- static int listType(int);
-#if QT_DEPRECATED_SINCE(5, 14)
- static QT_DEPRECATED int attachedPropertiesFuncId(QQmlEnginePrivate *engine,
- const QMetaObject *);
- static QT_DEPRECATED QQmlAttachedPropertiesFunc attachedPropertiesFuncById(QQmlEnginePrivate *,
- int);
-#endif
+ static QMetaType listValueType(QMetaType type);
static QQmlAttachedPropertiesFunc attachedPropertiesFunc(QQmlEnginePrivate *,
const QMetaObject *);
+ static bool isInterface(QMetaType type);
+ static const char *interfaceIId(QMetaType type);
+ static bool isList(QMetaType type);
- enum TypeCategory { Unknown, Object, List };
- static TypeCategory typeCategory(int);
-
- 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 isAnyModule(const QString &uri);
- static bool isLockedModule(const QString &uri, int majorVersion);
- static bool isModule(const QString &module, int versionMajor, int versionMinor);
- static QQmlTypeModule *typeModule(const QString &uri, int majorVersion);
+ static QTypeRevision latestModuleVersion(const QString &uri);
+ static bool isStronglyLockedModule(const QString &uri, QTypeRevision version);
+ static QTypeRevision matchingModuleVersion(const QString &module, QTypeRevision version);
+ static QQmlTypeModule *typeModule(const QString &uri, QTypeRevision version);
static QList<QQmlPrivate::AutoParentFunction> parentFunctions();
enum class CachedUnitLookupError {
NoError,
NoUnitFound,
- VersionMismatch
+ VersionMismatch,
+ NotFullyTyped
};
- static const QV4::CompiledData::Unit *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>
@@ -176,9 +212,28 @@ 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);
+ static QQmlType registerSequentialContainer(
+ const QQmlPrivate::RegisterSequentialContainer &sequenceRegistration);
+ static void unregisterSequentialContainer(int id);
+
static int registerUnitCacheHook(const QQmlPrivate::RegisterQmlUnitCacheHook &hookRegistration);
static void clearTypeRegistrations();
@@ -186,15 +241,118 @@ 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 bool isValueType(QMetaType type);
+ static QQmlValueType *valueType(QMetaType metaType);
+ 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);
- static void qmlInsertModuleRegistration(const QString &uri, int majorVersion,
- void (*registerFunction)());
- static void qmlRegisterModuleTypes(const QString &uri, int majorVersion);
+// used in QQmlListMetaType to tag the metatpye
+inline const QMetaObject *dynamicQmlListMarker(const QtPrivate::QMetaTypeInterface *) {
+ return nullptr;
};
-Q_DECLARE_TYPEINFO(QQmlMetaType, Q_MOVABLE_TYPE);
+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
diff --git a/src/qml/qml/qqmlmetatypedata.cpp b/src/qml/qml/qqmlmetatypedata.cpp
index c2150225c3..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,21 +15,24 @@ QQmlMetaTypeData::QQmlMetaTypeData()
QQmlMetaTypeData::~QQmlMetaTypeData()
{
- for (TypeModules::const_iterator i = uriToModule.constBegin(), cend = uriToModule.constEnd(); i != cend; ++i)
- delete *i;
- for (QHash<const QMetaObject *, QQmlPropertyCache *>::Iterator 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();
+ qDeleteAll(metaTypeToValueType);
}
// 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;
@@ -74,71 +41,119 @@ void QQmlMetaTypeData::registerType(QQmlTypePrivate *priv)
}
}
types.append(QQmlType(priv));
- priv->index = types.count() - 1;
+ priv->index = types.size() - 1;
priv->release();
}
-void QQmlMetaTypeData::registerModuleTypes(const QQmlMetaTypeData::VersionedUri &versionedUri)
+QQmlMetaTypeData::VersionedUri::VersionedUri(const std::unique_ptr<QQmlTypeModule> &module)
+ : uri(module->module()), majorVersion(module->majorVersion())
{
- auto function = moduleTypeRegistrationFunctions.constFind(versionedUri);
- if (function != moduleTypeRegistrationFunctions.constEnd())
- (*function)();
}
-QQmlPropertyCache *QQmlMetaTypeData::propertyCacheForMinorVersion(int index, int minorVersion) const
+QQmlTypeModule *QQmlMetaTypeData::findTypeModule(const QString &module, QTypeRevision version)
{
- return (index < typePropertyCaches.length())
- ? typePropertyCaches.at(index).value(minorVersion).data()
+ const auto qqtm = std::lower_bound(
+ uriToModule.begin(), uriToModule.end(), VersionedUri(module, version),
+ std::less<QQmlMetaTypeData::VersionedUri>());
+ if (qqtm == uriToModule.end())
+ return nullptr;
+
+ QQmlTypeModule *candidate = qqtm->get();
+ return (candidate->module() == module && candidate->majorVersion() == version.majorVersion())
+ ? candidate
: nullptr;
}
-void QQmlMetaTypeData::setPropertyCacheForMinorVersion(int index, int minorVersion,
- QQmlPropertyCache *cache)
+QQmlTypeModule *QQmlMetaTypeData::addTypeModule(std::unique_ptr<QQmlTypeModule> module)
+{
+ QQmlTypeModule *ret = module.get();
+ uriToModule.emplace_back(std::move(module));
+ std::sort(uriToModule.begin(), uriToModule.end(),
+ [](const std::unique_ptr<QQmlTypeModule> &a,
+ const std::unique_ptr<QQmlTypeModule> &b) {
+ const int diff = a->module().compare(b->module());
+ return diff < 0 || (diff == 0 && a->majorVersion() < b->majorVersion());
+ });
+ return ret;
+}
+
+bool QQmlMetaTypeData::registerModuleTypes(const QString &uri)
+{
+ auto function = moduleTypeRegistrationFunctions.constFind(uri);
+ if (function != moduleTypeRegistrationFunctions.constEnd()) {
+ (*function)();
+ return true;
+ }
+ return false;
+}
+
+QQmlPropertyCache::ConstPtr QQmlMetaTypeData::propertyCacheForVersion(
+ int index, QTypeRevision version) const
+{
+ return (index < typePropertyCaches.size())
+ ? typePropertyCaches.at(index).value(version)
+ : QQmlPropertyCache::ConstPtr();
+}
+
+void QQmlMetaTypeData::setPropertyCacheForVersion(int index, QTypeRevision version,
+ const QQmlPropertyCache::ConstPtr &cache)
{
- if (index >= typePropertyCaches.length())
+ if (index >= typePropertyCaches.size())
typePropertyCaches.resize(index + 1);
- typePropertyCaches[index][minorVersion] = cache;
+ typePropertyCaches[index][version] = cache;
}
-void QQmlMetaTypeData::clearPropertyCachesForMinorVersion(int index)
+void QQmlMetaTypeData::clearPropertyCachesForVersion(int index)
{
- if (index < typePropertyCaches.length())
+ if (index < typePropertyCaches.size())
typePropertyCaches[index].clear();
}
-QQmlPropertyCache *QQmlMetaTypeData::propertyCache(const QMetaObject *metaObject, int minorVersion)
+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;
- }
- QQmlPropertyCache *super = propertyCache(metaObject->superClass(), minorVersion);
- QQmlPropertyCache *rv = super->copyAndAppend(metaObject, minorVersion);
- propertyCaches.insert(metaObject, rv);
+
return rv;
}
-QQmlPropertyCache *QQmlMetaTypeData::propertyCache(const QQmlType &type, int minorVersion)
+QQmlPropertyCache::ConstPtr QQmlMetaTypeData::propertyCache(
+ const QQmlType &type, QTypeRevision version)
{
Q_ASSERT(type.isValid());
- if (QQmlPropertyCache *pc = propertyCacheForMinorVersion(type.index(), minorVersion))
+ if (auto pc = propertyCacheForVersion(type.index(), version))
return pc;
QVector<QQmlType> types;
- int maxMinorVersion = 0;
+ 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())
+ : QTypeRevision::fromMajorVersion(type.version().majorVersion()));
while (metaObject) {
- QQmlType t = QQmlMetaType::qmlType(metaObject, type.module(), type.majorVersion(), minorVersion);
+ QQmlType t = QQmlMetaType::qmlType(metaObject, type.module(), combinedVersion);
if (t.isValid()) {
- maxMinorVersion = qMax(maxMinorVersion, t.minorVersion());
+ maxMinorVersion = qMax(maxMinorVersion, t.version().minorVersion());
types << t;
} else {
types << QQmlType();
@@ -147,32 +162,30 @@ QQmlPropertyCache *QQmlMetaTypeData::propertyCache(const QQmlType &type, int min
metaObject = metaObject->superClass();
}
- if (QQmlPropertyCache *pc = propertyCacheForMinorVersion(type.index(), maxMinorVersion)) {
- setPropertyCacheForMinorVersion(type.index(), minorVersion, pc);
+ const QTypeRevision maxVersion = QTypeRevision::fromVersion(combinedVersion.majorVersion(),
+ maxMinorVersion);
+ if (auto pc = propertyCacheForVersion(type.index(), maxVersion)) {
+ setPropertyCacheForVersion(type.index(), maxVersion, pc);
return pc;
}
- QQmlPropertyCache *raw = propertyCache(type.metaObject(), minorVersion);
-
- 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;
- int rev = currentType.metaObjectRevision();
- int moIndex = types.count() - 1 - ii;
+ QTypeRevision rev = currentType.metaObjectRevision();
+ 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);
}
}
@@ -198,12 +211,12 @@ QQmlPropertyCache *QQmlMetaTypeData::propertyCache(const QQmlType &type, int min
!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))
@@ -219,15 +232,31 @@ QQmlPropertyCache *QQmlMetaTypeData::propertyCache(const QQmlType &type, int min
}
#endif
- setPropertyCacheForMinorVersion(type.index(), minorVersion, raw);
-
- if (hasCopied)
- raw->release();
+ setPropertyCacheForVersion(type.index(), version, raw);
- if (minorVersion != maxMinorVersion)
- setPropertyCacheForMinorVersion(type.index(), maxMinorVersion, raw);
+ 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 755a51a16e..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
@@ -54,10 +18,10 @@
#include <private/qqmltype_p.h>
#include <private/qqmlmetatype_p.h>
#include <private/qhashedstring_p.h>
+#include <private/qqmlvaluetype_p.h>
#include <QtCore/qset.h>
#include <QtCore/qvector.h>
-#include <QtCore/qbitarray.h>
QT_BEGIN_NAMESPACE
@@ -71,55 +35,79 @@ struct QQmlMetaTypeData
QSet<QQmlType> undeletableTypes;
typedef QHash<int, QQmlTypePrivate *> Ids;
Ids idToType;
- typedef QHash<QHashedStringRef, QQmlTypePrivate *> Names;
+
+ 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
// of them by url, even if it was registered as
// a module via QQmlPrivate::RegisterCompositeType
- typedef QHash<const QMetaObject *, QQmlTypePrivate *> MetaObjects;
+ typedef QMultiHash<const QMetaObject *, QQmlTypePrivate *> MetaObjects;
MetaObjects metaObjectToType;
- typedef QHash<int, QQmlMetaType::StringConverter> StringConverters;
- StringConverters stringConverters;
- QVector<QHash<int, 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()
- : majorVersion(0) {}
- VersionedUri(const QHashedString &uri, int majorVersion)
- : uri(uri), majorVersion(majorVersion) {}
- bool operator==(const VersionedUri &other) const {
- return other.majorVersion == majorVersion && other.uri == uri;
+ VersionedUri() = default;
+ VersionedUri(const QString &uri, QTypeRevision version)
+ : uri(uri), majorVersion(version.majorVersion()) {}
+ VersionedUri(const std::unique_ptr<QQmlTypeModule> &module);
+
+ friend bool operator==(const VersionedUri &a, const VersionedUri &b)
+ {
+ return a.majorVersion == b.majorVersion && a.uri == b.uri;
+ }
+
+ friend size_t qHash(const VersionedUri &v, size_t seed = 0)
+ {
+ return qHashMulti(seed, v.uri, v.majorVersion);
+ }
+
+ friend bool operator<(const QQmlMetaTypeData::VersionedUri &a,
+ const QQmlMetaTypeData::VersionedUri &b)
+ {
+ const int diff = a.uri.compare(b.uri);
+ return diff < 0 || (diff == 0 && a.majorVersion < b.majorVersion);
}
- QHashedString uri;
- int majorVersion;
+
+ QString uri;
+ quint8 majorVersion = 0;
};
- typedef QHash<VersionedUri, QQmlTypeModule *> TypeModules;
+ typedef std::vector<std::unique_ptr<QQmlTypeModule>> TypeModules;
TypeModules uriToModule;
+ QQmlTypeModule *findTypeModule(const QString &module, QTypeRevision version);
+ QQmlTypeModule *addTypeModule(std::unique_ptr<QQmlTypeModule> module);
+
+ using ModuleImports = QMultiMap<VersionedUri, QQmlDirParser::Import>;
+ ModuleImports moduleImports;
- QHash<VersionedUri, void (*)()> moduleTypeRegistrationFunctions;
- void registerModuleTypes(const VersionedUri &versionedUri);
+ QHash<QString, void (*)()> moduleTypeRegistrationFunctions;
+ bool registerModuleTypes(const QString &uri);
- QBitArray objects;
- QBitArray interfaces;
- QBitArray lists;
+ QSet<int> interfaces;
QList<QQmlPrivate::AutoParentFunction> parentFunctions;
QVector<QQmlPrivate::QmlUnitCacheLookupFunction> lookupCachedQmlUnit;
- QHash<int, int> qmlLists;
+ QHash<const QMetaObject *, QQmlPropertyCache::ConstPtr> propertyCaches;
- QHash<const QMetaObject *, QQmlPropertyCache *> propertyCaches;
+ QQmlPropertyCache::ConstPtr propertyCacheForVersion(int index, QTypeRevision version) const;
+ void setPropertyCacheForVersion(
+ int index, QTypeRevision version, const QQmlPropertyCache::ConstPtr &cache);
+ void clearPropertyCachesForVersion(int index);
- QQmlPropertyCache *propertyCacheForMinorVersion(int index, int minorVersion) const;
- void setPropertyCacheForMinorVersion(int index, int minorVersion, QQmlPropertyCache *cache);
- void clearPropertyCachesForMinorVersion(int index);
-
- QQmlPropertyCache *propertyCache(const QMetaObject *metaObject, int minorVersion);
- QQmlPropertyCache *propertyCache(const QQmlType &type, int minorVersion);
+ 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)
{
@@ -138,11 +126,6 @@ private:
QStringList *m_typeRegistrationFailures = nullptr;
};
-inline uint qHash(const QQmlMetaTypeData::VersionedUri &v)
-{
- return v.uri.hash() ^ qHash(v.majorVersion);
-}
-
QT_END_NAMESPACE
#endif // QQMLMETATYPEDATA_P_H
diff --git a/src/qml/qml/qqmlmoduleregistration.cpp b/src/qml/qml/qqmlmoduleregistration.cpp
index bb82ec1d95..a6d7e879b3 100644
--- a/src/qml/qml/qqmlmoduleregistration.cpp
+++ b/src/qml/qml/qqmlmoduleregistration.cpp
@@ -1,54 +1,36 @@
-/****************************************************************************
-**
-** 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>
-#include <QtCore/qglobalstatic.h>
+#include <QtCore/qversionnumber.h>
QT_BEGIN_NAMESPACE
+struct QQmlModuleRegistrationPrivate
+{
+ const QString uri;
+};
+
+QQmlModuleRegistration::QQmlModuleRegistration(const char *uri, void (*registerFunction)()) :
+ d(new QQmlModuleRegistrationPrivate { QString::fromUtf8(uri) })
+{
+ QQmlMetaType::qmlInsertModuleRegistration(d->uri, registerFunction);
+}
+
+#if QT_DEPRECATED_SINCE(6, 0)
QQmlModuleRegistration::QQmlModuleRegistration(
- const char *uri, int majorVersion,
- void (*registerFunction)())
+ const char *uri, int majorVersion, void (*registerFunction)()) :
+ QQmlModuleRegistration(uri, registerFunction)
+{
+ Q_UNUSED(majorVersion);
+}
+#endif
+
+QQmlModuleRegistration::~QQmlModuleRegistration()
{
- QQmlMetaType::qmlInsertModuleRegistration(QString::fromUtf8(uri), majorVersion,
- registerFunction);
+ QQmlMetaType::qmlRemoveModuleRegistration(d->uri);
+ delete d;
}
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlmoduleregistration.h b/src/qml/qml/qqmlmoduleregistration.h
index 8924724b48..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
@@ -44,13 +8,21 @@
QT_BEGIN_NAMESPACE
+struct QQmlModuleRegistrationPrivate;
class Q_QML_EXPORT QQmlModuleRegistration
{
Q_DISABLE_COPY_MOVE(QQmlModuleRegistration)
-
public:
+ QQmlModuleRegistration(const char *uri, void (*registerFunction)());
+ ~QQmlModuleRegistration();
+
+#if QT_DEPRECATED_SINCE(6, 0)
+ QT_DEPRECATED_X("Use registration without major version")
QQmlModuleRegistration(const char *uri, int majorVersion, void (*registerFunction)());
- ~QQmlModuleRegistration() = default;
+#endif
+
+private:
+ QQmlModuleRegistrationPrivate *d = nullptr;
};
QT_END_NAMESPACE
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 1359586b31..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 {
@@ -118,15 +84,15 @@ void QQmlNotifierEndpoint::connect(QObject *source, int sourceSignal, QQmlEngine
disconnect();
Q_ASSERT(engine);
- if (QObjectPrivate::get(source)->threadData->threadId.loadRelaxed() !=
- QObjectPrivate::get(engine)->threadData->threadId.loadRelaxed()) {
+ if (QObjectPrivate::get(source)->threadData.loadRelaxed()->threadId.loadRelaxed() !=
+ QObjectPrivate::get(engine)->threadData.loadRelaxed()->threadId.loadRelaxed()) {
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 44006c3f6a..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"
@@ -56,75 +20,95 @@
#include <private/qqmldebugconnector_p.h>
#include <private/qqmldebugserviceinterfaces_p.h>
#include <private/qqmlscriptdata_p.h>
+#include <private/qqmlsourcecoordinate_p.h>
#include <private/qjsvalue_p.h>
#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 <qtqml_tracepoints_p.h>
+#include <QScopedValueRollback>
-QT_USE_NAMESPACE
+#include <qtqml_tracepoints_p.h>
+#include <QScopedValueRollback>
+#include <QLoggingCategory>
-namespace {
-struct ActiveOCRestorer
-{
- ActiveOCRestorer(QQmlObjectCreator *creator, QQmlEnginePrivate *ep)
- : ep(ep), oldCreator(ep->activeObjectCreator) { ep->activeObjectCreator = creator; }
- ~ActiveOCRestorer() { ep->activeObjectCreator = oldCreator; }
+Q_LOGGING_CATEGORY(lcQmlDefaultMethod, "qt.qml.defaultmethod")
- QQmlEnginePrivate *ep;
- QQmlObjectCreator *oldCreator;
-};
-}
+QT_USE_NAMESPACE
-QQmlObjectCreator::QQmlObjectCreator(QQmlContextData *parentContext, const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit, QQmlContextData *creationContext,
- QQmlIncubatorPrivate *incubator)
+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,
+ const QQmlRefPointer<QQmlContextData> &creationContext,
+ 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(parentContext);
+ init(std::move(parentContext));
sharedState->componentAttached = nullptr;
- sharedState->allCreatedBindings.allocate(compilationUnit->totalBindingsCount);
- sharedState->allParserStatusCallbacks.allocate(compilationUnit->totalParserStatusCount);
- sharedState->allCreatedObjects.allocate(compilationUnit->totalObjectCount);
- sharedState->allJavaScriptObjects = nullptr;
+ sharedState->allCreatedBindings.allocate(compilationUnit->totalBindingsCount());
+ sharedState->allParserStatusCallbacks.allocate(compilationUnit->totalParserStatusCount());
+ sharedState->allCreatedObjects.allocate(compilationUnit->totalObjectCount());
+ 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,
- sharedState->profiler.init(profiler, compilationUnit->totalParserStatusCount));
+ sharedState->profiler.init(profiler, compilationUnit->totalParserStatusCount()));
} else {
Q_UNUSED(profiler);
}
}
-QQmlObjectCreator::QQmlObjectCreator(QQmlContextData *parentContext, const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit, QQmlObjectCreatorSharedState *inheritedSharedState)
+QQmlObjectCreator::QQmlObjectCreator(QQmlRefPointer<QQmlContextData> parentContext,
+ const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit,
+ QQmlObjectCreatorSharedState *inheritedSharedState, bool isContextObject)
: phase(Startup)
, compilationUnit(compilationUnit)
- , propertyCaches(&compilationUnit->propertyCaches)
+ , propertyCaches(compilationUnit->propertyCachesPtr())
, sharedState(inheritedSharedState)
, topLevelCreator(false)
+ , isContextObject(isContextObject)
, incubator(nullptr)
{
- init(parentContext);
+ init(std::move(parentContext));
}
-void QQmlObjectCreator::init(QQmlContextData *providedParentContext)
+void QQmlObjectCreator::init(QQmlRefPointer<QQmlContextData> providedParentContext)
{
- parentContext = providedParentContext;
- engine = parentContext->engine;
+ parentContext = std::move(providedParentContext);
+ 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;
@@ -132,7 +116,6 @@ void QQmlObjectCreator::init(QQmlContextData *providedParentContext)
_compiledObject = nullptr;
_compiledObjectIndex = -1;
_ddata = nullptr;
- _propertyCache = nullptr;
_vmeMetaObject = nullptr;
_qmlContext = nullptr;
}
@@ -150,57 +133,69 @@ QQmlObjectCreator::~QQmlObjectCreator()
}
while (sharedState->componentAttached) {
QQmlComponentAttached *a = sharedState->componentAttached;
- a->rem();
+ a->removeFromList();
}
}
}
-QObject *QQmlObjectCreator::create(int subComponentIndex, QObject *parent, QQmlInstantiationInterrupt *interrupt)
+QObject *QQmlObjectCreator::create(int subComponentIndex, QObject *parent, QQmlInstantiationInterrupt *interrupt, int flags)
{
if (phase == CreatingObjectsPhase2) {
phase = ObjectsCreated;
- return context->contextObject;
+ return context->contextObject();
}
Q_ASSERT(phase == Startup);
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 {
- const QV4::CompiledData::Object *compObj = compilationUnit->objectAt(subComponentIndex);
- objectToCreate = compObj->bindingTable()->value.objectIndex;
+ 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 = new QQmlContextData;
- context->isInternal = true;
- context->imports = compilationUnit->typeNameCache;
- context->initFromTypeCompilationUnit(compilationUnit, subComponentIndex);
- context->setParent(parentContext);
+ context = QQmlEnginePrivate::get(engine)->createInternalContext(
+ compilationUnit, parentContext, subComponentIndex, isComponentRoot);
if (!sharedState->rootContext) {
sharedState->rootContext = context;
- sharedState->rootContext->incubator = incubator;
- sharedState->rootContext->isRootObjectInCreation = true;
+ sharedState->rootContext->setIncubator(incubator);
+ sharedState->rootContext->setRootObjectInCreation(true);
}
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->importedScripts.set(v4, scripts);
- 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) {
- context->importedScripts = sharedState->creationContext->importedScripts;
+ sharedState->allJavaScriptObjects = ObjectInCreationGCAnchorList(scope, compilationUnit->totalObjectCount());
+
+ if (!isComponentRoot && sharedState->creationContext) {
+ // otherwise QQmlEnginePrivate::createInternalContext() handles it
+ context->setImportedScripts(sharedState->creationContext->importedScripts());
}
QObject *instance = createInstance(objectToCreate, parent, /*isContextObject*/true);
@@ -211,7 +206,7 @@ QObject *QQmlObjectCreator::create(int subComponentIndex, QObject *parent, QQmlI
}
if (topLevelCreator)
- sharedState->allJavaScriptObjects = nullptr;
+ sharedState->allJavaScriptObjects = ObjectInCreationGCAnchorList();
phase = CreatingObjectsPhase2;
@@ -223,72 +218,44 @@ QObject *QQmlObjectCreator::create(int subComponentIndex, QObject *parent, QQmlI
if (instance) {
if (QQmlEngineDebugService *service
= QQmlDebugConnector::service<QQmlEngineDebugService>()) {
- if (!parentContext->isInternal)
- parentContext->asQQmlContextPrivate()->instances.append(instance);
+ if (!parentContext->isInternal())
+ parentContext->asQQmlContextPrivate()->appendInstance(instance);
service->objectCreated(engine, instance);
- } else if (!parentContext->isInternal && QQmlDebugConnector::service<QV4DebugService>()) {
- parentContext->asQQmlContextPrivate()->instances.append(instance);
+ } else if (!parentContext->isInternal() && QQmlDebugConnector::service<QV4DebugService>()) {
+ parentContext->asQQmlContextPrivate()->appendInstance(instance);
}
}
return instance;
}
-void QQmlObjectCreator::beginPopulateDeferred(QQmlContextData *newContext)
+void QQmlObjectCreator::beginPopulateDeferred(const QQmlRefPointer<QQmlContextData> &newContext)
{
context = newContext;
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);
-
- 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) {
@@ -298,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,
@@ -326,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()
@@ -340,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();
+ 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);
@@ -357,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);
@@ -377,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()) {
@@ -397,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 {
@@ -417,45 +393,40 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const
QV4::ScopedString s(scope, v4->newString(stringValue));
_vmeMetaObject->setVMEProperty(property->coreIndex(), s);
} else {
- // ### Qt 6: Doing the conversion here where we don't know the eventual target type is rather strange
- // and caused for instance QTBUG-78943
- QVariant value = QQmlStringConverters::variantFromString(stringValue);
+ QVariant value = stringValue;
property->writeProperty(_qobject, &value, propertyWriteFlags);
}
}
}
break;
- case QVariant::String: {
+ case QMetaType::QString: {
assertOrNull(binding->evaluatesToString());
QString value = compilationUnit->bindingValueAsString(binding);
property->writeProperty(_qobject, &value, propertyWriteFlags);
}
break;
- case QVariant::StringList: {
+ case QMetaType::QStringList: {
assertOrNull(binding->evaluatesToString());
QStringList value(compilationUnit->bindingValueAsString(binding));
property->writeProperty(_qobject, &value, propertyWriteFlags);
}
break;
- case QVariant::ByteArray: {
+ case QMetaType::QByteArray: {
assertType(QV4::CompiledData::Binding::Type_String);
QByteArray value(compilationUnit->bindingValueAsString(binding).toUtf8());
property->writeProperty(_qobject, &value, propertyWriteFlags);
}
break;
- case QVariant::Url: {
+ case QMetaType::QUrl: {
assertType(QV4::CompiledData::Binding::Type_String);
- QString string = compilationUnit->bindingValueAsString(binding);
- // Encoded dir-separators defeat QUrl processing - decode them first
- string.replace(QLatin1String("%2f"), QLatin1String("/"), Qt::CaseInsensitive);
- QUrl value = string.isEmpty() ? QUrl() : compilationUnit->finalUrl().resolved(QUrl(string));
- // Apply URL interceptor
- if (engine->urlInterceptor())
- value = engine->urlInterceptor()->intercept(value, QQmlAbstractUrlInterceptor::UrlString);
+ const QString string = compilationUnit->bindingValueAsString(binding);
+ QUrl value = (!string.isEmpty() && QQmlPropertyPrivate::resolveUrlsOnAssignment())
+ ? compilationUnit->finalUrl().resolved(QUrl(string))
+ : QUrl(string);
property->writeProperty(_qobject, &value, propertyWriteFlags);
}
break;
- case QVariant::UInt: {
+ case QMetaType::UInt: {
assertType(QV4::CompiledData::Binding::Type_Number);
double d = compilationUnit->bindingValueAsNumber(binding);
uint value = uint(d);
@@ -463,7 +434,7 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const
break;
}
break;
- case QVariant::Int: {
+ case QMetaType::Int: {
assertType(QV4::CompiledData::Binding::Type_Number);
double d = compilationUnit->bindingValueAsNumber(binding);
int value = int(d);
@@ -471,225 +442,247 @@ 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));
property->writeProperty(_qobject, &value, propertyWriteFlags);
}
break;
- case QVariant::Double: {
+ case QMetaType::Double: {
assertType(QV4::CompiledData::Binding::Type_Number);
double value = compilationUnit->bindingValueAsNumber(binding);
property->writeProperty(_qobject, &value, propertyWriteFlags);
}
break;
- case QVariant::Color: {
- bool ok = false;
- uint colorValue = QQmlStringConverters::rgbaFromString(compilationUnit->bindingValueAsString(binding), &ok);
- assertOrNull(ok);
- struct { void *data[4]; } buffer;
- if (QQml_valueTypeProvider()->storeValueType(property->propType(), &colorValue, &buffer, sizeof(buffer))) {
- property->writeProperty(_qobject, &buffer, propertyWriteFlags);
+ case QMetaType::QColor: {
+ QVariant data = QQmlValueTypeProvider::createValueType(
+ compilationUnit->bindingValueAsString(binding), propertyType);
+ if (data.isValid()) {
+ property->writeProperty(_qobject, data.data(), propertyWriteFlags);
}
}
break;
#if QT_CONFIG(datestring)
- case QVariant::Date: {
+ case QMetaType::QDate: {
bool ok = false;
QDate value = QQmlStringConverters::dateFromString(compilationUnit->bindingValueAsString(binding), &ok);
assertOrNull(ok);
property->writeProperty(_qobject, &value, propertyWriteFlags);
}
break;
- case QVariant::Time: {
+ case QMetaType::QTime: {
bool ok = false;
QTime value = QQmlStringConverters::timeFromString(compilationUnit->bindingValueAsString(binding), &ok);
assertOrNull(ok);
property->writeProperty(_qobject, &value, propertyWriteFlags);
}
break;
- case QVariant::DateTime: {
+ case QMetaType::QDateTime: {
bool ok = false;
- QDateTime value = QQmlStringConverters::dateTimeFromString(compilationUnit->bindingValueAsString(binding), &ok);
- // ### VME compatibility :(
- {
- const qint64 date = value.date().toJulianDay();
- const int msecsSinceStartOfDay = value.time().msecsSinceStartOfDay();
- value = QDateTime(QDate::fromJulianDay(date), QTime::fromMSecsSinceStartOfDay(msecsSinceStartOfDay));
- }
+ QDateTime value = QQmlStringConverters::dateTimeFromString(
+ compilationUnit->bindingValueAsString(binding), &ok);
assertOrNull(ok);
property->writeProperty(_qobject, &value, propertyWriteFlags);
}
break;
#endif // datestring
- case QVariant::Point: {
+ case QMetaType::QPoint: {
bool ok = false;
QPoint value = QQmlStringConverters::pointFFromString(compilationUnit->bindingValueAsString(binding), &ok).toPoint();
assertOrNull(ok);
property->writeProperty(_qobject, &value, propertyWriteFlags);
}
break;
- case QVariant::PointF: {
+ case QMetaType::QPointF: {
bool ok = false;
QPointF value = QQmlStringConverters::pointFFromString(compilationUnit->bindingValueAsString(binding), &ok);
assertOrNull(ok);
property->writeProperty(_qobject, &value, propertyWriteFlags);
}
break;
- case QVariant::Size: {
+ case QMetaType::QSize: {
bool ok = false;
QSize value = QQmlStringConverters::sizeFFromString(compilationUnit->bindingValueAsString(binding), &ok).toSize();
assertOrNull(ok);
property->writeProperty(_qobject, &value, propertyWriteFlags);
}
break;
- case QVariant::SizeF: {
+ case QMetaType::QSizeF: {
bool ok = false;
QSizeF value = QQmlStringConverters::sizeFFromString(compilationUnit->bindingValueAsString(binding), &ok);
assertOrNull(ok);
property->writeProperty(_qobject, &value, propertyWriteFlags);
}
break;
- case QVariant::Rect: {
+ case QMetaType::QRect: {
bool ok = false;
QRect value = QQmlStringConverters::rectFFromString(compilationUnit->bindingValueAsString(binding), &ok).toRect();
assertOrNull(ok);
property->writeProperty(_qobject, &value, propertyWriteFlags);
}
break;
- case QVariant::RectF: {
+ case QMetaType::QRectF: {
bool ok = false;
QRectF value = QQmlStringConverters::rectFFromString(compilationUnit->bindingValueAsString(binding), &ok);
assertOrNull(ok);
property->writeProperty(_qobject, &value, propertyWriteFlags);
}
break;
- case QVariant::Bool: {
+ case QMetaType::Bool: {
assertType(QV4::CompiledData::Binding::Type_Boolean);
bool value = binding->valueAsBoolean();
property->writeProperty(_qobject, &value, propertyWriteFlags);
}
break;
- case QVariant::Vector2D: {
- struct {
- float xp;
- float yp;
- } vec;
- bool ok = QQmlStringConverters::createFromString(QMetaType::QVector2D, compilationUnit->bindingValueAsString(binding), &vec, sizeof(vec));
- assertOrNull(ok);
- Q_UNUSED(ok);
- property->writeProperty(_qobject, &vec, propertyWriteFlags);
- }
- break;
- case QVariant::Vector3D: {
- struct {
- float xp;
- float yp;
- float zy;
- } vec;
- bool ok = QQmlStringConverters::createFromString(QMetaType::QVector3D, compilationUnit->bindingValueAsString(binding), &vec, sizeof(vec));
- assertOrNull(ok);
- Q_UNUSED(ok);
- property->writeProperty(_qobject, &vec, propertyWriteFlags);
- }
- break;
- case QVariant::Vector4D: {
- struct {
- float xp;
- float yp;
- float zy;
- float wp;
- } vec;
- bool ok = QQmlStringConverters::createFromString(QMetaType::QVector4D, compilationUnit->bindingValueAsString(binding), &vec, sizeof(vec));
- assertOrNull(ok);
- Q_UNUSED(ok);
- property->writeProperty(_qobject, &vec, propertyWriteFlags);
- }
- break;
- case QVariant::Quaternion: {
- struct {
- float wp;
- float xp;
- float yp;
- float zp;
- } vec;
- bool ok = QQmlStringConverters::createFromString(QMetaType::QQuaternion, compilationUnit->bindingValueAsString(binding), &vec, sizeof(vec));
- assertOrNull(ok);
- Q_UNUSED(ok);
- property->writeProperty(_qobject, &vec, propertyWriteFlags);
- }
- break;
- case QVariant::RegExp:
- assertOrNull(!"not possible");
+ case QMetaType::QVector2D:
+ case QMetaType::QVector3D:
+ case QMetaType::QVector4D:
+ case QMetaType::QQuaternion: {
+ 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 (property->propType() == 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 (property->propType() == 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 (property->propType() == 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 (property->propType() == qMetaTypeId<QList<QUrl> >()) {
+ } else if (propertyType == QMetaType::fromType<QList<QUrl>>()) {
assertType(QV4::CompiledData::Binding::Type_String);
- QString urlString = compilationUnit->bindingValueAsString(binding);
- QUrl u = urlString.isEmpty() ? QUrl()
- : compilationUnit->finalUrl().resolved(QUrl(urlString));
- QList<QUrl> value;
- value.append(u);
+ const QUrl url(compilationUnit->bindingValueAsString(binding));
+ QList<QUrl> value {
+ QQmlPropertyPrivate::resolveUrlsOnAssignment()
+ ? compilationUnit->finalUrl().resolved(url)
+ : url
+ };
property->writeProperty(_qobject, &value, propertyWriteFlags);
break;
- } else if (property->propType() == 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 (property->propType() == 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());
- Q_ASSERT(converter);
- QVariant value = (*converter)(stringValue);
-
QMetaProperty metaProperty = _qobject->metaObject()->property(property->coreIndex());
- if (value.isNull() || ((int)metaProperty.type() != property->propType() && metaProperty.userType() != 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;
}
@@ -706,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() == QMetaType::QString) {
+ 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);
}
}
@@ -731,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);
@@ -739,11 +734,14 @@ 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 ? _propertyCache->property(stringAt(binding->propertyNameIndex), _qobject, context) : defaultProperty;
+ const QQmlPropertyData *property = binding->propertyNameIndex != 0
+ ? _propertyCache->property(stringAt(binding->propertyNameIndex),
+ _qobject, context)
+ : defaultProperty;
if (property)
bindingSkipList |= (1 << property->coreIndex());
}
@@ -757,39 +755,66 @@ 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
- auto target = _bindingTarget;
QQmlPropertyIndex originalIndex(targetProperty->coreIndex(), _valueTypeProperty ? _valueTypeProperty->coreIndex() : -1);
- QQmlPropertyIndex propIndex;
- QQmlPropertyPrivate::findAliasTarget(target, originalIndex, &target, &propIndex);
- QQmlData *data = QQmlData::get(target);
+ auto [targetObject, targetIndex] = QQmlPropertyPrivate::findAliasTarget(_bindingTarget, originalIndex);
+ QQmlData *data = QQmlData::get(targetObject);
Q_ASSERT(data && data->propertyCache);
- targetProperty = data->propertyCache->property(propIndex.coreIndex());
+ 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);
currentListPropertyIndex = property->coreIndex();
+
+ // manage override behavior
+ const QMetaObject *const metaobject = _qobject->metaObject();
+ const int qmlListBehavorClassInfoIndex = metaobject->indexOfClassInfo("QML.ListPropertyAssignBehavior");
+ if (qmlListBehavorClassInfoIndex != -1) { // QML.ListPropertyAssignBehavior class info is set
+ const char *overrideBehavior =
+ metaobject->classInfo(qmlListBehavorClassInfoIndex).value();
+ if (!strcmp(overrideBehavior,
+ "Replace")) {
+ if (_currentList.clear) {
+ _currentList.clear(&_currentList);
+ }
+ } else {
+ bool isDefaultProperty =
+ (property->name(_qobject)
+ == QString::fromUtf8(
+ metaobject
+ ->classInfo(metaobject->indexOfClassInfo(
+ "DefaultProperty"))
+ .value()));
+ if (!isDefaultProperty
+ && (!strcmp(overrideBehavior,
+ "ReplaceIfNotDefault"))) {
+ if (_currentList.clear) {
+ _currentList.clear(&_currentList);
+ }
+ }
+ }
+ }
}
} else if (_currentList.object) {
_currentList = QQmlListProperty<void>();
@@ -805,34 +830,45 @@ 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;
+ QQmlType attachedType = tr->type();
+ QQmlEnginePrivate *enginePrivate = QQmlEnginePrivate::get(engine);
if (!attachedType.isValid()) {
- QQmlTypeNameCache::Result res = context->imports->query(stringAt(binding->propertyNameIndex));
+ QQmlTypeNameCache::Result res = context->imports()->query(
+ 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;
}
// ### resolve this at compile time
- if (bindingProperty && bindingProperty->propType() == qMetaTypeId<QQmlScriptString>()) {
+ 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 |
@@ -844,26 +880,34 @@ 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()) {
QObject *groupObject = nullptr;
- QQmlValueType *valueType = nullptr;
+ QQmlGadgetPtrWrapper *valueType = nullptr;
const QQmlPropertyData *valueTypeProperty = nullptr;
QObject *bindingTarget = _bindingTarget;
-
- if (QQmlValueTypeFactory::isValueType(bindingProperty->propType())) {
- valueType = QQmlValueTypeFactory::valueType(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)));
return false;
@@ -877,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);
@@ -894,20 +950,71 @@ 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) {
+ 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());
- QQmlBoundSignal *bs = new QQmlBoundSignal(_bindingTarget, signalIndex, _scopeObject, engine);
- QQmlBoundSignalExpression *expr = new QQmlBoundSignalExpression(_bindingTarget, signalIndex,
- context, _scopeObject, runtimeFunction, currentQmlContext());
+ QQmlBoundSignalExpression *expr = new QQmlBoundSignalExpression(
+ _bindingTarget, signalIndex, context,
+ _scopeObject, runtimeFunction, currentQmlContext());
- bs->takeExpression(expr);
+ if (bindingProperty->isBindable()) {
+ auto target = _bindingTarget;
+ if (bindingProperty->isAlias()) {
+ // If the property is an alias, we cannot obtain the bindable interface directly with qt_metacall
+ // so instead, we resolve the alias to obtain the actual target
+ // This should be faster than doing a detour through the metaobject of the target, and relying on
+ // QMetaObject::metacall doing the correct resolution
+ QQmlPropertyIndex originalIndex(bindingProperty->coreIndex(), _valueTypeProperty ? _valueTypeProperty->coreIndex() : -1);
+ auto [aliasTargetObject, aliasTargetIndex] = QQmlPropertyPrivate::findAliasTarget(target, originalIndex);
+ target = aliasTargetObject;
+ QQmlData *data = QQmlData::get(target);
+ Q_ASSERT(data && data->propertyCache);
+ bindingProperty = data->propertyCache->property(aliasTargetIndex.coreIndex());
+ }
+ auto &observer = QQmlData::get(_scopeObject)->propertyObservers.emplace_back(expr);
+ QUntypedBindable bindable;
+ void *argv[] = { &bindable };
+ target->qt_metacall(QMetaObject::BindableProperty, bindingProperty->coreIndex(), argv);
+ Q_ASSERT(bindable.isValid());
+ bindable.observe(&observer);
+ } else {
+ QQmlBoundSignal *bs = new QQmlBoundSignal(_bindingTarget, signalIndex, _scopeObject, engine);
+ bs->takeExpression(expr);
+ }
+ } else if (bindingProperty->isBindable()) {
+ QUntypedPropertyBinding qmlBinding;
+ if (binding->isTranslationBinding()) {
+ qmlBinding = QQmlTranslationPropertyBinding::create(bindingProperty, compilationUnit, binding);
+ } else {
+ QV4::Function *runtimeFunction = compilationUnit->runtimeFunctions[binding->value.compiledScriptIndex];
+ QQmlPropertyIndex index(bindingProperty->coreIndex(), -1);
+ qmlBinding = QQmlPropertyBinding::create(bindingProperty, runtimeFunction, _scopeObject, context, currentQmlContext(), _bindingTarget, index);
+ }
+ 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
@@ -922,10 +1029,12 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *bindingProper
subprop = bindingProperty;
}
if (binding->isTranslationBinding()) {
- qmlBinding = QQmlBinding::createTranslationBinding(compilationUnit, binding, _scopeObject, context);
+ qmlBinding = QQmlBinding::createTranslationBinding(
+ compilationUnit, binding, _scopeObject, context);
} else {
QV4::Function *runtimeFunction = compilationUnit->runtimeFunctions[binding->value.compiledScriptIndex];
- qmlBinding = QQmlBinding::create(targetProperty, runtimeFunction, _scopeObject, context, currentQmlContext());
+ qmlBinding = QQmlBinding::create(targetProperty, runtimeFunction, _scopeObject,
+ context, currentQmlContext());
}
auto bindingTarget = _bindingTarget;
@@ -956,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());
@@ -967,10 +1076,12 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *bindingProper
QQmlPropertyValueSource *vs = reinterpret_cast<QQmlPropertyValueSource *>(reinterpret_cast<char *>(createdSubObject) + valueSourceCast);
QObject *target = createdSubObject->parent();
QQmlProperty prop;
- if (_valueTypeProperty)
- prop = QQmlPropertyPrivate::restore(target, *_valueTypeProperty, bindingProperty, context);
- else
+ if (_valueTypeProperty) {
+ prop = QQmlPropertyPrivate::restore(target, *_valueTypeProperty,
+ bindingProperty, context);
+ } else {
prop = QQmlPropertyPrivate::restore(target, *bindingProperty, nullptr, context);
+ }
vs->setTarget(prop);
return true;
}
@@ -982,8 +1093,8 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *bindingProper
QQmlPropertyIndex propertyIndex;
if (bindingProperty->isAlias()) {
QQmlPropertyIndex originalIndex(bindingProperty->coreIndex(), _valueTypeProperty ? _valueTypeProperty->coreIndex() : -1);
- QQmlPropertyIndex propIndex;
- QQmlPropertyPrivate::findAliasTarget(target, originalIndex, &target, &propIndex);
+ auto aliasTarget = QQmlPropertyPrivate::findAliasTarget(target, originalIndex);
+ target = aliasTarget.targetObject;
QQmlData *data = QQmlData::get(target);
if (!data || !data->propertyCache) {
qWarning() << "can't resolve property alias for 'on' assignment";
@@ -991,16 +1102,20 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *bindingProper
}
// we can't have aliasses on subproperties of value types, so:
- QQmlPropertyData targetPropertyData = *data->propertyCache->property(propIndex.coreIndex());
- auto prop = QQmlPropertyPrivate::restore(target, targetPropertyData, nullptr, context);
+ QQmlPropertyData targetPropertyData = *data->propertyCache->property(aliasTarget.targetIndex.coreIndex());
+ auto prop = QQmlPropertyPrivate::restore(
+ target, targetPropertyData, nullptr, context);
vi->setTarget(prop);
propertyIndex = QQmlPropertyPrivate::propertyIndex(prop);
} else {
QQmlProperty prop;
- if (_valueTypeProperty)
- prop = QQmlPropertyPrivate::restore(target, *_valueTypeProperty, bindingProperty, context);
- else
- prop = QQmlPropertyPrivate::restore(target, *bindingProperty, nullptr, context);
+ if (_valueTypeProperty) {
+ prop = QQmlPropertyPrivate::restore(
+ target, *_valueTypeProperty, bindingProperty, context);
+ } else {
+ prop = QQmlPropertyPrivate::restore(
+ target, *bindingProperty, nullptr, context);
+ }
vi->setTarget(prop);
propertyIndex = QQmlPropertyPrivate::propertyIndex(prop);
}
@@ -1014,8 +1129,8 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *bindingProper
return false;
}
- // Assigning object to signal property?
- if (binding->flags & QV4::CompiledData::Binding::IsSignalHandlerObject) {
+ // Assigning object to signal property? ### Qt 7: Remove that functionality
+ 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;
@@ -1025,11 +1140,14 @@ 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. The object is:" << createdSubObject;
QMetaMethod signalMethod = _qobject->metaObject()->method(bindingProperty->coreIndex());
if (!QMetaObject::checkConnectArgs(signalMethod, method)) {
recordError(binding->valueLocation,
- tr("Cannot connect mismatched signal/slot %1 %vs. %2")
+ tr("Cannot connect mismatched signal/slot %1 vs %2")
.arg(QString::fromUtf8(method.methodSignature()))
.arg(QString::fromUtf8(signalMethod.methodSignature())));
return false;
@@ -1053,7 +1171,7 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *bindingProper
recordError(binding->location, tr("Cannot assign object to interface property"));
return false;
}
- } else if (bindingProperty->propType() == QMetaType::QVariant) {
+ } else if (bindingProperty->propType() == QMetaType::fromType<QVariant>()) {
if (bindingProperty->isVarProperty()) {
QV4::Scope scope(v4);
QV4::ScopedValue wrappedObject(scope, QV4::QObjectWrapper::wrap(engine->handle(), createdSubObject));
@@ -1063,28 +1181,28 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *bindingProper
argv[0] = &value;
QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, bindingProperty->coreIndex(), argv);
}
- } else if (bindingProperty->propType() == qMetaTypeId<QJSValue>()) {
+ } else if (bindingProperty->propType() == QMetaType::fromType<QJSValue>()) {
QV4::Scope scope(v4);
QV4::ScopedValue wrappedObject(scope, QV4::QObjectWrapper::wrap(engine->handle(), createdSubObject));
if (bindingProperty->isVarProperty()) {
_vmeMetaObject->setVMEProperty(bindingProperty->coreIndex(), wrappedObject);
} else {
QJSValue value;
- QJSValuePrivate::setValue(&value, v4, wrappedObject);
+ QJSValuePrivate::setValue(&value, wrappedObject);
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 = QQmlEnginePrivate::get(engine)->listType(bindingProperty->propType());
- 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);
@@ -1121,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;
@@ -1137,21 +1255,16 @@ void QQmlObjectCreator::recordError(const QV4::CompiledData::Location &location,
{
QQmlError error;
error.setUrl(compilationUnit->url());
- error.setLine(location.line);
- error.setColumn(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->setIdProperty(object->id, instance);
-}
-
-void QQmlObjectCreator::createQmlContext()
-{
- _qmlContext->setM(QV4::QmlContext::create(v4->rootContext(), context, _scopeObject));
+ if (object->objectId() >= 0)
+ context->setIdValue(object->objectId(), instance);
}
QObject *QQmlObjectCreator::createInstance(int index, QObject *parent, bool isContextObject)
@@ -1162,7 +1275,7 @@ QObject *QQmlObjectCreator::createInstance(int index, QObject *parent, bool isCo
QString typeName;
Q_TRACE_EXIT(QQmlObjectCreator_createInstance_exit, typeName);
- ActiveOCRestorer ocRestorer(this, QQmlEnginePrivate::get(engine));
+ QScopedValueRollback<QQmlObjectCreator*> ocRestore(QQmlEnginePrivate::get(engine)->activeObjectCreator, this);
bool isComponent = false;
QObject *instance = nullptr;
@@ -1171,63 +1284,96 @@ 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);
- installPropertyCache = !typeRef->isFullyDynamicType;
- QQmlType type = typeRef->type;
- if (type.isValid()) {
+ installPropertyCache = !typeRef->isFullyDynamicType();
+ const QQmlType type = typeRef->type();
+ 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);
customParser = type.customParser();
- if (sharedState->rootContext && sharedState->rootContext->isRootObjectInCreation) {
+ if (sharedState->rootContext && sharedState->rootContext->isRootObjectInCreation()) {
QQmlData *ddata = QQmlData::get(instance, /*create*/true);
ddata->rootObjectInCreation = true;
- sharedState->rootContext->isRootObjectInCreation = false;
+ sharedState->rootContext->setRootObjectInCreation(false);
}
sharedState->allCreatedObjects.push(instance);
} else {
- Q_ASSERT(typeRef->compilationUnit);
- typeName = typeRef->compilationUnit->fileName();
- if (typeRef->compilationUnit->unitData()->isSingleton())
- {
+ auto compilationUnit = typeRef->compilationUnit();
+ Q_ASSERT(compilationUnit);
+ typeName = compilationUnit->fileName();
+ // compilation unit is shared between root type and its inline component types
+ // so isSingleton errorneously returns true for inline components
+ if (compilationUnit->unitData()->isSingleton() && !type.isInlineComponentType()) {
recordError(obj->location, tr("Composite Singleton Type %1 is not creatable").arg(stringAt(obj->inheritedTypeNameIndex)));
return nullptr;
}
- QQmlObjectCreator subCreator(context, typeRef->compilationUnit, sharedState.data());
- instance = subCreator.create();
- if (!instance) {
- errors += subCreator.errors;
- return nullptr;
+ if (!type.isInlineComponentType()) {
+ QQmlObjectCreator subCreator(
+ context, engine->handle()->executableCompilationUnit(
+ std::move(compilationUnit)),
+ sharedState.data(), isContextObject);
+ instance = subCreator.create();
+ if (!instance) {
+ errors += subCreator.errors;
+ return nullptr;
+ }
+ } else {
+ 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;
+ }
}
}
if (instance->isWidgetType()) {
@@ -1248,27 +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();
- if (static_cast<quint32>(index) == /*root object*/0 || ddata->rootObjectInCreation) {
- if (ddata->context) {
- Q_ASSERT(ddata->context != context);
- Q_ASSERT(ddata->outerContext);
- Q_ASSERT(ddata->outerContext != context);
- QQmlContextData *c = ddata->context;
- while (c->linkedContext) c = c->linkedContext;
- c->linkedContext = context;
- } else {
- ddata->context = context;
- }
- ddata->ownContext = ddata->context;
- } else if (!ddata->context) {
- ddata->context = context;
- }
-
- context->addObject(ddata);
+ // inline components are root objects, but their index is != 0, so we need
+ // an additional check
+ 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();
@@ -1282,21 +1418,20 @@ QObject *QQmlObjectCreator::createInstance(int index, QObject *parent, bool isCo
// Register the context object in the context early on in order for pending binding
// initialization to find it available.
if (isContextObject)
- context->contextObject = instance;
+ 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;
@@ -1307,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());
@@ -1357,13 +1487,26 @@ QObject *QQmlObjectCreator::createInstance(int index, QObject *parent, bool isCo
return ok ? instance : nullptr;
}
-QQmlContextData *QQmlObjectCreator::finalize(QQmlInstantiationInterrupt &interrupt)
+bool QQmlObjectCreator::finalize(QQmlInstantiationInterrupt &interrupt)
{
Q_ASSERT(phase == ObjectsCreated || phase == Finalizing);
phase = Finalizing;
QQmlObjectCreatorRecursionWatcher watcher(this);
- ActiveOCRestorer ocRestorer(this, QQmlEnginePrivate::get(engine));
+ 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();
@@ -1376,15 +1519,54 @@ QQmlContextData *QQmlObjectCreator::finalize(QQmlInstantiationInterrupt &interru
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->context() && !binding->context()->unresolvedNames)
+ && !binding->hasUnresolvedNames()) {
b->removeFromObject();
+ }
}
if (watcher.hasRecursed() || interrupt.shouldInterrupt())
- return nullptr;
+ return false;
+ }
+
+ 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 };
+ // 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;
}
if (QQmlVME::componentCompleteEnabled()) { // the qml designer does the component complete later
@@ -1398,39 +1580,34 @@ QQmlContextData *QQmlObjectCreator::finalize(QQmlInstantiationInterrupt &interru
}
if (watcher.hasRecursed() || interrupt.shouldInterrupt())
- return nullptr;
+ return false;
}
}
- 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 nullptr;
+ return false;
}
- sharedState->finalizeCallbacks.clear();
+ sharedState->finalizeHooks.clear();
while (sharedState->componentAttached) {
QQmlComponentAttached *a = sharedState->componentAttached;
- a->rem();
+ a->removeFromList();
QQmlData *d = QQmlData::get(a->parent());
Q_ASSERT(d);
Q_ASSERT(d->context);
- a->add(&d->context->componentAttached);
+ d->context->addComponentAttached(a);
if (QQmlVME::componentCompleteEnabled())
emit a->completed();
if (watcher.hasRecursed() || interrupt.shouldInterrupt())
- return nullptr;
+ return false;
}
phase = Done;
- return sharedState->rootContext;
+ return true;
}
void QQmlObjectCreator::clear()
@@ -1448,14 +1625,17 @@ void QQmlObjectCreator::clear()
while (sharedState->componentAttached) {
QQmlComponentAttached *a = sharedState->componentAttached;
- a->rem();
+ a->removeFromList();
}
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);
@@ -1469,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);
@@ -1490,44 +1667,158 @@ 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));
+ bool hadInheritedRequiredProperties = !postHocRequired.empty();
+
for (int propertyIndex = 0; propertyIndex != _compiledObject->propertyCount(); ++propertyIndex) {
const QV4::CompiledData::Property* property = _compiledObject->propertiesBegin() + propertyIndex;
- QQmlPropertyData *propertyData = _propertyCache->property(_propertyCache->propertyOffset() + propertyIndex);
- if (property->isRequired) {
- sharedState->hadRequiredProperties = true;
- sharedState->requiredProperties.insert(propertyData,
- RequiredPropertyInfo {compilationUnit->stringAt(property->nameIndex), compilationUnit->finalUrl(), property->location, {}});
+ 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)
+ continue;
+ if (postHocIt != postHocRequired.end())
+ postHocRequired.erase(postHocIt);
+ if (isContextObject)
+ sharedState->hadTopLevelRequiredProperties = true;
+ sharedState->requiredProperties.insert({_qobject, propertyData},
+ RequiredPropertyInfo {compilationUnit->stringAt(property->nameIndex), compilationUnit->finalUrl(), property->location, {}});
+
+ }
+
+ 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);
+ auto postHocIt = postHocRequired.find(name);
+ if (!propertyData->isRequired() && postHocRequired.end() == postHocIt )
+ continue;
+
+ if (postHocIt != postHocRequired.end())
+ postHocRequired.erase(postHocIt);
+
+ 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);
- if (!context->idValues->wasSet())
+ Q_ASSERT(alias->hasFlag(QV4::CompiledData::Alias::Resolved));
+ if (!context->isIdValueSet(0)) // TODO: Do we really want 0 here?
continue;
- QObject *target = context->idValues[alias->targetObjectId].data();
+ QObject *target = context->idValue(alias->targetObjectId());
if (!target)
continue;
QQmlData *targetDData = QQmlData::get(target, /*create*/false);
- if (!targetDData)
+ 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);
@@ -1542,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 8b6cb67341..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
@@ -57,6 +21,9 @@
#include <private/qrecursionwatcher_p.h>
#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>
@@ -86,71 +53,152 @@ struct RequiredPropertyInfo
QVector<AliasToRequiredInfo> aliasesToRequired;
};
-using RequiredProperties = 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);
+ }
-struct QQmlObjectCreatorSharedState : public QSharedData
+ 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 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>
{
- QQmlContextData *rootContext;
- QQmlContextData *creationContext;
+ 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;
- bool hadRequiredProperties;
+ QList<DeferredQPropertyBinding> allQPropertyBindings;
+ bool hadTopLevelRequiredProperties;
};
-class Q_QML_PRIVATE_EXPORT QQmlObjectCreator
+class Q_QML_EXPORT QQmlObjectCreator
{
Q_DECLARE_TR_FUNCTIONS(QQmlObjectCreator)
public:
- QQmlObjectCreator(QQmlContextData *parentContext, const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit, QQmlContextData *creationContext, QQmlIncubatorPrivate *incubator = nullptr);
+ QQmlObjectCreator(QQmlRefPointer<QQmlContextData> parentContext,
+ const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit,
+ const QQmlRefPointer<QQmlContextData> &creationContext,
+ QQmlIncubatorPrivate *incubator = nullptr);
~QQmlObjectCreator();
- QObject *create(int subComponentIndex = -1, QObject *parent = nullptr, QQmlInstantiationInterrupt *interrupt = nullptr);
+ enum CreationFlags { NormalObject = 1, InlineComponent = 2 };
+ QObject *create(int subComponentIndex = -1, QObject *parent = nullptr,
+ QQmlInstantiationInterrupt *interrupt = nullptr, int flags = NormalObject);
bool populateDeferredProperties(QObject *instance, const QQmlData::DeferredData *deferredData);
- void beginPopulateDeferred(QQmlContextData *context);
+ 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();
- QQmlContextData *finalize(QQmlInstantiationInterrupt &interrupt);
+ bool finalize(QQmlInstantiationInterrupt &interrupt);
void clear();
+ QQmlRefPointer<QQmlContextData> rootContext() const { return sharedState->rootContext; }
QQmlComponentAttached **componentAttachment() { return &sharedState->componentAttached; }
- QList<QQmlEnginePrivate::FinalizeCallback> *finalizeCallbacks() { return &sharedState->finalizeCallbacks; }
-
QList<QQmlError> errors;
- QQmlContextData *parentContextData() const { return parentContext.contextData(); }
- QFiniteStack<QPointer<QObject> > &allCreatedObjects() { return sharedState->allCreatedObjects; }
+ QQmlRefPointer<QQmlContextData> parentContextData() const
+ {
+ return parentContext.contextData();
+ }
+ QFiniteStack<QQmlGuard<QObject> > &allCreatedObjects() { return sharedState->allCreatedObjects; }
+
+ RequiredProperties *requiredProperties() {return &sharedState->requiredProperties;}
+ bool componentHadTopLevelRequiredProperties() const {return sharedState->hadTopLevelRequiredProperties;}
- RequiredProperties &requiredProperties() {return sharedState->requiredProperties;}
- bool componentHadRequiredProperties() const {return sharedState->hadRequiredProperties;}
+ 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(QQmlContextData *contextData, const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit, QQmlObjectCreatorSharedState *inheritedSharedState);
+ QQmlObjectCreator(QQmlRefPointer<QQmlContextData> contextData,
+ const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit,
+ QQmlObjectCreatorSharedState *inheritedSharedState,
+ bool isContextObject);
- void init(QQmlContextData *parentContext);
+ 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();
@@ -161,7 +209,6 @@ private:
void registerObjectWithContextById(const QV4::CompiledData::Object *object, QObject *instance) const;
inline QV4::QmlContext *currentQmlContext();
- Q_NEVER_INLINE void createQmlContext();
QV4::ResolvedTypeReference *resolvedType(int id) const
{
return compilationUnit->resolvedType(id);
@@ -181,10 +228,11 @@ private:
QQmlRefPointer<QV4::ExecutableCompilationUnit> compilationUnit;
const QV4::CompiledData::Unit *qmlUnit;
QQmlGuardedContextData parentContext;
- QQmlContextData *context;
+ QQmlRefPointer<QQmlContextData> context;
const QQmlPropertyCacheVector *propertyCaches;
- QExplicitlySharedDataPointer<QQmlObjectCreatorSharedState> sharedState;
+ QQmlRefPointer<QQmlObjectCreatorSharedState> sharedState;
bool topLevelCreator;
+ bool isContextObject;
QQmlIncubatorPrivate *incubator;
QObject *_qobject;
@@ -195,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;
@@ -204,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
@@ -213,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 1d4916d7d1..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"
@@ -44,14 +8,13 @@ QT_BEGIN_NAMESPACE
void QQmlObjectOrGadget::metacall(QMetaObject::Call type, int index, void **argv) const
{
if (ptr.isNull()) {
- const QMetaObject *metaObject = _m.asT2();
- metaObject->d.static_metacall(nullptr, type, index, argv);
+ _m->d.static_metacall(nullptr, type, index, argv);
}
else if (ptr.isT1()) {
QMetaObject::metacall(ptr.asT1(), type, index, argv);
}
else {
- const QMetaObject *metaObject = _m.asT1()->metaObject();
+ const QMetaObject *metaObject = _m;
QQmlMetaObject::resolveGadgetMethodOrPropertyIndex(type, &metaObject, &index);
metaObject->d.static_metacall(reinterpret_cast<QObject*>(ptr.asT2()), type, index, argv);
}
diff --git a/src/qml/qml/qqmlobjectorgadget_p.h b/src/qml/qml/qqmlobjectorgadget_p.h
index c5f5f58a3a..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
@@ -62,20 +27,21 @@ public:
: QQmlMetaObject(obj),
ptr(obj)
{}
- QQmlObjectOrGadget(QQmlPropertyCache *propertyCache, void *gadget)
- : QQmlMetaObject(propertyCache)
+ QQmlObjectOrGadget(const QMetaObject *metaObject, void *gadget)
+ : QQmlMetaObject(metaObject)
, ptr(gadget)
{}
+ QQmlObjectOrGadget(const QMetaObject* metaObject)
+ : QQmlMetaObject(metaObject)
+ {}
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;
-
-protected:
- QQmlObjectOrGadget(const QMetaObject* metaObject)
- : QQmlMetaObject(metaObject)
- {}
};
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlopenmetaobject.cpp b/src/qml/qml/qqmlopenmetaobject.cpp
index fe0946c6de..2d0a78c6cb 100644
--- a/src/qml/qml/qqmlopenmetaobject.cpp
+++ b/src/qml/qml/qqmlopenmetaobject.cpp
@@ -1,48 +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 <qqmlengine.h>
#include <qdebug.h>
+#include <QtCore/qpointer.h>
+#include <QtCore/qset.h>
QT_BEGIN_NAMESPACE
@@ -50,7 +17,7 @@ QT_BEGIN_NAMESPACE
class QQmlOpenMetaObjectTypePrivate
{
public:
- QQmlOpenMetaObjectTypePrivate() : mem(nullptr), cache(nullptr), engine(nullptr) {}
+ QQmlOpenMetaObjectTypePrivate() : mem(nullptr) {}
void init(const QMetaObject *metaObj);
@@ -59,15 +26,19 @@ public:
QHash<QByteArray, int> names;
QMetaObjectBuilder mob;
QMetaObject *mem;
- QQmlPropertyCache *cache;
- QQmlEngine *engine;
+
+ // 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;
};
-QQmlOpenMetaObjectType::QQmlOpenMetaObjectType(const QMetaObject *base, QQmlEngine *engine)
- : QQmlCleanup(engine), d(new QQmlOpenMetaObjectTypePrivate)
+QQmlOpenMetaObjectType::QQmlOpenMetaObjectType(const QMetaObject *base)
+ : d(new QQmlOpenMetaObjectTypePrivate)
{
- d->engine = engine;
d->init(base);
}
@@ -75,16 +46,9 @@ QQmlOpenMetaObjectType::~QQmlOpenMetaObjectType()
{
if (d->mem)
free(d->mem);
- if (d->cache)
- d->cache->release();
delete d;
}
-void QQmlOpenMetaObjectType::clear()
-{
- d->engine = nullptr;
-}
-
int QQmlOpenMetaObjectType::propertyOffset() const
{
return d->propertyOffset;
@@ -97,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) + "()");
@@ -136,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;
@@ -152,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);
}
@@ -166,7 +125,7 @@ void QQmlOpenMetaObjectTypePrivate::init(const QMetaObject *metaObj)
if (!mem) {
mob.setSuperClass(metaObj);
mob.setClassName(metaObj->className());
- mob.setFlags(QMetaObjectBuilder::DynamicMetaObject);
+ mob.setFlags(MetaObjectFlag::DynamicMetaObject);
mem = mob.toMetaObject();
@@ -180,8 +139,8 @@ void QQmlOpenMetaObjectTypePrivate::init(const QMetaObject *metaObj)
class QQmlOpenMetaObjectPrivate
{
public:
- QQmlOpenMetaObjectPrivate(QQmlOpenMetaObject *_q, bool _autoCreate, QObject *obj)
- : q(_q), object(obj), autoCreate(_autoCreate) {}
+ QQmlOpenMetaObjectPrivate(QQmlOpenMetaObject *_q, QObject *obj)
+ : q(_q), object(obj) {}
struct Property {
private:
@@ -191,7 +150,7 @@ public:
bool valueSet = false;
QVariant value() const {
- if (QMetaType::typeFlags(m_value.userType()) & QMetaType::PointerToQObject
+ if (m_value.metaType().flags() & QMetaType::PointerToQObject
&& qobjectTracker.isNull())
return QVariant::fromValue<QObject*>(nullptr);
return m_value;
@@ -200,19 +159,19 @@ public:
void setValue(const QVariant &v) {
m_value = v;
valueSet = true;
- if (QMetaType::typeFlags(v.userType()) & QMetaType::PointerToQObject)
+ if (v.metaType().flags() & QMetaType::PointerToQObject)
qobjectTracker = m_value.value<QObject*>();
}
};
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)
@@ -231,40 +190,47 @@ 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))
+ ddata->propertyCache.reset();
+ }
+
QQmlOpenMetaObject *q;
- QAbstractDynamicMetaObject *parent = nullptr;
+ QDynamicMetaObjectData *parent = nullptr;
QVector<Property> data;
QObject *object;
QQmlRefPointer<QQmlOpenMetaObjectType> type;
- bool autoCreate;
+ QVector<QByteArray> *deferredPropertyNames = nullptr;
+ bool autoCreate = true;
bool cacheProperties = false;
};
-QQmlOpenMetaObject::QQmlOpenMetaObject(QObject *obj, const QMetaObject *base, bool automatic)
-: d(new QQmlOpenMetaObjectPrivate(this, automatic, obj))
+QQmlOpenMetaObject::QQmlOpenMetaObject(QObject *obj, const QMetaObject *base)
+: d(new QQmlOpenMetaObjectPrivate(this, obj))
{
- d->type.adopt(new QQmlOpenMetaObjectType(base ? base : obj->metaObject(), nullptr));
+ d->type.adopt(new QQmlOpenMetaObjectType(base ? base : obj->metaObject()));
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, bool automatic)
-: d(new QQmlOpenMetaObjectPrivate(this, automatic, obj))
+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;
}
@@ -290,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);
@@ -301,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);
@@ -317,11 +288,21 @@ int QQmlOpenMetaObject::metaCall(QObject *o, QMetaObject::Call c, int id, void *
}
}
-QAbstractDynamicMetaObject *QQmlOpenMetaObject::parent() const
+QDynamicMetaObjectData *QQmlOpenMetaObject::parent() const
{
return d->parent;
}
+bool QQmlOpenMetaObject::checkedSetValue(int index, const QVariant &value, bool force)
+{
+ if (!force && d->propertyValue(index) == value)
+ return false;
+
+ d->setPropertyValue(index, value);
+ activate(d->object, index + d->type->d->signalOffset, nullptr);
+ return true;
+}
+
QVariant QQmlOpenMetaObject::value(int id) const
{
return d->propertyValue(id);
@@ -361,16 +342,43 @@ bool QQmlOpenMetaObject::setValue(const QByteArray &name, const QVariant &val, b
id = *iter;
}
- if (id >= 0) {
- if (!force && d->propertyValue(id) == val)
- return false;
+ if (id >= 0)
+ return checkedSetValue(id, val, force);
- d->setPropertyValue(id, val);
- activate(d->object, id + d->type->d->signalOffset, nullptr);
- return true;
+ return false;
+}
+
+void QQmlOpenMetaObject::setValues(const QHash<QByteArray, QVariant> &values, bool force)
+{
+ QVector<QByteArray> missingProperties;
+ d->deferredPropertyNames = &missingProperties;
+ const auto &names = d->type->d->names;
+
+ for (auto valueIt = values.begin(), end = values.end(); valueIt != end; ++valueIt) {
+ const auto nameIt = names.constFind(valueIt.key());
+ if (nameIt == names.constEnd()) {
+ const int id = createProperty(valueIt.key(), "") - d->type->d->propertyOffset;
+
+ // If id >= 0 some override of createProperty() created it. Then set it.
+ // Else it either ends up in missingProperties and we create it later
+ // or it cannot be created.
+
+ if (id >= 0)
+ checkedSetValue(id, valueIt.value(), force);
+ } else {
+ checkedSetValue(*nameIt, valueIt.value(), force);
+ }
}
- return false;
+ d->deferredPropertyNames = nullptr;
+ if (missingProperties.isEmpty())
+ return;
+
+ d->type->createProperties(missingProperties);
+ d->dropPropertyCache();
+
+ for (const QByteArray &name : std::as_const(missingProperties))
+ checkedSetValue(names[name], values[name], force);
}
// returns true if this value has been initialized by a call to either value() or setValue()
@@ -381,37 +389,47 @@ bool QQmlOpenMetaObject::hasValue(int id) const
void QQmlOpenMetaObject::setCached(bool c)
{
- if (c == d->cacheProperties || !d->type->d->engine)
+ if (c == d->cacheProperties)
return;
d->cacheProperties = 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();
}
}
+bool QQmlOpenMetaObject::autoCreatesProperties() const
+{
+ return d->autoCreate;
+}
+
+void QQmlOpenMetaObject::setAutoCreatesProperties(bool autoCreate)
+{
+ d->autoCreate = autoCreate;
+}
+
int QQmlOpenMetaObject::createProperty(const char *name, const char *)
{
if (d->autoCreate) {
- int result = d->type->createProperty(name);
-
- if (QQmlData *ddata = QQmlData::get(d->object, /*create*/false)) {
- if (ddata->propertyCache) {
- ddata->propertyCache->release();
- ddata->propertyCache = nullptr;
- }
+ if (d->deferredPropertyNames) {
+ // Defer the creation of new properties. See setValues(QHash<QByteArray, QVariant>)
+ d->deferredPropertyNames->append(name);
+ return -1;
}
+ const int result = d->type->createProperty(name);
+ d->dropPropertyCache();
return result;
} else
return -1;
@@ -445,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 168a2a6f7f..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
@@ -55,7 +19,6 @@
#include <QtCore/QObject>
#include <private/qqmlrefcount_p.h>
-#include <private/qqmlcleanup_p.h>
#include <private/qtqmlglobal_p.h>
#include <private/qobject_p.h>
@@ -65,11 +28,12 @@ QT_BEGIN_NAMESPACE
class QQmlEngine;
class QMetaPropertyBuilder;
class QQmlOpenMetaObjectTypePrivate;
-class Q_QML_PRIVATE_EXPORT QQmlOpenMetaObjectType : public QQmlRefCount, public QQmlCleanup
+class Q_QML_EXPORT QQmlOpenMetaObjectType final
+ : public QQmlRefCounted<QQmlOpenMetaObjectType>
{
public:
- QQmlOpenMetaObjectType(const QMetaObject *base, QQmlEngine *engine);
- ~QQmlOpenMetaObjectType() override;
+ QQmlOpenMetaObjectType(const QMetaObject *base);
+ ~QQmlOpenMetaObjectType();
void createProperties(const QVector<QByteArray> &names);
int createProperty(const QByteArray &name);
@@ -79,11 +43,9 @@ public:
int propertyCount() const;
QByteArray propertyName(int) const;
- QMetaObject *metaObject() const;
protected:
virtual void propertyCreated(int, QMetaPropertyBuilder &);
- void clear() override;
private:
QQmlOpenMetaObjectTypePrivate *d;
@@ -92,15 +54,16 @@ private:
};
class QQmlOpenMetaObjectPrivate;
-class Q_QML_PRIVATE_EXPORT QQmlOpenMetaObject : public QAbstractDynamicMetaObject
+class Q_QML_EXPORT QQmlOpenMetaObject : public QAbstractDynamicMetaObject
{
public:
- QQmlOpenMetaObject(QObject *, const QMetaObject * = nullptr, bool = true);
- QQmlOpenMetaObject(QObject *, QQmlOpenMetaObjectType *, bool = true);
+ QQmlOpenMetaObject(QObject *, const QMetaObject * = nullptr);
+ QQmlOpenMetaObject(QObject *, const QQmlRefPointer<QQmlOpenMetaObjectType> &);
~QQmlOpenMetaObject() override;
QVariant value(const QByteArray &) const;
bool setValue(const QByteArray &, const QVariant &, bool force = false);
+ void setValues(const QHash<QByteArray, QVariant> &, bool force = false);
QVariant value(int) const;
void setValue(int, const QVariant &);
QVariant &valueRef(const QByteArray &);
@@ -116,9 +79,13 @@ public:
// longer automatically called for new properties.
void setCached(bool);
+ bool autoCreatesProperties() const;
+ void setAutoCreatesProperties(bool autoCreate);
+
QQmlOpenMetaObjectType *type() const;
void emitPropertyNotification(const QByteArray &propertyName);
+ void unparent();
protected:
int metaCall(QObject *o, QMetaObject::Call _c, int _id, void **_a) override;
@@ -130,7 +97,9 @@ 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);
private:
QQmlOpenMetaObjectPrivate *d;
diff --git a/src/qml/qml/qqmlparserstatus.cpp b/src/qml/qml/qqmlparserstatus.cpp
index b8f4bb8c19..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"
@@ -68,19 +32,7 @@ QT_BEGIN_NAMESPACE
To use QQmlParserStatus, you must inherit both a QObject-derived class
and QQmlParserStatus, and use the Q_INTERFACES() macro.
- \code
- class MyObject : public QObject, public QQmlParserStatus
- {
- Q_OBJECT
- Q_INTERFACES(QQmlParserStatus)
-
- public:
- MyObject(QObject *parent = 0);
- ...
- void classBegin();
- void componentComplete();
- }
- \endcode
+ \snippet code/src_qml_qqmlparserstatus.cpp 0
*/
/*! \internal */
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 0acf20bbb4..dd52ee2090 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"
@@ -58,22 +22,27 @@ QQmlPlatform::~QQmlPlatform()
QString QQmlPlatform::os()
{
+ // ### Qt7: Consider implementing in terms of QSysInfo
+
#if defined(Q_OS_ANDROID)
return QStringLiteral("android");
#elif defined(Q_OS_IOS)
return QStringLiteral("ios");
#elif defined(Q_OS_TVOS)
return QStringLiteral("tvos");
-#elif defined(Q_OS_MAC)
+#elif defined(Q_OS_VISIONOS)
+ return QStringLiteral("visionos");
+#elif defined(Q_OS_MACOS)
+ // ### Qt7: Replace with "macos"
return QStringLiteral("osx");
-#elif defined(Q_OS_WINRT)
- return QStringLiteral("winrt");
#elif defined(Q_OS_WIN)
return QStringLiteral("windows");
#elif defined(Q_OS_LINUX)
return QStringLiteral("linux");
#elif defined(Q_OS_QNX)
return QStringLiteral("qnx");
+#elif defined(Q_OS_WASM)
+ return QStringLiteral("wasm");
#elif defined(Q_OS_UNIX)
return QStringLiteral("unix");
#else
diff --git a/src/qml/qml/qqmlplatform_p.h b/src/qml/qml/qqmlplatform_p.h
index af33dffca3..9905f6330c 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,11 +21,12 @@
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)
Q_PROPERTY(QString pluginName READ pluginName CONSTANT)
+ QML_ANONYMOUS
public:
explicit QQmlPlatform(QObject *parent = nullptr);
@@ -76,6 +41,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..091cd28b73
--- /dev/null
+++ b/src/qml/qml/qqmlpluginimporter.cpp
@@ -0,0 +1,610 @@
+// 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
+
+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 9504fc37dc..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,39 +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/qtqmlglobal.h>
+#include <QtCore/qdatetime.h>
+#include <QtCore/qdebug.h>
#include <QtCore/qglobal.h>
-#include <QtCore/qvariant.h>
-#include <QtCore/qurl.h>
-#include <QtCore/qpointer.h>
-
+#include <QtCore/qmetacontainer.h>
#include <QtCore/qmetaobject.h>
-#include <QtCore/qdebug.h>
+#include <QtCore/qpointer.h>
+#include <QtCore/qurl.h>
+#include <QtCore/qvariant.h>
+#include <QtCore/qversionnumber.h>
-#define QML_GETTYPENAMES \
- const char *className = T::staticMetaObject.className(); \
- const int nameLen = int(strlen(className)); \
- QVarLengthArray<char,48> pointerName(nameLen+2); \
- memcpy(pointerName.data(), className, size_t(nameLen)); \
- pointerName[nameLen] = '*'; \
- pointerName[nameLen+1] = '\0'; \
- const int listLen = int(strlen("QQmlListProperty<")); \
- QVarLengthArray<char,64> listName(listLen + nameLen + 2); \
- memcpy(listName.data(), "QQmlListProperty<", size_t(listLen)); \
- memcpy(listName.data()+listLen, className, size_t(nameLen)); \
- listName[listLen+nameLen] = '>'; \
- listName[listLen+nameLen+1] = '\0';
+#include <functional>
+#include <limits>
+#include <type_traits>
QT_BEGIN_NAMESPACE
class QQmlPropertyValueInterceptor;
+class QQmlContextData;
+class QQmlFinalizerHook;
namespace QQmlPrivate {
struct CachedQmlUnit;
@@ -93,9 +50,9 @@ using QQmlAttachedPropertiesFunc = A *(*)(QObject *);
namespace QV4 {
struct ExecutionEngine;
+class ExecutableCompilationUnit;
namespace CompiledData {
struct Unit;
-struct CompilationUnit;
}
}
namespace QmlIR {
@@ -105,7 +62,7 @@ typedef void (*IRLoaderFunction)(Document *, const QQmlPrivate::CachedQmlUnit *)
using QQmlAttachedPropertiesFunc = QQmlPrivate::QQmlAttachedPropertiesFunc<QObject>;
-inline uint qHash(QQmlAttachedPropertiesFunc func, uint seed = 0)
+inline size_t qHash(QQmlAttachedPropertiesFunc func, size_t seed = 0)
{
return qHash(quintptr(func), seed);
}
@@ -120,10 +77,14 @@ public:
};
-class QJSValue;
class QJSEngine;
class QQmlEngine;
class QQmlCustomParser;
+class QQmlTypeNotAvailable;
+
+class QQmlV4Function;
+using QQmlV4FunctionPtr = QQmlV4Function *;
+using QQmlV4ExecutionEnginePtr = QV4::ExecutionEngine *;
template<class T>
QQmlCustomParser *qmlCreateCustomParser()
@@ -149,67 +110,202 @@ 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
};
- template<typename T>
- constexpr bool isConstructible()
+ enum class SingletonConstructionMode
{
- return std::is_default_constructible<T>::value && std::is_base_of<QObject, T>::value;
+ None,
+ Constructor,
+ Factory,
+ FactoryWrapper
+ };
+
+ template<typename T, typename WrapperT = T, typename = std::void_t<>>
+ struct HasSingletonFactory
+ {
+ static constexpr bool value = false;
+ };
+
+ template<typename T, typename WrapperT>
+ struct HasSingletonFactory<T, WrapperT, std::void_t<decltype(WrapperT::create(
+ static_cast<QQmlEngine *>(nullptr),
+ static_cast<QJSEngine *>(nullptr)))>>
+ {
+ static constexpr bool value = std::is_same_v<
+ decltype(WrapperT::create(static_cast<QQmlEngine *>(nullptr),
+ static_cast<QJSEngine *>(nullptr))), T *>;
+ };
+
+ template<typename T, typename WrapperT>
+ constexpr SingletonConstructionMode singletonConstructionMode()
+ {
+ if constexpr (!std::is_base_of<QObject, T>::value)
+ return SingletonConstructionMode::None;
+ if constexpr (!std::is_same_v<T, WrapperT> && HasSingletonFactory<T, WrapperT>::value)
+ return SingletonConstructionMode::FactoryWrapper;
+ if constexpr (std::is_default_constructible<T>::value)
+ return SingletonConstructionMode::Constructor;
+ if constexpr (HasSingletonFactory<T>::value)
+ return SingletonConstructionMode::Factory;
+
+ return SingletonConstructionMode::None;
}
- template<typename T>
- void createInto(void *memory) { new (memory) QQmlElement<T>; }
+ 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>
- QObject *createSingletonInstance(QQmlEngine *, QJSEngine *) { return new T; }
+ void createInto(void *memory, void *) { new (memory) QQmlElement<T>; }
+
+ template<typename T, typename WrapperT, SingletonConstructionMode Mode>
+ QObject *createSingletonInstance(QQmlEngine *q, QJSEngine *j)
+ {
+ Q_UNUSED(q);
+ Q_UNUSED(j);
+ if constexpr (Mode == SingletonConstructionMode::Constructor)
+ return new T;
+ else if constexpr (Mode == SingletonConstructionMode::Factory)
+ return T::create(q, j);
+ else if constexpr (Mode == SingletonConstructionMode::FactoryWrapper)
+ return WrapperT::create(q, j);
+ else
+ return nullptr;
+ }
template<typename T>
QObject *createParent(QObject *p) { return new T(p); }
- using CreateIntoFunction = void (*)(void *);
+ using CreateIntoFunction = void (*)(void *, void *);
using CreateSingletonFunction = QObject *(*)(QQmlEngine *, QJSEngine *);
using CreateParentFunction = QObject *(*)(QObject *);
+ using CreateValueTypeFunction = QVariant (*)(const QJSValue &);
- template<typename T, bool Constructible = isConstructible<T>()>
+ template<typename T, typename WrapperT = T,
+ SingletonConstructionMode Mode = singletonConstructionMode<T, WrapperT>()>
struct Constructors;
- template<typename T>
- struct Constructors<T, true>
+ template<typename T, typename WrapperT>
+ struct Constructors<T, WrapperT, SingletonConstructionMode::Constructor>
{
static constexpr CreateIntoFunction createInto
= QQmlPrivate::createInto<T>;
static constexpr CreateSingletonFunction createSingletonInstance
- = QQmlPrivate::createSingletonInstance<T>;
+ = QQmlPrivate::createSingletonInstance<
+ T, WrapperT, SingletonConstructionMode::Constructor>;
};
- template<typename T>
- struct Constructors<T, false>
+ template<typename T, typename WrapperT>
+ struct Constructors<T, WrapperT, SingletonConstructionMode::None>
{
static constexpr CreateIntoFunction createInto = nullptr;
static constexpr CreateSingletonFunction createSingletonInstance = nullptr;
};
- template<typename T, bool IsVoid = std::is_void<T>::value>
+ template<typename T, typename WrapperT>
+ struct Constructors<T, WrapperT, SingletonConstructionMode::Factory>
+ {
+ static constexpr CreateIntoFunction createInto = nullptr;
+ static constexpr CreateSingletonFunction createSingletonInstance
+ = QQmlPrivate::createSingletonInstance<
+ T, WrapperT, SingletonConstructionMode::Factory>;
+ };
+
+ template<typename T, typename WrapperT>
+ struct Constructors<T, WrapperT, SingletonConstructionMode::FactoryWrapper>
+ {
+ static constexpr CreateIntoFunction createInto = nullptr;
+ static constexpr CreateSingletonFunction createSingletonInstance
+ = QQmlPrivate::createSingletonInstance<
+ T, WrapperT, SingletonConstructionMode::FactoryWrapper>;
+ };
+
+ template<typename T,
+ bool IsObject = std::is_base_of<QObject, T>::value,
+ bool IsGadget = QtPrivate::IsGadgetHelper<T>::IsRealGadget>
struct ExtendedType;
- // void means "not an extended type"
template<typename T>
- struct ExtendedType<T, true>
+ struct ExtendedType<T, false, false>
{
static constexpr const CreateParentFunction createParent = nullptr;
- static constexpr const QMetaObject *staticMetaObject = nullptr;
+ static const QMetaObject *staticMetaObject() { return nullptr; }
};
- // If it's not void, we actually want an error if the ctor or the metaobject is missing.
+ // If it's a QObject, we actually want an error if the ctor or the metaobject is missing.
template<typename T>
- struct ExtendedType<T, false>
+ struct ExtendedType<T, true, false>
{
static constexpr const CreateParentFunction createParent = QQmlPrivate::createParent<T>;
- static constexpr const QMetaObject *staticMetaObject = &T::staticMetaObject;
+ static const QMetaObject *staticMetaObject() { return &T::staticMetaObject; }
+ };
+
+ // If it's a Q_GADGET, we don't want the ctor.
+ template<typename T>
+ struct ExtendedType<T, false, true>
+ {
+ static constexpr const CreateParentFunction createParent = nullptr;
+ static const QMetaObject *staticMetaObject() { return &T::staticMetaObject; }
+ };
+
+ template<typename F, typename Result = void>
+ struct ValueTypeFactory
+ {
+ static constexpr const Result (*create)(const QJSValue &) = nullptr;
+ };
+
+ template<typename F>
+ struct ValueTypeFactory<F, std::void_t<decltype(F::create(QJSValue()))>>
+ {
+ static decltype(F::create(QJSValue())) create(const QJSValue &params)
+ {
+ return F::create(params);
+ }
+ };
+
+ template<typename T, typename F,
+ bool HasCtor = std::is_constructible_v<T, QJSValue>,
+ bool HasFactory = std::is_constructible_v<
+ QVariant, decltype(ValueTypeFactory<F>::create(QJSValue()))>>
+ struct ValueType;
+
+ template<typename T, typename F>
+ struct ValueType<T, F, false, false>
+ {
+ static constexpr const CreateValueTypeFunction create = nullptr;
+ };
+
+ template<typename T, typename F, bool HasCtor>
+ struct ValueType<T, F, HasCtor, true>
+ {
+ static QVariant create(const QJSValue &params)
+ {
+ return F::create(params);
+ }
+ };
+
+ template<typename T, typename F>
+ struct ValueType<T, F, true, false>
+ {
+ static QVariant create(const QJSValue &params)
+ {
+ return QVariant::fromValue(T(params));
+ }
};
template<class From, class To, int N>
@@ -239,9 +335,6 @@ namespace QQmlPrivate
}
};
- template<typename...>
- using QmlVoidT = void;
-
// You can prevent subclasses from using the same attached type by specialzing this.
// This is reserved for internal types, though.
template<class T, class A>
@@ -250,7 +343,7 @@ namespace QQmlPrivate
using Type = A;
};
- template<class T, class = QmlVoidT<>, bool OldStyle = QQmlTypeInfo<T>::hasAttachedProperties>
+ template<class T, class = std::void_t<>, bool OldStyle = QQmlTypeInfo<T>::hasAttachedProperties>
struct QmlAttached
{
using Type = void;
@@ -261,7 +354,7 @@ namespace QQmlPrivate
// Defined inline via QML_ATTACHED
template<class T>
- struct QmlAttached<T, QmlVoidT<typename OverridableAttachedType<T, typename T::QmlAttachedType>::Type>, false>
+ struct QmlAttached<T, std::void_t<typename OverridableAttachedType<T, typename T::QmlAttachedType>::Type>, false>
{
// Normal attached properties
template <typename Parent, typename Attached>
@@ -277,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()
@@ -297,7 +392,7 @@ namespace QQmlPrivate
// Separately defined via QQmlTypeInfo
template<class T>
- struct QmlAttached<T, QmlVoidT<decltype(T::qmlAttachedProperties)>, true>
+ struct QmlAttached<T, std::void_t<decltype(T::qmlAttachedProperties)>, true>
{
using Type = typename std::remove_pointer<decltype(T::qmlAttachedProperties(nullptr))>::type;
using Func = QQmlAttachedPropertiesFunc<Type>;
@@ -341,18 +436,33 @@ namespace QQmlPrivate
enum AutoParentResult { Parented, IncompatibleObject, IncompatibleParent };
typedef AutoParentResult (*AutoParentFunction)(QObject *object, QObject *parent);
+ enum class ValueTypeCreationMethod { None, Construct, Structured };
+
struct RegisterType {
- int version;
+ enum StructVersion: int {
+ Base = 0,
+ FinalizerCast = 1,
+ CreationMethod = 2,
+ CurrentVersion = CreationMethod,
+ };
+
+ bool has(StructVersion v) const { return structVersion >= int(v); }
- int typeId;
- int listId;
+ int structVersion;
+
+ QMetaType typeId;
+ QMetaType listId;
int objectSize;
- void (*create)(void *);
+ // The second parameter of create is for userdata
+ void (*create)(void *, void *);
+ void *userdata;
QString noCreationReason;
+ // ### Qt7: Get rid of this. It can be covered by creationMethod below.
+ QVariant (*createValueType)(const QJSValue &);
+
const char *uri;
- int versionMajor;
- int versionMinor;
+ QTypeRevision version;
const char *elementName;
const QMetaObject *metaObject;
@@ -368,20 +478,26 @@ namespace QQmlPrivate
QQmlCustomParser *customParser;
- int revision;
+ QTypeRevision revision;
+ int finalizerCast;
+
+ ValueTypeCreationMethod creationMethod;
// If this is extended ensure "version" is bumped!!!
};
struct RegisterTypeAndRevisions {
- int version;
+ int structVersion;
- int typeId;
- int listId;
+ QMetaType typeId;
+ QMetaType listId;
int objectSize;
- void (*create)(void *);
+ void (*create)(void *, void *);
+ void *userdata;
+
+ QVariant (*createValueType)(const QJSValue &);
const char *uri;
- int versionMajor;
+ QTypeRevision version;
const QMetaObject *metaObject;
const QMetaObject *classInfoMetaObject;
@@ -397,78 +513,253 @@ namespace QQmlPrivate
const QMetaObject *extensionMetaObject;
QQmlCustomParser *(*customParserFactory)();
+ QVector<int> *qmlTypeIds;
+ int finalizerCast;
+
+ bool forceAnonymous;
+ QMetaSequence listMetaSequence;
};
struct RegisterInterface {
- int version;
+ int structVersion;
- int typeId;
- int listId;
+ QMetaType typeId;
+ QMetaType listId;
const char *iid;
+
+ const char *uri;
+ QTypeRevision version;
};
struct RegisterAutoParent {
- int version;
+ int structVersion;
AutoParentFunction function;
};
struct RegisterSingletonType {
- int version;
+ int structVersion;
const char *uri;
- int versionMajor;
- int versionMinor;
+ QTypeRevision version;
const char *typeName;
- QJSValue (*scriptApi)(QQmlEngine *, QJSEngine *);
- QObject *(*qobjectApi)(QQmlEngine *, QJSEngine *);
- const QMetaObject *instanceMetaObject; // new in version 1
- int typeId; // new in version 2
- int revision; // new in version 2
- std::function<QObject*(QQmlEngine *, QJSEngine *)> generalizedQobjectApi; // new in version 3
- // If this is extended ensure "version" is bumped!!!
+ std::function<QJSValue(QQmlEngine *, QJSEngine *)> scriptApi;
+ std::function<QObject*(QQmlEngine *, QJSEngine *)> qObjectApi;
+
+ const QMetaObject *instanceMetaObject;
+ QMetaType typeId;
+
+ QObject *(*extensionObjectCreate)(QObject *);
+ const QMetaObject *extensionMetaObject;
+
+ QTypeRevision revision;
};
struct RegisterSingletonTypeAndRevisions {
- int version;
+ int structVersion;
const char *uri;
- int versionMajor;
+ QTypeRevision version;
+
+ std::function<QObject*(QQmlEngine *, QJSEngine *)> qObjectApi;
- QJSValue (*scriptApi)(QQmlEngine *, QJSEngine *);
const QMetaObject *instanceMetaObject;
const QMetaObject *classInfoMetaObject;
- int typeId;
- std::function<QObject*(QQmlEngine *, QJSEngine *)> generalizedQobjectApi; // new in version 3
+ QMetaType typeId;
+
+ QObject *(*extensionObjectCreate)(QObject *);
+ const QMetaObject *extensionMetaObject;
+
+ QVector<int> *qmlTypeIds;
};
struct RegisterCompositeType {
+ int structVersion;
QUrl url;
const char *uri;
- int versionMajor;
- int versionMinor;
+ QTypeRevision version;
const char *typeName;
};
struct RegisterCompositeSingletonType {
+ int structVersion;
QUrl url;
const char *uri;
- int versionMajor;
- int versionMinor;
+ QTypeRevision version;
const char *typeName;
};
+ struct RegisterSequentialContainer {
+ 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;
+ };
+
+ struct RegisterSequentialContainerAndRevisions {
+ int structVersion;
+ const char *uri;
+ QTypeRevision version;
+
+ const QMetaObject *classInfoMetaObject;
+ QMetaType typeId;
+ QMetaSequence metaSequence;
+
+ QVector<int> *qmlTypeIds;
+ };
+
+ struct Q_QML_EXPORT AOTCompiledContext {
+ enum: uint { InvalidStringId = (std::numeric_limits<uint>::max)() };
+
+ QQmlContextData *qmlContext;
+ QObject *qmlScopeObject;
+ QJSEngine *engine;
+ 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 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;
- void *unused1;
+ const AOTCompiledFunction *aotCompiledFunctions;
void *unused2;
};
typedef const CachedQmlUnit *(*QmlUnitCacheLookupFunction)(const QUrl &url);
struct RegisterQmlUnitCacheHook {
- int version;
+ int structVersion;
QmlUnitCacheLookupFunction lookupCachedQmlUnit;
};
@@ -481,26 +772,45 @@ namespace QQmlPrivate
CompositeSingletonRegistration = 5,
QmlUnitCacheHookRegistration = 6,
TypeAndRevisionsRegistration = 7,
- SingletonAndRevisionsRegistration = 8
+ SingletonAndRevisionsRegistration = 8,
+ SequentialContainerRegistration = 9,
+ SequentialContainerAndRevisionsRegistration = 10,
};
int Q_QML_EXPORT qmlregister(RegistrationType, void *);
void Q_QML_EXPORT qmlunregister(RegistrationType, quintptr);
- struct Q_QML_EXPORT RegisterSingletonFunctor
+
+#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;
}
@@ -512,92 +822,229 @@ namespace QQmlPrivate
return metaObject->classInfo(indexOfOwnClassInfo(metaObject, key)).value();
}
- inline int intClassInfo(const QMetaObject *metaObject, const char *key, int defaultValue = 0)
+ inline QTypeRevision revisionClassInfo(const QMetaObject *metaObject, const char *key,
+ QTypeRevision defaultValue = QTypeRevision())
{
const int index = indexOfOwnClassInfo(metaObject, key);
return (index == -1) ? defaultValue
- : QByteArray(metaObject->classInfo(index).value()).toInt();
+ : QTypeRevision::fromEncodedVersion(
+ 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");
+ if (index == -1)
+ return defaultValue;
+ return qstrcmp(metaObject->classInfo(index).value(), "true") == 0;
}
- inline const char *classElementName(const QMetaObject *metaObject)
+ template<class T, class = std::void_t<>>
+ struct QmlExtended
{
- const char *elementName = classInfo(metaObject, "QML.Element");
- if (qstrcmp(elementName, "auto") == 0)
- return metaObject->className();
- if (qstrcmp(elementName, "anonymous") == 0)
- return nullptr;
-
- if (!elementName || elementName[0] < 'A' || elementName[0] > 'Z') {
- qWarning() << "Missing or unusable QML.Element class info \"" << elementName << "\""
- << "for" << metaObject->className();
- }
+ using Type = void;
+ };
- return elementName;
- }
+ template<class T>
+ struct QmlExtended<T, std::void_t<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 = QmlVoidT<>>
- struct QmlExtended
+ template<class T, class = std::void_t<>>
+ struct QmlExtendedNamespace
{
- using Type = void;
+ static constexpr const QMetaObject *metaObject() { return nullptr; }
};
template<class T>
- struct QmlExtended<T, QmlVoidT<typename T::QmlExtendedType>>
+ struct QmlExtendedNamespace<T, std::void_t<decltype(T::qmlExtendedNamespace())>>
{
- using Type = typename T::QmlExtendedType;
+ 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 = QmlVoidT<>>
+ template<class T, class = std::void_t<>>
struct QmlResolved
{
using Type = T;
};
template<class T>
- struct QmlResolved<T, QmlVoidT<typename T::QmlForeignType>>
+ struct QmlResolved<T, std::void_t<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>>
{
- using Type = typename T::QmlForeignType;
+ static constexpr bool Value =
+ QmlTypeHasMarker<T, decltype(&T::qt_qmlMarker_anonymous)>::value
+ && bool(T::QmlIsAnonymous::yes);
};
- template<class T, class = QmlVoidT<>>
+
+ template<class T, class = std::void_t<>>
struct QmlSingleton
{
static constexpr bool Value = false;
};
template<class T>
- struct QmlSingleton<T, QmlVoidT<typename T::QmlIsSingleton>>
+ 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<typename T>
- void qmlRegisterSingletonAndRevisions(const char *uri, int versionMajor,
- const QMetaObject *classInfoMetaObject)
+ template<class T, class = std::void_t<>>
+ struct QmlSequence
+ {
+ static constexpr bool Value = false;
+ };
+
+ template<class T>
+ struct QmlSequence<T, std::void_t<typename T::QmlIsSequence>>
+ {
+ Q_STATIC_ASSERT((std::is_same_v<typename T::QmlSequenceValueType,
+ typename QmlResolved<T>::Type::value_type>));
+ static constexpr bool Value = bool(T::QmlIsSequence::yes);
+ };
+
+ template<class T, class = std::void_t<>>
+ struct QmlInterface
+ {
+ static constexpr bool Value = false;
+ };
+
+ template<class T>
+ struct QmlInterface<T, std::void_t<typename T::QmlIsInterface, decltype(qobject_interface_iid<T *>())>>
{
- QML_GETTYPENAMES
+ static constexpr bool Value = bool(T::QmlIsInterface::yes);
+ };
+
+ template<class T, typename = std::void_t<>>
+ struct StaticMetaObject
+ {
+ static const QMetaObject *staticMetaObject() { return nullptr; }
+ };
+
+ template<class T>
+ struct StaticMetaObject<T, std::void_t<decltype(T::staticMetaObject)>>
+ {
+ static const QMetaObject *staticMetaObject() { return &T::staticMetaObject; }
+ };
+
+ template<class T>
+ struct QmlMetaType
+ {
+ 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*>();
+ else
+ return QMetaType::fromType<T>();
+ }
+
+ static constexpr QMetaType list()
+ {
+ if constexpr (std::is_base_of_v<QObject, T>)
+ return QMetaType::fromType<QQmlListProperty<T>>();
+ else
+ 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,
uri,
- versionMajor,
+ QTypeRevision::fromMajorVersion(versionMajor),
- nullptr,
+ Constructors<T, WrapperT>::createSingletonInstance,
- &T::staticMetaObject,
+ StaticMetaObject<T>::staticMetaObject(),
classInfoMetaObject,
- qRegisterNormalizedMetaType<T *>(pointerName.constData()),
- Constructors<T>::createSingletonInstance
+ QmlMetaType<T>::self(),
+
+ ExtendedType<E>::createParent,
+ extension ? extension : ExtendedType<E>::staticMetaObject(),
+
+ qmlTypeIds
};
qmlregister(SingletonAndRevisionsRegistration, &api);
@@ -605,21 +1052,23 @@ namespace QQmlPrivate
template<typename T, typename E>
void qmlRegisterTypeAndRevisions(const char *uri, int versionMajor,
- const QMetaObject *classInfoMetaObject)
+ const QMetaObject *classInfoMetaObject,
+ QVector<int> *qmlTypeIds, const QMetaObject *extension,
+ bool forceAnonymous = false)
{
- QML_GETTYPENAMES
-
RegisterTypeAndRevisions type = {
- 0,
- qRegisterNormalizedMetaType<T *>(pointerName.constData()),
- qRegisterNormalizedMetaType<QQmlListProperty<T> >(listName.constData()),
- int(sizeof(T)),
+ 3,
+ QmlMetaType<T>::self(),
+ QmlMetaType<T>::list(),
+ QmlMetaType<T>::size(),
Constructors<T>::createInto,
+ nullptr,
+ ValueType<T, E>::create,
uri,
- versionMajor,
+ QTypeRevision::fromMajorVersion(versionMajor),
- &T::staticMetaObject,
+ StaticMetaObject<T>::staticMetaObject(),
classInfoMetaObject,
attachedPropertiesFunc<T>(),
@@ -630,15 +1079,89 @@ namespace QQmlPrivate
StaticCastSelector<T, QQmlPropertyValueInterceptor>::cast(),
ExtendedType<E>::createParent,
- ExtendedType<E>::staticMetaObject,
+ extension ? extension : ExtendedType<E>::staticMetaObject(),
- &qmlCreateCustomParser<T>
+ &qmlCreateCustomParser<T>,
+ 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);
}
+
+ template<typename T>
+ void qmlRegisterSequenceAndRevisions(const char *uri, int versionMajor,
+ const QMetaObject *classInfoMetaObject,
+ QVector<int> *qmlTypeIds)
+ {
+ RegisterSequentialContainerAndRevisions type = {
+ 0,
+ uri,
+ QTypeRevision::fromMajorVersion(versionMajor),
+ classInfoMetaObject,
+ QMetaType::fromType<T>(),
+ QMetaSequence::fromContainer<T>(),
+ qmlTypeIds
+ };
+
+ qmlregister(SequentialContainerAndRevisionsRegistration, &type);
+ }
+
+ template<>
+ void Q_QML_EXPORT qmlRegisterTypeAndRevisions<QQmlTypeNotAvailable, void>(
+ const char *uri, int versionMajor, const QMetaObject *classInfoMetaObject,
+ QVector<int> *qmlTypeIds, const QMetaObject *, bool);
+
+ constexpr QtPrivate::QMetaTypeInterface metaTypeForNamespace(
+ const QtPrivate::QMetaTypeInterface::MetaObjectFn &metaObjectFunction, const char *name)
+ {
+ return {
+ /*.revision=*/ 0,
+ /*.alignment=*/ 0,
+ /*.size=*/ 0,
+ /*.flags=*/ 0,
+ /*.typeId=*/ {},
+ /*.metaObject=*/ metaObjectFunction,
+ /*.name=*/ name,
+ /*.defaultCtr=*/ nullptr,
+ /*.copyCtr=*/ nullptr,
+ /*.moveCtr=*/ nullptr,
+ /*.dtor=*/ nullptr,
+ /*.equals*/ nullptr,
+ /*.lessThan*/ nullptr,
+ /*.debugStream=*/ nullptr,
+ /*.dataStreamOut=*/ nullptr,
+ /*.dataStreamIn=*/ nullptr,
+ /*.legacyRegisterOp=*/ nullptr
+ };
+ }
+
+ 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 eff3e94fbd..7c78fbb984 100644
--- a/src/qml/qml/qqmlproperty.cpp
+++ b/src/qml/qml/qqmlproperty.cpp
@@ -1,77 +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 <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
@@ -116,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()
@@ -148,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);
}
@@ -162,7 +125,6 @@ QQmlProperty::QQmlProperty(QObject *obj, QQmlContext *ctxt)
QQmlProperty::QQmlProperty(QObject *obj, QQmlEngine *engine)
: d(new QQmlPropertyPrivate)
{
- d->context = nullptr;
d->engine = engine;
d->initDefault(obj);
}
@@ -201,10 +163,17 @@ 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->engine = nullptr; }
+ if (!isValid()) {
+ d->object = nullptr;
+ d->context.reset();
+ d->engine = nullptr;
+ }
}
/*!
@@ -215,82 +184,97 @@ QQmlProperty::QQmlProperty(QObject *obj, const QString &name, QQmlContext *ctxt)
QQmlProperty::QQmlProperty(QObject *obj, const QString &name, QQmlEngine *engine)
: d(new QQmlPropertyPrivate)
{
- d->context = nullptr;
d->engine = engine;
d->initProperty(obj, name);
- if (!isValid()) { d->object = nullptr; d->context = nullptr; d->engine = nullptr; }
+ if (!isValid()) {
+ d->object = nullptr;
+ d->context.reset();
+ d->engine = nullptr;
+ }
}
-QQmlProperty QQmlPropertyPrivate::create(QObject *target, const QString &propertyName, QQmlContextData *context)
+QQmlProperty QQmlPropertyPrivate::create(QObject *target, const QString &propertyName,
+ 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->engine = context ? context->engine() : nullptr;
+ d->initProperty(target, propertyName, flags);
if (!result.isValid()) {
d->object = nullptr;
- d->context = nullptr;
+ d->context.reset();
d->engine = nullptr;
}
return result;
}
-QQmlPropertyPrivate::QQmlPropertyPrivate()
-: context(nullptr), engine(nullptr), object(nullptr), isNameCached(false)
+bool QQmlPropertyPrivate::resolveUrlsOnAssignment()
{
+ return ::compatResolveUrlsOnAssigment();
}
-QQmlContextData *QQmlPropertyPrivate::effectiveContext() const
+QQmlRefPointer<QQmlContextData> QQmlPropertyPrivate::effectiveContext() const
{
- if (context) return context;
- else if (engine) return QQmlContextData::get(engine->rootContext());
- else return nullptr;
+ if (context)
+ return context;
+ else if (engine)
+ return QQmlContextData::get(engine->rootContext());
+ else
+ 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;
+ QQmlRefPointer<QQmlTypeNameCache> typeNameCache = context ? context->imports() : nullptr;
QObject *currentObject = obj;
- QVector<QStringRef> path;
- QStringRef terminal(&name);
+ QList<QStringView> path;
+ QStringView terminal(name);
if (name.contains(QLatin1Char('.'))) {
- path = name.splitRef(QLatin1Char('.'));
+ path = QStringView{name}.split(QLatin1Char('.'));
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) {
- const QStringRef &pathName = path.at(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
- ++ii; r = typeNameCache->query(path.at(ii), r.importNamespace);
- if (!r.type.isValid()) return; // Invalid type in 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);
+
+ 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
@@ -303,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) && QQmlValueTypeFactory::isValueType(property->propType())) {
+ if (ii == (path.size() - 2) && QQmlMetaType::isValueType(property->propType())) {
// We're now at a value type property
- const QMetaObject *valueTypeMetaObject = QQmlValueTypeFactory::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());
@@ -320,21 +323,25 @@ void QQmlPropertyPrivate::initProperty(QObject *obj, const QString &name)
QMetaProperty vtProp = valueTypeMetaObject->property(idx);
- Q_ASSERT(vtProp.userType() <= 0x0000FFFF);
Q_ASSERT(idx <= 0x0000FFFF);
object = currentObject;
core = *property;
valueTypeData.setFlags(QQmlPropertyData::flagsForProperty(vtProp));
- valueTypeData.setPropType(vtProp.userType());
+ valueTypeData.setPropType(vtProp.metaType());
valueTypeData.setCoreIndex(idx);
return;
} else {
- if (!property->isQObject())
- return; // Not an object property
+ if (!property->isQObject()) {
+ if (auto asPropertyMap = qobject_cast<QQmlPropertyMap*>(currentObject))
+ currentObject = asPropertyMap->value(path.at(ii).toString()).value<QObject*>();
+ else
+ return; // Not an object property, and not a property map
+ } else {
+ property->readProperty(currentObject, &currentObject);
+ }
- property->readProperty(currentObject, &currentObject);
if (!currentObject) return; // No value
}
@@ -342,66 +349,119 @@ void QQmlPropertyPrivate::initProperty(QObject *obj, const QString &name)
}
terminal = path.last();
+ } else if (!currentObject) {
+ return;
}
- if (terminal.count() >= 3 &&
- terminal.at(0) == QLatin1Char('o') &&
- terminal.at(1) == QLatin1Char('n') &&
- terminal.at(2).isUpper()) {
+ auto findSignalInMetaObject = [&](const QByteArray &signalName) {
+ const QMetaMethod method = findSignalByName(currentObject->metaObject(), signalName);
+ if (!method.isValid())
+ return false;
- QString signalName = terminal.mid(2).toString();
- signalName[0] = signalName.at(0).toLower();
+ object = currentObject;
+ core.load(method);
+ return true;
+ };
+
+ 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);
- // XXX - this code treats methods as signals
+ if (d && d->notifyIndex() != -1) {
+ object = currentObject;
+ core = *ddata->propertyCache->signal(d->notifyIndex());
+ return true;
+ }
+ }
+ return false;
+ };
- QQmlData *ddata = QQmlData::get(currentObject, 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 QStringRef propName = signalName.midRef(0, signalName.length() - 7);
- QQmlPropertyData *d = ddata->propertyCache->property(propName, currentObject, context);
- while (d && d->isFunction())
- d = ddata->propertyCache->overrideData(d);
+ return findChangeSignal(signalName);
+ }
- if (d && d->notifyIndex() != -1) {
- object = currentObject;
- core = *ddata->propertyCache->signal(d->notifyIndex());
- return;
- }
+ return findSignalInMetaObject(signalName.toUtf8());
+ };
+
+ 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();
- isNameCached = true;
+ 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());
}
}
@@ -464,10 +524,10 @@ QQmlPropertyPrivate::propertyTypeCategory() const
if (isValueType()) {
return QQmlProperty::Normal;
} else if (type & QQmlProperty::Property) {
- int type = propertyType();
- if (type == QVariant::Invalid)
+ QMetaType type = propertyType();
+ if (!type.isValid())
return QQmlProperty::InvalidCategory;
- else if (QQmlValueTypeFactory::isValueType((uint)type))
+ else if (QQmlMetaType::isValueType(type))
return QQmlProperty::Normal;
else if (core.isQObject())
return QQmlProperty::Object;
@@ -489,7 +549,7 @@ const char *QQmlProperty::propertyTypeName() const
if (!d)
return nullptr;
if (d->isValueType()) {
- const QMetaObject *valueTypeMetaObject = QQmlValueTypeFactory::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()) {
@@ -515,12 +575,24 @@ bool QQmlProperty::operator==(const QQmlProperty &other) const
}
/*!
- Returns the QVariant type of the property, or QVariant::Invalid if the
- property has no QVariant type.
+ Returns the metatype id of the property, or QMetaType::UnknownType if the
+ property has no metatype.
+
+ \sa propertyMetaType
*/
int QQmlProperty::propertyType() const
{
- return d ? d->propertyType() : int(QVariant::Invalid);
+ return d ? d->propertyType().id() : int(QMetaType::UnknownType);
+}
+
+/*!
+ Returns the metatype of the property.
+
+ \sa propertyType
+ */
+QMetaType QQmlProperty::propertyMetaType() const
+{
+ return d ? d->propertyType() : QMetaType {};
}
bool QQmlPropertyPrivate::isValueType() const
@@ -528,7 +600,7 @@ bool QQmlPropertyPrivate::isValueType() const
return valueTypeData.isValid();
}
-int QQmlPropertyPrivate::propertyType() const
+QMetaType QQmlPropertyPrivate::propertyType() const
{
uint type = this->type();
if (isValueType()) {
@@ -536,7 +608,7 @@ int QQmlPropertyPrivate::propertyType() const
} else if (type & QQmlProperty::Property) {
return core.propType();
} else {
- return QVariant::Invalid;
+ return QMetaType();
}
}
@@ -587,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;
}
@@ -616,6 +684,21 @@ bool QQmlProperty::isWritable() const
}
/*!
+ \internal
+ Returns true if the property is bindable, otherwise false.
+ */
+bool QQmlProperty::isBindable() const
+{
+ if (!d)
+ return false;
+ if (!d->object)
+ return false;
+ if (d->core.isValid())
+ return d->core.isBindable();
+ return false;
+}
+
+/*!
Returns true if the property is designable, otherwise false.
*/
bool QQmlProperty::isDesignable() const
@@ -659,23 +742,20 @@ QString QQmlProperty::name() const
{
if (!d)
return QString();
- if (!d->isNameCached) {
- // ###
+ if (d->nameCache.isEmpty()) {
if (!d->object) {
} else if (d->isValueType()) {
- const QMetaObject *valueTypeMetaObject = QQmlValueTypeFactory::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);
}
- d->isNameCached = true;
}
return d->nameCache;
@@ -732,9 +812,6 @@ QQmlPropertyPrivate::binding(const QQmlProperty &that)
Ownership of \a newBinding transfers to QML. Ownership of the return value
is assumed by the caller.
-
- \a flags is passed through to the binding and is used for the initial update (when
- the binding sets the initial value, it will use these flags for the write).
*/
void
QQmlPropertyPrivate::setBinding(const QQmlProperty &that, QQmlAbstractBinding *newBinding)
@@ -772,14 +849,14 @@ 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)
return;
if (!(flags & QQmlPropertyPrivate::DontEnable))
- oldBinding->setEnabled(false, nullptr);
+ oldBinding->setEnabled(false, {});
oldBinding->removeFromObject();
}
@@ -792,9 +869,7 @@ void QQmlPropertyPrivate::removeBinding(QObject *o, QQmlPropertyIndex index)
{
Q_ASSERT(o);
- QObject *target;
- QQmlPropertyIndex targetIndex;
- findAliasTarget(o, index, &target, &targetIndex);
+ auto [target, targetIndex] = findAliasTarget(o, index);
removeOldBinding(target, targetIndex);
}
@@ -809,7 +884,9 @@ void QQmlPropertyPrivate::removeBinding(const QQmlProperty &that)
QQmlAbstractBinding *
QQmlPropertyPrivate::binding(QObject *object, QQmlPropertyIndex index)
{
- findAliasTarget(object, index, &object, &index);
+ auto aliasTarget = findAliasTarget(object, index);
+ object = aliasTarget.targetObject;
+ index = aliasTarget.targetIndex;
QQmlData *data = QQmlData::get(object);
if (!data)
@@ -827,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;
@@ -844,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);
@@ -871,6 +947,14 @@ void QQmlPropertyPrivate::findAliasTarget(QObject *object, QQmlPropertyIndex bin
*targetBindingIndex = bindingIndex;
}
+QQmlPropertyPrivate::ResolvedAlias QQmlPropertyPrivate::findAliasTarget(QObject *baseObject, QQmlPropertyIndex baseIndex)
+{
+ ResolvedAlias resolved;
+ findAliasTarget(baseObject, baseIndex, &resolved.targetObject, &resolved.targetIndex);
+ return resolved;
+}
+
+
void QQmlPropertyPrivate::setBinding(QQmlAbstractBinding *binding, BindingFlags flags, QQmlPropertyData::WriteFlags writeFlags)
{
@@ -884,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
@@ -907,6 +991,8 @@ QQmlPropertyPrivate::signalExpression(const QQmlProperty &that)
if (!(that.type() & QQmlProperty::SignalProperty))
return nullptr;
+ if (!that.d->object)
+ return nullptr;
QQmlData *data = QQmlData::get(that.d->object);
if (!data)
return nullptr;
@@ -946,6 +1032,8 @@ void QQmlPropertyPrivate::takeSignalExpression(const QQmlProperty &that,
return;
}
+ if (!that.d->object)
+ return;
QQmlData *data = QQmlData::get(that.d->object, nullptr != expr);
if (!data)
return;
@@ -963,7 +1051,7 @@ void QQmlPropertyPrivate::takeSignalExpression(const QQmlProperty &that,
if (expr) {
int signalIndex = QQmlPropertyPrivate::get(that)->signalIndex();
QQmlBoundSignal *signal = new QQmlBoundSignal(that.d->object, signalIndex, that.d->object,
- expr->context()->engine);
+ expr->engine());
signal->takeExpression(expr);
}
}
@@ -1038,18 +1126,24 @@ QVariant QQmlProperty::read(const QObject *object, const QString &name, QQmlEngi
QVariant QQmlPropertyPrivate::readValueProperty()
{
- if (isValueType()) {
-
- QQmlValueType *valueType = QQmlValueTypeFactory::valueType(core.propType());
- Q_ASSERT(valueType);
- valueType->read(object, core.coreIndex());
- return valueType->metaObject()->property(valueTypeData.coreIndex()).read(valueType);
+ auto doRead = [&](QQmlGadgetPtrWrapper *wrapper) {
+ wrapper->read(object, core.coreIndex());
+ return wrapper->readOnGadget(wrapper->property(valueTypeData.coreIndex()));
+ };
+ if (isValueType()) {
+ if (QQmlGadgetPtrWrapper *wrapper = QQmlGadgetPtrWrapper::instance(engine, core.propType()))
+ return doRead(wrapper);
+ if (QQmlValueType *valueType = QQmlMetaType::valueType(core.propType())) {
+ QQmlGadgetPtrWrapper wrapper(valueType, nullptr);
+ return doRead(&wrapper);
+ }
+ return QVariant();
} else if (core.isQList()) {
QQmlListProperty<QObject> prop;
core.readProperty(object, &prop);
- return QVariant::fromValue(QQmlListReferencePrivate::init(prop, core.propType(), engine));
+ return QVariant::fromValue(QQmlListReferencePrivate::init(prop, core.propType()));
} else if (core.isQObject()) {
@@ -1059,63 +1153,59 @@ QVariant QQmlPropertyPrivate::readValueProperty()
} else {
- if (!core.propType()) // Unregistered type
+ if (!core.propType().isValid()) // Unregistered type
return object->metaObject()->property(core.coreIndex()).read(object);
QVariant value;
int status = -1;
void *args[] = { nullptr, &value, &status };
- if (core.propType() == QMetaType::QVariant) {
+ if (core.propType() == QMetaType::fromType<QVariant>()) {
args[0] = &value;
} else {
value = QVariant(core.propType(), (void*)nullptr);
args[0] = value.data();
}
core.readPropertyWithArgs(object, args);
- if (core.propType() != QMetaType::QVariant && args[0] != value.data())
- return QVariant((QVariant::Type)core.propType(), args[0]);
+ if (core.propType() != QMetaType::fromType<QVariant>() && args[0] != value.data())
+ return QVariant(QMetaType(core.propType()), args[0]);
return value;
}
}
// helper function to allow assignment / binding to QList<QUrl> properties.
-QVariant QQmlPropertyPrivate::resolvedUrlSequence(const QVariant &value, QQmlContextData *context)
+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;
+}
- QList<QUrl> resolvedUrls;
- const int urlsSize = urls.size();
- resolvedUrls.reserve(urlsSize);
- for (int i = 0; i < urlsSize; ++i) {
- QUrl u = urls.at(i);
- if (context && u.isRelative() && !u.isEmpty())
- u = context->resolvedUrl(u);
- resolvedUrls.append(u);
- }
+// ### Qt7: Get rid of this
+QList<QUrl> QQmlPropertyPrivate::urlSequence(
+ const QVariant &value, const QQmlRefPointer<QQmlContextData> &ctxt)
+{
+ QList<QUrl> urls = urlSequence(value);
+
+ for (auto urlIt = urls.begin(); urlIt != urls.end(); ++urlIt)
+ *urlIt = ctxt->resolvedUrl(*urlIt);
- return QVariant::fromValue<QList<QUrl> >(resolvedUrls);
+ return urls;
}
//writeEnumProperty MIRRORS the relelvant bit of QMetaProperty::write AND MUST BE KEPT IN SYNC!
@@ -1125,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() == QVariant::String
-#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));
@@ -1139,13 +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() != QVariant::Int && v.userType() != QVariant::UInt) {
- int enumMetaTypeId = QMetaType::type(QByteArray(menum.scope() + QByteArray("::") + menum.name()));
- if ((enumMetaTypeId == QMetaType::UnknownType) || (v.userType() != enumMetaTypeId) || !v.constData())
- return false;
- v = QVariant(*reinterpret_cast<const int *>(v.constData()));
}
- v.convert(QVariant::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
@@ -1164,71 +1246,275 @@ 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,
- 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()) {
- QQmlValueType *writeBack = QQmlValueTypeFactory::valueType(core.propType());
- writeBack->read(object, core.coreIndex());
- rv = write(writeBack, valueTypeData, value, context, flags);
- writeBack->write(object, core.coreIndex(), flags);
- } else {
- rv = write(object, core, value, context, flags);
+ 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;
}
-bool QQmlPropertyPrivate::write(QObject *object,
- const QQmlPropertyData &property,
- const QVariant &value, QQmlContextData *context,
- QQmlPropertyData::WriteFlags flags)
+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};
+ }
+ }
+
+ // 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;
+ }
+ }
+
+ 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(
+ QObject *object, const QQmlPropertyData &property, const QVariant &value,
+ const QQmlRefPointer<QQmlContextData> &context, QQmlPropertyData::WriteFlags flags)
{
- const int propertyType = property.propType();
- const int variantType = value.userType();
+ const QMetaType propertyMetaType = property.propType();
+ 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 == QVariant::Double) {
+ if (variantMetaType == QMetaType::fromType<double>()) {
double integral;
double fractional = std::modf(value.toDouble(), &integral);
if (qFuzzyIsNull(fractional))
- v.convert(QVariant::Int);
+ v.convert(QMetaType::fromType<qint32>());
}
return writeEnumProperty(prop, property.coreIndex(), object, v, flags);
}
QQmlEnginePrivate *enginePriv = QQmlEnginePrivate::get(context);
- const bool isUrl = propertyType == QVariant::Url; // 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::QObjectStar, 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;
@@ -1243,165 +1529,189 @@ bool QQmlPropertyPrivate::write(QObject *object,
} else {
return false;
}
- } else if (value.canConvert(propertyType) && !isUrl && variantType != QVariant::String && 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(propertyType);
- 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 == QVariant::Url) {
+ if (variantMetaType == QMetaType::fromType<QUrl>()) {
u = value.toUrl();
- } else if (variantType == QVariant::ByteArray) {
- QString input(QString::fromUtf8(value.toByteArray()));
- // Encoded dir-separators defeat QUrl processing - decode them first
- input.replace(QLatin1String("%2f"), QLatin1String("/"), Qt::CaseInsensitive);
- u = QUrl(input);
- } else if (variantType == QVariant::String) {
- QString input(value.toString());
- // Encoded dir-separators defeat QUrl processing - decode them first
- input.replace(QLatin1String("%2f"), QLatin1String("/"), Qt::CaseInsensitive);
- u = QUrl(input);
- } else {
- return false;
+ 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 (variantMetaType == QMetaType::fromType<QString>())
+ u = QUrl(value.toString());
+ else
+ return false;
- if (context && u.isRelative() && !u.isEmpty())
- u = context->resolvedUrl(u);
return property.writeProperty(object, &u, flags);
- } else if (propertyType == qMetaTypeId<QList<QUrl>>()) {
- QList<QUrl> urlSeq = resolvedUrlSequence(value, context).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(enginePriv->listType(property.propType()));
- } else {
- QQmlType type = QQmlMetaType::qmlType(QQmlMetaType::listType(property.propType()));
- 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 (int 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 (int 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 = enginePriv?enginePriv->toQObject(value):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 == QVariant::String)
- 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(propertyType)) {
+ if (v.convert(propertyMetaType)) {
ok = true;
- } else if (v.isValid() && value.isNull()) {
- // For historical reasons converting a null QVariant to another type will do the trick
- // but return false anyway. This is caught with the above condition and considered a
- // successful conversion.
- Q_ASSERT(v.userType() == propertyType);
- ok = true;
- } else if (static_cast<uint>(propertyType) >= QVariant::UserType &&
- variantType == QVariant::String) {
- QQmlMetaType::StringConverter con = QQmlMetaType::customStringConverter(propertyType);
- if (con) {
- v = con(value.toString());
- if (v.userType() == propertyType)
- ok = true;
- }
}
}
if (!ok) {
- // the only other option is that they are assigning a single value
- // to a sequence type property (eg, an int to a QList<int> property).
+ // the only other options are that they are assigning a single value
+ // 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 == QVariant::Int && propertyType == qMetaTypeId<QList<int> >()) {
- QList<int> list;
- list << value.toInt();
- v = QVariant::fromValue<QList<int> >(list);
- ok = true;
- } else if ((variantType == QVariant::Double || variantType == QVariant::Int)
- && (propertyType == qMetaTypeId<QList<qreal> >())) {
- QList<qreal> list;
- list << value.toReal();
- v = QVariant::fromValue<QList<qreal> >(list);
- ok = true;
- } else if (variantType == QVariant::Bool && propertyType == qMetaTypeId<QList<bool> >()) {
- QList<bool> list;
- list << value.toBool();
- v = QVariant::fromValue<QList<bool> >(list);
- ok = true;
- } else if (variantType == QVariant::String && propertyType == qMetaTypeId<QList<QString> >()) {
- QList<QString> list;
- list << value.toString();
- v = QVariant::fromValue<QList<QString> >(list);
- ok = true;
- } else if (variantType == QVariant::String && 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(propertyMetaType)) {
+ auto valueAsQObject = qvariant_cast<QObject *>(value);
+
+ if (void *iface = valueAsQObject
+ ? valueAsQObject->qt_metacast(QQmlMetaType::interfaceIId(propertyMetaType))
+ : nullptr;
+ iface) {
+ // this case can occur when object has an interface type
+ // and the variant contains a type implementing the interface
+ return property.writeProperty(object, &iface, flags);
}
}
@@ -1415,17 +1725,22 @@ bool QQmlPropertyPrivate::write(QObject *object,
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);
}
/*!
@@ -1435,7 +1750,7 @@ QQmlMetaObject QQmlPropertyPrivate::rawMetaObjectForType(QQmlEnginePrivate *engi
*/
bool QQmlProperty::write(const QVariant &value) const
{
- return QQmlPropertyPrivate::write(*this, value, nullptr);
+ return QQmlPropertyPrivate::write(*this, value, {});
}
/*!
@@ -1608,14 +1923,15 @@ QQmlPropertyIndex QQmlPropertyPrivate::propertyIndex(const QQmlProperty &that)
QQmlProperty
QQmlPropertyPrivate::restore(QObject *object, const QQmlPropertyData &data,
- const QQmlPropertyData *valueTypeData, QQmlContextData *ctxt)
+ const QQmlPropertyData *valueTypeData,
+ const QQmlRefPointer<QQmlContextData> &ctxt)
{
QQmlProperty prop;
prop.d = new QQmlPropertyPrivate;
prop.d->object = object;
prop.d->context = ctxt;
- prop.d->engine = ctxt ? ctxt->engine : nullptr;
+ prop.d->engine = ctxt ? ctxt->engine() : nullptr;
prop.d->core = data;
if (valueTypeData)
@@ -1640,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())
@@ -1653,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
@@ -1662,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()) {
@@ -1705,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 34eab8208c..cbe5eb21ad 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,11 @@ class QQmlEngine;
class QQmlPropertyPrivate;
class Q_QML_EXPORT QQmlProperty
{
+ Q_GADGET
+ QML_ANONYMOUS
+
+ Q_PROPERTY(QObject *object READ object CONSTANT FINAL)
+ Q_PROPERTY(QString name READ name CONSTANT FINAL)
public:
enum PropertyTypeCategory {
InvalidCategory,
@@ -82,6 +54,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;
@@ -90,6 +66,7 @@ public:
bool isSignalProperty() const;
int propertyType() const;
+ QMetaType propertyMetaType() const;
PropertyTypeCategory propertyTypeCategory() const;
const char *propertyTypeName() const;
@@ -113,6 +90,7 @@ public:
bool connectNotifySignal(QObject *dest, int method) const;
bool isWritable() const;
+ bool isBindable() const;
bool isDesignable() const;
bool isResettable() const;
QObject *object() const;
@@ -123,16 +101,16 @@ public:
private:
friend class QQmlPropertyPrivate;
- QQmlPropertyPrivate *d;
+ QQmlPropertyPrivate *d = nullptr;
};
typedef QList<QQmlProperty> QQmlProperties;
-inline uint qHash (const QQmlProperty &key)
+inline size_t qHash (const QQmlProperty &key, size_t seed = 0)
{
- return qHash(key.object()) + qHash(key.name());
+ return qHashMulti(seed, key.object(), key.name());
}
-Q_DECLARE_TYPEINFO(QQmlProperty, Q_MOVABLE_TYPE);
+Q_DECLARE_TYPEINFO(QQmlProperty, Q_RELOCATABLE_TYPE);
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlproperty_p.h b/src/qml/qml/qqmlproperty_p.h
index 285c34d7fa..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/qqmlcontext_p.h>
-#include <private/qqmlboundsignalexpressionpointer_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
@@ -67,51 +34,81 @@ class QQmlContext;
class QQmlEnginePrivate;
class QQmlJavaScriptExpression;
class QQmlMetaObject;
+class QQmlAbstractBinding;
+class QQmlBoundSignalExpression;
-class Q_QML_PRIVATE_EXPORT QQmlPropertyPrivate : public QQmlRefCount
+class Q_QML_EXPORT QQmlPropertyPrivate final : public QQmlRefCounted<QQmlPropertyPrivate>
{
public:
- QQmlContextData *context;
+ enum class InitFlag {
+ None = 0x0,
+ AllowId = 0x1,
+ AllowSignal = 0x2
+ };
+ Q_DECLARE_FLAGS(InitFlags, InitFlag);
+
+ QQmlRefPointer<QQmlContextData> context;
QPointer<QQmlEngine> engine;
QPointer<QObject> object;
QQmlPropertyData core;
QQmlPropertyData valueTypeData;
- bool isNameCached:1;
QString nameCache;
- QQmlPropertyPrivate();
+ // ### Qt7: Get rid of this.
+ static bool resolveUrlsOnAssignment();
+
+ QQmlPropertyPrivate() {}
QQmlPropertyIndex encodedIndex() const
{ return encodedIndex(core, valueTypeData); }
static QQmlPropertyIndex encodedIndex(const QQmlPropertyData &core, const QQmlPropertyData &valueTypeData)
{ return QQmlPropertyIndex(core.coreIndex(), valueTypeData.coreIndex()); }
- inline QQmlContextData *effectiveContext() const;
+ 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;
- int propertyType() const;
+ QMetaType propertyType() const;
QQmlProperty::Type type() const;
QQmlProperty::PropertyTypeCategory propertyTypeCategory() const;
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 &, QQmlContextData *,
- QQmlPropertyData::WriteFlags flags = nullptr);
+ 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 &,
- QQmlContextData *, QQmlPropertyData::WriteFlags flags = nullptr);
+ const QQmlRefPointer<QQmlContextData> &,
+ QQmlPropertyData::WriteFlags flags = {});
+ static bool reset(QObject *, const QQmlPropertyData &,
+ QQmlPropertyData::WriteFlags flags = {});
static void findAliasTarget(QObject *, QQmlPropertyIndex, QObject **, QQmlPropertyIndex *);
+ struct ResolvedAlias
+ {
+ QObject *targetObject;
+ QQmlPropertyIndex targetIndex;
+ };
+ /*!
+ \internal
+ Given an alias property specified by \a baseObject and \a baseIndex, this function
+ computes the alias target.
+ */
+ static ResolvedAlias findAliasTarget(QObject *baseObject, QQmlPropertyIndex baseIndex);
+
enum BindingFlag {
None = 0,
DontEnable = 0x1
@@ -126,7 +123,8 @@ public:
static void removeBinding(QQmlAbstractBinding *b);
static QQmlAbstractBinding *binding(QObject *, QQmlPropertyIndex index);
- static QQmlProperty restore(QObject *, const QQmlPropertyData &, const QQmlPropertyData *, QQmlContextData *);
+ static QQmlProperty restore(QObject *, const QQmlPropertyData &, const QQmlPropertyData *,
+ const QQmlRefPointer<QQmlContextData> &);
int signalIndex() const;
@@ -141,17 +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 resolvedUrlSequence(const QVariant &value, QQmlContextData *context);
- static QQmlProperty create(QObject *target, const QString &propertyName, QQmlContextData *context);
+ 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,
+ 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
new file mode 100644
index 0000000000..c8a7e6256a
--- /dev/null
+++ b/src/qml/qml/qqmlpropertybinding.cpp
@@ -0,0 +1,383 @@
+// 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 <private/qv4qmlcontext_p.h>
+
+#include <QtQml/qqmlinfo.h>
+
+#include <QtCore/qloggingcategory.h>
+
+QT_BEGIN_NAMESPACE
+
+using namespace Qt::Literals::StringLiterals;
+
+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)
+{
+ Q_ASSERT(pd);
+ return create(pd->propType(), function, obj, ctxt, scope, target, targetIndex);
+}
+
+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);
+ binding->jsExpression()->setNotifyOnValueChanged(true);
+ binding->jsExpression()->setContext(ctxt);
+ binding->jsExpression()->setScopeObject(obj);
+ binding->jsExpression()->setupFunction(scope, function);
+ return QUntypedPropertyBinding(static_cast<QPropertyBindingPrivate *>(QPropertyBindingPrivatePtr(binding).data()));
+}
+
+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[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);
+ binding->jsExpression()->setNotifyOnValueChanged(true);
+ binding->jsExpression()->setContext(ctxt);
+ binding->jsExpression()->createQmlBinding(ctxt, obj, str, url, lineNumber);
+ 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[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);
+ binding->jsExpression()->setNotifyOnValueChanged(true);
+ binding->jsExpression()->setContext(ctxt);
+ binding->jsExpression()->setScopeObject(obj);
+ binding->jsExpression()->setupFunction(scope, function->function());
+ js->m_boundFunction.set(function->engine(), *function);
+ 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) {
+ QQmlError err;
+ auto location = QQmlJavaScriptExpression::sourceLocation();
+ err.setUrl(QUrl{location.sourceFile});
+ err.setLine(location.line);
+ err.setColumn(location.column);
+ const auto ctxt = context();
+ QQmlEngine *engine = ctxt ? ctxt->engine() : nullptr;
+ if (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(InEvaluationLoop);
+ PendingBindingObserverList bindingObservers;
+ binding->evaluateRecursive(bindingObservers);
+ binding->notifyNonRecursive(bindingObservers);
+ m_error.setTag(NoTag);
+}
+
+QQmlPropertyBinding::QQmlPropertyBinding(QMetaType mt, QObject *target, QQmlPropertyIndex targetIndex, TargetData::BoundFunction hasBoundFunction)
+ : QPropertyBindingPrivate(mt,
+ 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));
+ const auto state = hasBoundFunction ? TargetData::HasBoundFunction : TargetData::WithoutBoundFunction;
+ new (&declarativeExtraData) TargetData {target, targetIndex, state};
+ errorCallBack = bindingErrorCallback;
+}
+
+static QtPrivate::QPropertyBindingData *bindingDataFromPropertyData(QUntypedPropertyData *dataPtr, QMetaType type)
+{
+ // 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);
+}
+
+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());
+
+ 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);
+ }
+ 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;
+ }
+ // 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);
+ }
+}
+
+QString QQmlPropertyBinding::createBindingLoopErrorDescription()
+{
+ 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());
+
+ propertyData = data->propertyCache->property(targetIndex().coreIndex());
+ Q_ASSERT(propertyData);
+ Q_ASSERT(!targetIndex().hasValueTypeIndex());
+ QQmlProperty prop = QQmlPropertyPrivate::restore(target(), *propertyData, &valueTypeData, nullptr);
+ return R"(QML %1: Binding loop detected for property "%2")"_L1.arg(QQmlMetaType::prettyTypeName(target()) , prop.name());
+}
+
+void QQmlPropertyBinding::bindingErrorCallback(QPropertyBindingPrivate *that)
+{
+ auto This = static_cast<QQmlPropertyBinding *>(that);
+ auto target = This->target();
+ auto engine = qmlEngine(target);
+ if (!engine)
+ return;
+
+ auto error = This->bindingError();
+ QQmlError qmlError;
+ auto location = This->jsExpression()->sourceLocation();
+ qmlError.setColumn(location.column);
+ qmlError.setLine(location.line);
+ qmlError.setUrl(QUrl {location.sourceFile});
+ auto description = error.description();
+ if (error.type() == QPropertyBindingError::BindingLoop) {
+ description = This->createBindingLoopErrorDescription();
+ }
+ qmlError.setDescription(description);
+ qmlError.setObject(target);
+ QQmlEnginePrivate::get(engine)->warning(qmlError);
+}
+
+template<typename TranslateWithUnit>
+auto qQmlTranslationPropertyBindingCreateBinding(
+ const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit,
+ TranslateWithUnit &&translateWithUnit)
+{
+ return [compilationUnit, translateWithUnit](QMetaType metaType, void *dataPtr) -> bool {
+ // Create a dependency to the translationLanguage
+ QQmlEnginePrivate::get(compilationUnit->engine)->translationLanguage.value();
+
+ QVariant resultVariant(translateWithUnit(compilationUnit));
+ if (metaType != QMetaType::fromType<QString>())
+ resultVariant.convert(metaType);
+
+ const bool hasChanged = !metaType.equals(resultVariant.constData(), dataPtr);
+ metaType.destruct(dataPtr);
+ metaType.construct(dataPtr, resultVariant.constData());
+ return hasChanged;
+ };
+}
+
+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)
+{
+ QV4::ExecutionEngine *v4 = engine()->handle();
+ int argc = 0;
+ const QV4::Value *argv = nullptr;
+ const QV4::Value *thisObject = nullptr;
+ QV4::BoundFunction *b = nullptr;
+ if ((b = m_boundFunction.as<QV4::BoundFunction>())) {
+ QV4::Heap::MemberData *args = b->boundArgs();
+ if (args) {
+ argc = args->values.size;
+ argv = args->values.data();
+ }
+ thisObject = &b->d()->boundThis;
+ }
+ QV4::Scope scope(v4);
+ QV4::JSCallData jsCall(thisObject, argv, argc);
+
+ 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
new file mode 100644
index 0000000000..840239285e
--- /dev/null
+++ b/src/qml/qml/qqmlpropertybinding_p.h
@@ -0,0 +1,421 @@
+// 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
+
+//
+// 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/qqmljavascriptexpression_p.h>
+#include <private/qqmlpropertydata_p.h>
+#include <private/qv4alloca_p.h>
+#include <private/qqmltranslation_p.h>
+
+#include <QtCore/qproperty.h>
+
+#include <memory>
+
+QT_BEGIN_NAMESPACE
+
+namespace QV4 {
+ struct BoundFunction;
+}
+
+class QQmlPropertyBinding;
+class QQmlScriptString;
+
+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());
+ }
+
+ inline QQmlPropertyBinding const *asBinding() const;
+};
+
+class Q_QML_EXPORT QQmlPropertyBindingJSForBoundFunction : public QQmlPropertyBindingJS
+{
+public:
+ QV4::ReturnedValue evaluate(bool *isUndefined);
+ QV4::PersistentValue m_boundFunction;
+};
+
+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
+ {
+ 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 -= QPropertyBindingPrivate::getSizeEnsuringAlignment(); // f now points to QPropertyBindingPrivate suboject
+ // and that has the same address as QQmlPropertyBinding
+ return reinterpret_cast<QQmlPropertyBinding *>(address)->evaluate<type>(metaType, dataPtr);
+ }
+
+ bool hasDependencies()
+ {
+ return (dependencyObserverCount > 0) || !jsExpression()->activeGuards.isEmpty();
+ }
+
+private:
+ template <QMetaType::Type type>
+ bool evaluate(QMetaType metaType, void *dataPtr);
+
+ 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;
+ }
+
+ void setIsUndefined(bool isUndefined)
+ {
+ std::launder(reinterpret_cast<TargetData *>(&declarativeExtraData))->isUndefined = isUndefined;
+ }
+
+ static void bindingErrorCallback(QPropertyBindingPrivate *);
+};
+
+template <auto I>
+struct Print {};
+
+namespace QtPrivate {
+template<QMetaType::Type type>
+inline constexpr BindingFunctionVTable bindingFunctionVTableForQQmlPropertyBinding = {
+ &QQmlPropertyBinding::doEvaluate<type>,
+ [](void *qpropertyBinding){
+ QQmlPropertyBinding *binding = reinterpret_cast<QQmlPropertyBinding *>(qpropertyBinding);
+ binding->jsExpression()->~QQmlPropertyBindingJS();
+ binding->~QQmlPropertyBinding();
+ auto address = static_cast<std::byte*>(qpropertyBinding);
+ delete[] address;
+ },
+ [](void *, void *){},
+ 0
+};
+}
+
+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_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 69957ab282..805113ad97 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>
@@ -65,49 +30,6 @@ QT_BEGIN_NAMESPACE
#define Q_INT16_MAX 32767
-// Flags that do *NOT* depend on the property's QMetaProperty::userType() and thus are quick
-// to load
-static QQmlPropertyData::Flags fastFlagsForProperty(const QMetaProperty &p)
-{
- QQmlPropertyData::Flags flags;
-
- flags.isConstant = p.isConstant();
- flags.isWritable = p.isWritable();
- flags.isResettable = p.isResettable();
- flags.isFinal = p.isFinal();
-
- if (p.isEnumType())
- flags.type = QQmlPropertyData::Flags::EnumType;
-
- return flags;
-}
-
-// Flags that do depend on the property's QMetaProperty::userType() and thus are slow to
-// load
-static void flagsForPropertyType(int propType, QQmlPropertyData::Flags &flags)
-{
- Q_ASSERT(propType != -1);
-
- if (propType == QMetaType::QObjectStar) {
- flags.type = QQmlPropertyData::Flags::QObjectDerivedType;
- } else if (propType == QMetaType::QVariant) {
- flags.type = QQmlPropertyData::Flags::QVariantType;
- } else if (propType < static_cast<int>(QVariant::UserType)) {
- // nothing to do
- } else if (propType == qMetaTypeId<QQmlBinding *>()) {
- flags.type = QQmlPropertyData::Flags::QmlBindingType;
- } else if (propType == qMetaTypeId<QJSValue>()) {
- flags.type = QQmlPropertyData::Flags::QJSValueType;
- } else {
- QQmlMetaType::TypeCategory cat = QQmlMetaType::typeCategory(propType);
-
- if (cat == QQmlMetaType::Object || QMetaType::typeFlags(propType) & QMetaType::PointerToQObject)
- flags.type = QQmlPropertyData::Flags::QObjectDerivedType;
- else if (cat == QQmlMetaType::List)
- flags.type = QQmlPropertyData::Flags::QListType;
- }
-}
-
static int metaObjectSignalCount(const QMetaObject *metaObject)
{
int signalCount = 0;
@@ -119,114 +41,119 @@ static int metaObjectSignalCount(const QMetaObject *metaObject)
QQmlPropertyData::Flags
QQmlPropertyData::flagsForProperty(const QMetaProperty &p)
{
- auto flags = fastFlagsForProperty(p);
- flagsForPropertyType(p.userType(), flags);
- return flags;
-}
+ QQmlPropertyData::Flags flags;
-static void populate(QQmlPropertyData *data, const QMetaProperty &p)
-{
- Q_ASSERT(p.revision() <= Q_INT16_MAX);
- data->setCoreIndex(p.propertyIndex());
- data->setNotifyIndex(QMetaObjectPrivate::signalIndex(p.notifySignal()));
- data->setFlags(fastFlagsForProperty(p));
- data->setRevision(p.revision());
-}
+ flags.setIsConstant(p.isConstant());
+ flags.setIsWritable(p.isWritable());
+ flags.setIsResettable(p.isResettable());
+ flags.setIsFinal(p.isFinal());
+ flags.setIsRequired(p.isRequired());
+ flags.setIsBindable(p.isBindable());
-void QQmlPropertyData::lazyLoad(const QMetaProperty &p)
-{
- populate(this, p);
- int type = static_cast<int>(p.type());
- if (type == QMetaType::QObjectStar) {
- setPropType(type);
- m_flags.type = Flags::QObjectDerivedType;
- } else if (type == QMetaType::QVariant) {
- setPropType(type);
- m_flags.type = Flags::QVariantType;
- } else if (type == QVariant::UserType || type == -1) {
- m_flags.notFullyResolved = true;
- } else {
- setPropType(type);
+
+ const QMetaType metaType = p.metaType();
+ int propType = metaType.id();
+ if (p.isEnumType()) {
+ flags.setType(QQmlPropertyData::Flags::EnumType);
+ } else if (metaType.flags() & QMetaType::PointerToQObject) {
+ flags.setType(QQmlPropertyData::Flags::QObjectDerivedType);
+ } else if (propType == QMetaType::QVariant) {
+ flags.setType(QQmlPropertyData::Flags::QVariantType);
+ } else if (metaType.flags() & QMetaType::IsQmlList) {
+ flags.setType(QQmlPropertyData::Flags::QListType);
}
+
+ return flags;
}
void QQmlPropertyData::load(const QMetaProperty &p)
{
- populate(this, p);
- setPropType(p.userType());
- flagsForPropertyType(propType(), m_flags);
+ Q_ASSERT(p.revision() <= std::numeric_limits<quint16>::max());
+ setCoreIndex(p.propertyIndex());
+ setNotifyIndex(QMetaObjectPrivate::signalIndex(p.notifySignal()));
+ setFlags(flagsForProperty(p));
+ setRevision(QTypeRevision::fromEncodedVersion(p.revision()));
+ QMetaType type = p.metaType();
+ setPropType(type);
}
void QQmlPropertyData::load(const QMetaMethod &m)
{
setCoreIndex(m.methodIndex());
- setArguments(nullptr);
-
- setPropType(m.returnType());
-
- m_flags.type = Flags::FunctionType;
- if (m.methodType() == QMetaMethod::Signal) {
- m_flags.isSignal = true;
- } else if (m.methodType() == QMetaMethod::Constructor) {
- m_flags.isConstructor = true;
- setPropType(QMetaType::QObjectStar);
+ m_flags.setType(Flags::FunctionType);
+
+ // 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.
+
+ switch (m.methodType()) {
+ case QMetaMethod::Signal:
+ m_flags.setIsSignal(true);
+ m_flags.setIsConstructor(false);
+ setPropType(m.returnMetaType());
+ break;
+ case QMetaMethod::Constructor:
+ m_flags.setIsSignal(false);
+ m_flags.setIsConstructor(true);
+ 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.hasArguments = true;
- if ((paramCount == 1) && (m.parameterTypes().constFirst() == "QQmlV4Function*"))
- m_flags.isV4Function = true;
+ m_flags.setHasArguments(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.isCloned = true;
+ m_flags.setIsCloned(m.attributes() & QMetaMethod::Cloned);
- Q_ASSERT(m.revision() <= Q_INT16_MAX);
- setRevision(m.revision());
-}
-
-void QQmlPropertyData::lazyLoad(const QMetaMethod &m)
-{
- load(m);
-
- const char *returnType = m.typeName();
- if (!returnType)
- returnType = "\0";
- if ((*returnType != 'v') || (qstrcmp(returnType+1, "oid") != 0)) {
- m_flags.notFullyResolved = true;
- }
+ 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()
- : _parent(nullptr), propertyIndexCacheStart(0), methodIndexCacheStart(0),
- signalHandlerIndexCacheStart(0), _hasPropertyOverrides(false), _ownMetaObject(false),
- _metaObject(nullptr), argumentsCache(nullptr), _jsFactoryMethodIndex(-1)
-{
-}
-
-/*!
-Creates a new QQmlPropertyCache of \a metaObject.
-*/
-QQmlPropertyCache::QQmlPropertyCache(const QMetaObject *metaObject, int 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 > 0) {
+ if (metaObjectRevision.isValid() && metaObjectRevision != QTypeRevision::zero()) {
// Set the revision of the meta object that this cache describes to be
// 'metaObjectRevision'. This is useful when constructing a property cache
// 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()
@@ -234,7 +161,6 @@ QQmlPropertyCache::~QQmlPropertyCache()
QQmlPropertyCacheMethodArguments *args = argumentsCache;
while (args) {
QQmlPropertyCacheMethodArguments *next = args->next;
- delete args->signalParameterStringForJS;
delete args->names;
free(args);
args = next;
@@ -243,44 +169,38 @@ QQmlPropertyCache::~QQmlPropertyCache()
// We must clear this prior to releasing the parent incase it is a
// linked hash
stringCache.clear();
- if (_parent) _parent->release();
-
- if (_ownMetaObject) free(const_cast<QMetaObject *>(_metaObject));
- _metaObject = nullptr;
- _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 = nullptr;
-
return rv;
}
@@ -290,89 +210,89 @@ QQmlPropertyCache *QQmlPropertyCache::copyAndReserve(int propertyCount, int meth
This is different from QMetaMethod::methodIndex().
*/
void QQmlPropertyCache::appendProperty(const QString &name, QQmlPropertyData::Flags flags,
- int coreIndex, int propType, int minorVersion, int notifyIndex)
+ int coreIndex, QMetaType propType, QTypeRevision version,
+ int notifyIndex)
{
QQmlPropertyData data;
data.setPropType(propType);
data.setCoreIndex(coreIndex);
data.setNotifyIndex(notifyIndex);
data.setFlags(flags);
- data.setTypeMinorVersion(minorVersion);
+ 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;
- data.setPropType(QVariant::Invalid);
+ data.setPropType(QMetaType());
data.setCoreIndex(coreIndex);
data.setFlags(flags);
data.setArguments(nullptr);
QQmlPropertyData handler = data;
- handler.m_flags.isSignalHandler = true;
+ 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(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)
@@ -384,76 +304,84 @@ 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) {
- _ownMetaObject = true;
-
+ if (_metaObject.isNull()) {
QMetaObjectBuilder builder;
toMetaObjectBuilder(builder);
builder.setSuperClass(_parent->createMetaObject());
- _metaObject = builder.toMetaObject();
+ _metaObject.setSharedOnce(builder.toMetaObject());
}
- return _metaObject;
+ return _metaObject.metaObject();
}
-QQmlPropertyData *QQmlPropertyCache::defaultProperty() const
+const QQmlPropertyData *QQmlPropertyCache::maybeUnresolvedProperty(int index) const
{
- return property(defaultPropertyName(), nullptr, nullptr);
+ if (index < 0 || index >= propertyCount())
+ return nullptr;
+
+ const QQmlPropertyData *rv = nullptr;
+ if (index < propertyIndexCacheStart)
+ return _parent->maybeUnresolvedProperty(index);
+ else
+ rv = const_cast<const QQmlPropertyData *>(&propertyIndexCache.at(index - propertyIndexCacheStart));
+ return rv;
}
-void QQmlPropertyCache::setParent(QQmlPropertyCache *newParent)
+const QQmlPropertyData *QQmlPropertyCache::defaultProperty() const
{
- if (_parent == newParent)
- return;
- if (_parent)
- _parent->release();
- _parent = newParent;
- _parent->addref();
+ return property(defaultPropertyName(), nullptr, nullptr);
}
-QQmlPropertyCache *
-QQmlPropertyCache::copyAndAppend(const QMetaObject *metaObject,
- QQmlPropertyData::Flags propertyFlags,
- QQmlPropertyData::Flags methodFlags,
- QQmlPropertyData::Flags signalFlags)
+void QQmlPropertyCache::setParent(QQmlPropertyCache::ConstPtr newParent)
{
- return copyAndAppend(metaObject, -1, propertyFlags, methodFlags, signalFlags);
+ if (_parent != newParent)
+ _parent = std::move(newParent);
}
-QQmlPropertyCache *
+QQmlPropertyCache::Ptr
QQmlPropertyCache::copyAndAppend(const QMetaObject *metaObject,
- int typeMinorVersion,
+ 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, typeMinorVersion, propertyFlags, methodFlags, signalFlags);
+ 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,
- int typeMinorVersion,
+ QTypeRevision typeVersion,
QQmlPropertyData::Flags propertyFlags,
QQmlPropertyData::Flags methodFlags,
QQmlPropertyData::Flags signalFlags)
{
- _metaObject = metaObject;
-
- bool dynamicMetaObject = isDynamicMetaObject(metaObject);
-
- allowedRevisionCache.append(0);
+ allowedRevisionCache.append(QTypeRevision::zero());
int methodCount = metaObject->methodCount();
Q_ASSERT(QMetaObjectPrivate::get(metaObject)->revision >= 4);
@@ -473,6 +401,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();
}
}
}
@@ -482,7 +412,9 @@ void QQmlPropertyCache::append(const QMetaObject *metaObject,
static const int destroyedIdx2 = QObject::staticMetaObject.indexOfSignal("destroyed()");
static const int deleteLaterIdx = QObject::staticMetaObject.indexOfSlot("deleteLater()");
// These indices don't apply to gadgets, so don't block them.
- const bool preventDestruction = metaObject->superClass() || metaObject == &QObject::staticMetaObject;
+ // It is enough to check for QObject::staticMetaObject here because the loop below excludes
+ // methods of parent classes: It starts at metaObject->methodOffset()
+ const bool preventDestruction = (metaObject == &QObject::staticMetaObject);
int methodOffset = metaObject->methodOffset();
int signalOffset = signalCount - QMetaObjectPrivate::get(metaObject)->signalCount;
@@ -518,61 +450,42 @@ void QQmlPropertyCache::append(const QMetaObject *metaObject,
else
data->setFlags(methodFlags);
- data->lazyLoad(m);
- data->m_flags.isDirect = !dynamicMetaObject;
+ data->load(m);
- 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];
*sigdata = *data;
- sigdata->m_flags.isSignalHandler = true;
+ sigdata->m_flags.setIsSignalHandler(true);
}
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() % methodName.midRef(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.isOverload = true;
-
- data->markAsOverrideOf(old);
- }
+ if (utf8)
+ doSetNamedProperty(QHashedString(QString::fromUtf8(rawName, cptr - rawName)));
+ else
+ doSetNamedProperty(QHashedCStringRef(rawName, cptr - rawName));
}
int propCount = metaObject->propertyCount();
@@ -597,26 +510,28 @@ void QQmlPropertyCache::append(const QMetaObject *metaObject,
QQmlPropertyData *data = &propertyIndexCache[ii - propertyIndexCacheStart];
data->setFlags(propertyFlags);
- data->lazyLoad(p);
- data->setTypeMinorVersion(typeMinorVersion);
-
- data->m_flags.isDirect = !dynamicMetaObject;
+ data->load(p);
+ data->setTypeVersion(typeVersion);
- 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;
@@ -625,67 +540,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.isDirect = 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::resolve(QQmlPropertyData *data) const
-{
- Q_ASSERT(data->notFullyResolved());
- data->m_flags.notFullyResolved = false;
-
- const QMetaObject *mo = firstCppMetaObject();
- if (data->isFunction()) {
- auto metaMethod = mo->method(data->coreIndex());
- const char *retTy = metaMethod.typeName();
- if (!retTy)
- retTy = "\0";
- data->setPropType(QMetaType::type(retTy));
- } else {
- auto metaProperty = mo->property(data->coreIndex());
- data->setPropType(QMetaType::type(metaProperty.typeName()));
- }
-
- if (!data->isFunction()) {
- if (data->propType() == QMetaType::UnknownType) {
- QQmlPropertyCache *p = _parent;
- while (p && (!mo || _ownMetaObject)) {
- mo = p->_metaObject;
- p = p->_parent;
- }
-
- int propOffset = mo->propertyOffset();
- if (mo && data->coreIndex() < propOffset + mo->propertyCount()) {
- while (data->coreIndex() < propOffset) {
- mo = mo->superClass();
- propOffset = mo->propertyOffset();
- }
-
- int registerResult = -1;
- void *argv[] = { &registerResult };
- mo->static_metacall(QMetaObject::RegisterPropertyMetaType, data->coreIndex() - propOffset, argv);
- data->setPropType(registerResult == -1 ? QMetaType::UnknownType : registerResult);
- }
- }
- flagsForPropertyType(data->propType(), data->m_flags);
- }
-}
-
-void QQmlPropertyCache::updateRecur(const QMetaObject *metaObject)
-{
- if (!metaObject)
- return;
-
- updateRecur(metaObject->superClass());
-
- append(metaObject, -1);
-}
-
void QQmlPropertyCache::update(const QMetaObject *metaObject)
{
Q_ASSERT(metaObject);
@@ -705,7 +565,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
@@ -718,7 +579,6 @@ void QQmlPropertyCache::invalidate(const QMetaObject *metaObject)
methodIndexCache.clear();
signalHandlerIndexCache.clear();
- _hasPropertyOverrides = false;
argumentsCache = nullptr;
int pc = metaObject->propertyCount();
@@ -727,11 +587,11 @@ 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, -1);
+ append(metaObject, QTypeRevision());
} else {
propertyIndexCacheStart = 0;
methodIndexCacheStart = 0;
@@ -740,7 +600,9 @@ void QQmlPropertyCache::invalidate(const QMetaObject *metaObject)
}
}
-QQmlPropertyData *QQmlPropertyCache::findProperty(StringCache::ConstIterator it, QObject *object, QQmlContextData *context) const
+const QQmlPropertyData *QQmlPropertyCache::findProperty(
+ StringCache::ConstIterator it, QObject *object,
+ const QQmlRefPointer<QQmlContextData> &context) const
{
QQmlData *data = (object ? QQmlData::get(object) : nullptr);
const QQmlVMEMetaObject *vmemo = nullptr;
@@ -753,14 +615,15 @@ QQmlPropertyData *QQmlPropertyCache::findProperty(StringCache::ConstIterator it,
namespace {
-inline bool contextHasNoExtensions(QQmlContextData *context)
+inline bool contextHasNoExtensions(const QQmlRefPointer<QQmlContextData> &context)
{
// 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
@@ -769,12 +632,14 @@ inline int maximumIndexForProperty(QQmlPropertyData *prop, const int methodCount
}
-QQmlPropertyData *QQmlPropertyCache::findProperty(StringCache::ConstIterator it, const QQmlVMEMetaObject *vmemo, QQmlContextData *context) const
+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
@@ -783,7 +648,7 @@ QQmlPropertyData *QQmlPropertyCache::findProperty(StringCache::ConstIterator it,
if (vmemo && context && !contextHasNoExtensions(context)) {
// Find the meta-object that corresponds to the supplied context
do {
- if (vmemo->ctxt == context)
+ if (vmemo->ctxt.contextData().data() == context.data())
break;
vmemo = vmemo->parentVMEMetaObject();
@@ -815,51 +680,34 @@ QQmlPropertyData *QQmlPropertyCache::findProperty(StringCache::ConstIterator it,
} while (it != end);
}
- return ensureResolved(result);
+ return result;
}
return nullptr;
}
-QString QQmlPropertyData::name(QObject *object) const
-{
- if (!object)
- return QString();
- return name(object->metaObject());
-}
-QString QQmlPropertyData::name(const QMetaObject *metaObject) const
-{
- if (!metaObject || coreIndex() == -1)
- return QString();
-
- if (isFunction()) {
- QMetaMethod m = metaObject->method(coreIndex());
- return QString::fromUtf8(m.name().constData());
- } else {
- QMetaProperty p = metaObject->property(coreIndex());
- return QString::fromUtf8(p.name());
- }
-}
-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.isOverridden = true;
+ 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->signalParameterStringForJS = nullptr;
- 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;
@@ -872,13 +720,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();
@@ -893,19 +745,19 @@ QString QQmlPropertyCache::signalParameterStringForJS(QV4::ExecutionEngine *engi
return parameters;
}
-int QQmlPropertyCache::originalClone(int index)
+int QQmlPropertyCache::originalClone(int index) const
{
while (signal(index)->isCloned())
--index;
return index;
}
-int QQmlPropertyCache::originalClone(QObject *object, 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);
@@ -981,7 +833,7 @@ static inline const char *qQmlPropertyCacheToString(QLatin1String string)
return string.data();
}
-static inline QByteArray qQmlPropertyCacheToString(const QStringRef &string)
+static inline QByteArray qQmlPropertyCacheToString(QStringView string)
{
return string.toUtf8();
}
@@ -992,99 +844,84 @@ static inline QByteArray qQmlPropertyCacheToString(const QV4::String *string)
}
template<typename T>
-QQmlPropertyData *
-qQmlPropertyCacheProperty(QJSEngine *engine, QObject *obj, T name,
- 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);
- } else {
- local = qQmlPropertyCacheCreate(obj->metaObject(), qQmlPropertyCacheToString(name));
- if (local.isValid())
- rv = &local;
+ } else if (local) {
+ *local = qQmlPropertyCacheCreate(obj->metaObject(), qQmlPropertyCacheToString(name));
+ if (local->isValid())
+ rv = local;
}
return rv;
}
-QQmlPropertyData *
-QQmlPropertyCache::property(QJSEngine *engine, QObject *obj, const QV4::String *name,
- 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, const QStringRef &name,
- QQmlContextData *context, QQmlPropertyData &local)
+const QQmlPropertyData *QQmlPropertyCache::property(
+ QObject *obj, QStringView name, const QQmlRefPointer<QQmlContextData> &context,
+ QQmlPropertyData *local)
{
- return qQmlPropertyCacheProperty<const QStringRef &>(engine, obj, name, context, local);
+ return qQmlPropertyCacheProperty<const QStringView &>(obj, name, context, local);
}
-QQmlPropertyData *
-QQmlPropertyCache::property(QJSEngine *engine, QObject *obj, const QLatin1String &name,
- 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)
{
- Q_ASSERT(priv(mo->d.data)->revision >= 7);
- const QByteArrayDataPtr data = { const_cast<QByteArrayData*>(&mo->d.stringdata[index]) };
- Q_ASSERT(data.ptr->ref.isStatic());
- Q_ASSERT(data.ptr->alloc == 0);
- Q_ASSERT(data.ptr->capacityReserved == 0);
- Q_ASSERT(data.ptr->size >= 0);
- return data;
-}
-
-bool QQmlPropertyCache::isDynamicMetaObject(const QMetaObject *mo)
-{
- return priv(mo->d.data)->revision >= 3 && priv(mo->d.data)->flags & DynamicMetaObject;
+ uint offset = mo->d.stringdata[2*index];
+ uint length = mo->d.stringdata[2*index + 1];
+ const char *string = reinterpret_cast<const char *>(mo->d.stringdata) + offset;
+ return QByteArray::fromRawData(string, length);
}
const char *QQmlPropertyCache::className() const
{
- if (!_ownMetaObject && _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;
@@ -1092,7 +929,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);
@@ -1102,7 +939,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);
@@ -1114,40 +951,43 @@ 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)
notifierId = data->notifyIndex() - signalHandlerIndexCacheStart;
QMetaPropertyBuilder property = builder.addProperty(properties.at(ii).first.toUtf8(),
- QMetaType::typeName(data->propType()),
+ data->propType().name(),
+ data->propType(),
notifierId);
property.setReadable(true);
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() != 0)
- returnType = QMetaType::typeName(data->propType());
+ if (data->propType().isValid())
+ returnType = data->propType().name();
QByteArray signature;
// '+=' reserves extra capacity. Follow-up appending will be probably free.
@@ -1155,11 +995,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::typeName(arguments->arguments[1 + ii]));
+ 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());
}
}
@@ -1180,23 +1021,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 {
@@ -1204,14 +1048,12 @@ template <typename StringVisitor, typename TypeInfoVisitor>
int visitMethods(const QMetaObject &mo, int methodOffset, int methodCount,
StringVisitor visitString, TypeInfoVisitor visitTypeInfo)
{
- const int intsPerMethod = 5;
-
int fieldsForParameterData = 0;
bool hasRevisionedMethods = false;
for (int i = 0; i < methodCount; ++i) {
- const int handle = methodOffset + i * intsPerMethod;
+ const int handle = methodOffset + i * QMetaObjectPrivate::IntsPerMethod;
const uint flags = mo.d.data[handle + 4];
if (flags & MethodRevisioned)
@@ -1241,42 +1083,23 @@ int visitMethods(const QMetaObject &mo, int methodOffset, int methodCount,
if (hasRevisionedMethods)
fieldsForRevisions = methodCount;
- return methodCount * intsPerMethod + fieldsForRevisions + fieldsForParameterData;
+ return methodCount * QMetaObjectPrivate::IntsPerMethod
+ + fieldsForRevisions + fieldsForParameterData;
}
template <typename StringVisitor, typename TypeInfoVisitor>
int visitProperties(const QMetaObject &mo, StringVisitor visitString, TypeInfoVisitor visitTypeInfo)
{
const QMetaObjectPrivate *const priv = reinterpret_cast<const QMetaObjectPrivate*>(mo.d.data);
- const int intsPerProperty = 3;
-
- bool hasRevisionedProperties = false;
- bool hasNotifySignals = false;
for (int i = 0; i < priv->propertyCount; ++i) {
- const int handle = priv->propertyData + i * intsPerProperty;
-
- const auto flags = mo.d.data[handle + 2];
- if (flags & Revisioned) {
- hasRevisionedProperties = true;
- }
- if (flags & Notify)
- hasNotifySignals = true;
+ const int handle = priv->propertyData + i * QMetaObjectPrivate::IntsPerProperty;
visitString(mo.d.data[handle]); // name
visitTypeInfo(mo.d.data[handle + 1]);
}
- int fieldsForPropertyRevisions = 0;
- if (hasRevisionedProperties)
- fieldsForPropertyRevisions = priv->propertyCount;
-
- int fieldsForNotifySignals = 0;
- if (hasNotifySignals)
- fieldsForNotifySignals = priv->propertyCount;
-
- return priv->propertyCount * intsPerProperty + fieldsForPropertyRevisions
- + fieldsForNotifySignals;
+ return priv->propertyCount * QMetaObjectPrivate::IntsPerProperty;
}
template <typename StringVisitor>
@@ -1299,21 +1122,19 @@ template <typename StringVisitor>
int visitEnumerations(const QMetaObject &mo, StringVisitor visitString)
{
const QMetaObjectPrivate *const priv = reinterpret_cast<const QMetaObjectPrivate*>(mo.d.data);
- const int intsPerEnumerator = priv->revision >= 8 ? 5 : 4;
- int fieldCount = priv->enumeratorCount * intsPerEnumerator;
+ int fieldCount = priv->enumeratorCount * QMetaObjectPrivate::IntsPerEnum;
for (int i = 0; i < priv->enumeratorCount; ++i) {
- const uint *enumeratorData = mo.d.data + priv->enumeratorData + i * intsPerEnumerator;
+ const uint *enumeratorData = mo.d.data + priv->enumeratorData + i * QMetaObjectPrivate::IntsPerEnum;
- const uint keyCount = enumeratorData[intsPerEnumerator == 5 ? 3 : 2];
+ const uint keyCount = enumeratorData[3];
fieldCount += keyCount * 2;
visitString(enumeratorData[0]); // name
- if (intsPerEnumerator == 5)
- visitString(enumeratorData[1]); // enum name
+ visitString(enumeratorData[1]); // enum name
- const uint keyOffset = enumeratorData[intsPerEnumerator == 5 ? 4 : 3];
+ const uint keyOffset = enumeratorData[4];
for (uint j = 0; j < keyCount; ++j) {
visitString(mo.d.data[keyOffset + 2 * j]);
@@ -1349,13 +1170,14 @@ 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 < 7 || priv->revision > 8) {
+ if (priv->revision != QMetaObjectPrivate::OutputRevision)
return false;
- }
uint highestStringIndex = 0;
const auto stringIndexVisitor = [&highestStringIndex](uint index) {
@@ -1376,7 +1198,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));
}
@@ -1384,35 +1206,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 || _ownMetaObject) {
+ 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
@@ -1421,7 +1249,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 bfd78eef88..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,20 +15,15 @@
// 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 "qqmlcleanup_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 <private/qv4value_p.h>
-#include <private/qqmlpropertydata_p.h>
-#include <private/qqmlenumdata_p.h>
-#include <private/qqmlenumvalue_p.h>
+#include <QtCore/qversionnumber.h>
#include <limits>
@@ -73,81 +32,176 @@ QT_BEGIN_NAMESPACE
class QCryptographicHash;
class QJSEngine;
class QMetaObjectBuilder;
-class QQmlVMEMetaObject;
+class QQmlContextData;
+class QQmlPropertyCache;
class QQmlPropertyCacheMethodArguments;
+class QQmlVMEMetaObject;
-class Q_QML_PRIVATE_EXPORT QQmlPropertyCache : public QQmlRefCount
+class QQmlMetaObjectPointer
{
public:
- QQmlPropertyCache();
- QQmlPropertyCache(const QMetaObject *, int metaObjectRevision = 0);
- ~QQmlPropertyCache() override;
+ Q_NODISCARD_CTOR QQmlMetaObjectPointer() = default;
+
+ Q_NODISCARD_CTOR QQmlMetaObjectPointer(const QMetaObject *staticMetaObject)
+ : d(quintptr(staticMetaObject))
+ {
+ Q_ASSERT((d.loadRelaxed() & Shared) == 0);
+ }
+
+ ~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();
+ }
+
+ 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);
+ }
+
+ bool isShared() const
+ {
+ // 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);
+ }
+
+ bool isNull() const
+ {
+ return d.loadRelaxed() == 0;
+ }
+
+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_EXPORT QQmlPropertyCache final
+ : public QQmlRefCounted<QQmlPropertyCache>
+{
+public:
+ 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(const QMetaObject *,
- QQmlPropertyData::Flags propertyFlags = QQmlPropertyData::Flags(),
- QQmlPropertyData::Flags methodFlags = QQmlPropertyData::Flags(),
- QQmlPropertyData::Flags signalFlags = QQmlPropertyData::Flags());
- QQmlPropertyCache *copyAndAppend(const QMetaObject *, int typeMinorVersion,
+ 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,
- int propType, int revision, int notifyIndex);
+ 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, QQmlContextData *context) const
+ 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 *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;
- 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 *, const QStringRef &,
- QQmlContextData *, QQmlPropertyData &);
- static QQmlPropertyData *property(QJSEngine *, QObject *, const QLatin1String &,
- QQmlContextData *, QQmlPropertyData &);
- static QQmlPropertyData *property(QJSEngine *, QObject *, const QV4::String *,
- QQmlContextData *, QQmlPropertyData &);
+ // is used by the Qml Designer
+ void setParent(QQmlPropertyCache::ConstPtr newParent);
- static QQmlPropertyData *property(QJSEngine *engine, QObject *obj, const QString &name,
- QQmlContextData *context, QQmlPropertyData &local)
- {
- return property(engine, obj, QStringRef(&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);
- static int originalClone(QObject *, int index);
+ int originalClone(int index) const;
+ static int originalClone(const QObject *, int index);
QList<QByteArray> signalParameterNames(int index) const;
static QString signalParameterStringForJS(QV4::ExecutionEngine *engine, const QList<QByteArray> &parameterNameList, QString *errorString = nullptr);
@@ -162,31 +216,31 @@ 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;
- int allowedRevision(int index) const { return allowedRevisionCache[index]; }
- void setAllowedRevision(int index, int allowed) { allowedRevisionCache[index] = allowed; }
+ QTypeRevision allowedRevision(int index) const { return allowedRevisionCache[index]; }
+ void setAllowedRevision(int index, QTypeRevision allowed) { allowedRevisionCache[index] = allowed; }
private:
friend class QQmlEnginePrivate;
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) {}
- void append(const QMetaObject *, int typeMinorVersion,
+ inline QQmlPropertyCache::Ptr copy(const QQmlMetaObjectPointer &mo, int reserve) const;
+
+ void append(const QMetaObject *, QTypeRevision typeVersion,
QQmlPropertyData::Flags propertyFlags = QQmlPropertyData::Flags(),
QQmlPropertyData::Flags methodFlags = QQmlPropertyData::Flags(),
QQmlPropertyData::Flags signalFlags = QQmlPropertyData::Flags());
@@ -195,15 +249,12 @@ private:
typedef QVector<QQmlPropertyData> IndexCache;
typedef QLinkedStringMultiHash<QPair<int, QQmlPropertyData *> > StringCache;
- typedef QVector<int> AllowedRevisionCache;
-
- QQmlPropertyData *findProperty(StringCache::ConstIterator it, QObject *, QQmlContextData *) const;
- QQmlPropertyData *findProperty(StringCache::ConstIterator it, const QQmlVMEMetaObject *, QQmlContextData *) const;
+ typedef QVector<QTypeRevision> AllowedRevisionCache;
- QQmlPropertyData *ensureResolved(QQmlPropertyData*) const;
-
- Q_NEVER_INLINE void resolve(QQmlPropertyData *) const;
- void updateRecur(const QMetaObject *);
+ const QQmlPropertyData *findProperty(StringCache::ConstIterator it, QObject *,
+ const QQmlRefPointer<QQmlContextData> &) const;
+ const QQmlPropertyData *findProperty(StringCache::ConstIterator it, const QQmlVMEMetaObject *,
+ const QQmlRefPointer<QQmlContextData> &) const;
template<typename K>
QQmlPropertyData *findNamedProperty(const K &key) const
@@ -213,17 +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:
- QQmlPropertyCache *_parent;
- int propertyIndexCacheStart;
- int methodIndexCacheStart;
- int signalHandlerIndexCacheStart;
+ 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;
@@ -232,84 +302,75 @@ private:
AllowedRevisionCache allowedRevisionCache;
QVector<QQmlEnumData> enumCache;
- bool _hasPropertyOverrides : 1;
- bool _ownMetaObject : 1;
- const QMetaObject *_metaObject;
+ QQmlMetaObjectPointer _metaObject;
QByteArray _dynamicClassName;
QByteArray _dynamicStringData;
+ QByteArray _listPropertyAssignBehavior;
QString _defaultPropertyName;
- QQmlPropertyCacheMethodArguments *argumentsCache;
- int _jsFactoryMethodIndex;
- QByteArray _checksum;
+ QQmlPropertyCacheMethodArguments *argumentsCache = nullptr;
+ int methodIndexCacheStart = 0;
+ int signalHandlerIndexCacheStart = 0;
+ int _jsFactoryMethodIndex = -1;
};
-inline QQmlPropertyData *QQmlPropertyCache::ensureResolved(QQmlPropertyData *p) const
-{
- if (p && Q_UNLIKELY(p->notFullyResolved()))
- resolve(p);
-
- return p;
-}
-
// 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
// QML
inline const QMetaObject *QQmlPropertyCache::firstCppMetaObject() const
{
- while (_parent && (_metaObject == nullptr || _ownMetaObject))
- return _parent->firstCppMetaObject();
- return _metaObject;
+ const QQmlPropertyCache *p = this;
+ 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);
- QQmlPropertyData *rv = const_cast<QQmlPropertyData *>(&propertyIndexCache.at(index - propertyIndexCacheStart));
- return ensureResolved(rv);
+ 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);
- QQmlPropertyData *rv = const_cast<QQmlPropertyData *>(&methodIndexCache.at(index - methodIndexCacheStart));
- return ensureResolved(rv);
+ 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 ensureResolved(rv);
+ 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));
@@ -317,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)
@@ -332,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;
@@ -349,15 +410,30 @@ QQmlPropertyCache::overrideData(QQmlPropertyData *data) const
return method(data->overrideIndex());
}
-bool QQmlPropertyCache::isAllowedInRevision(QQmlPropertyData *data) const
+bool QQmlPropertyCache::isAllowedInRevision(const QQmlPropertyData *data) const
{
- return (data->metaObjectOffset() == -1 && data->revision() == 0) ||
- (allowedRevisionCache[data->metaObjectOffset()] >= data->revision());
+ const QTypeRevision requested = data->revision();
+ const int offset = data->metaObjectOffset();
+ if (offset == -1 && requested == QTypeRevision::zero())
+ return true;
+
+ Q_ASSERT(offset >= 0);
+ Q_ASSERT(offset < allowedRevisionCache.size());
+ const QTypeRevision allowed = allowedRevisionCache[offset];
+
+ if (requested.hasMajorVersion()) {
+ if (requested.majorVersion() > allowed.majorVersion())
+ return false;
+ if (requested.majorVersion() < allowed.majorVersion())
+ return true;
+ }
+
+ return !requested.hasMinorVersion() || requested.minorVersion() <= allowed.minorVersion();
}
int QQmlPropertyCache::propertyCount() const
{
- return propertyIndexCacheStart + propertyIndexCache.count();
+ return propertyIndexCacheStart + int(propertyIndexCache.size());
}
int QQmlPropertyCache::propertyOffset() const
@@ -367,7 +443,7 @@ int QQmlPropertyCache::propertyOffset() const
int QQmlPropertyCache::methodCount() const
{
- return methodIndexCacheStart + methodIndexCache.count();
+ return methodIndexCacheStart + int(methodIndexCache.size());
}
int QQmlPropertyCache::methodOffset() const
@@ -377,7 +453,7 @@ int QQmlPropertyCache::methodOffset() const
int QQmlPropertyCache::signalCount() const
{
- return signalHandlerIndexCacheStart + signalHandlerIndexCache.count();
+ return signalHandlerIndexCacheStart + int(signalHandlerIndexCache.size());
}
int QQmlPropertyCache::signalOffset() const
@@ -387,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 034ebfc743..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,37 +9,61 @@ QT_BEGIN_NAMESPACE
QAtomicInt QQmlPropertyCacheCreatorBase::classIndexCounter(0);
+template<typename BaseNameHandler, typename FailHandler>
+auto processUrlForClassName(
+ const QUrl &url, BaseNameHandler &&baseNameHandler, FailHandler &&failHandler)
+{
+ const QString path = url.path();
+
+ // Not a reusable type if we don't have an absolute Url
+ const qsizetype lastSlash = path.lastIndexOf(QLatin1Char('/'));
+ if (lastSlash <= -1)
+ return failHandler();
+
+ // ### this might not be correct for .ui.qml files
+ 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.
+ return (!baseName.isEmpty() && baseName.at(0).isUpper())
+ ? baseNameHandler(baseName)
+ : failHandler();
+}
+
+bool QQmlPropertyCacheCreatorBase::canCreateClassNameTypeByUrl(const QUrl &url)
+{
+ return processUrlForClassName(url, [](QStringView) {
+ return true;
+ }, []() {
+ return false;
+ });
+}
-int QQmlPropertyCacheCreatorBase::metaTypeForPropertyType(QV4::CompiledData::BuiltinType type)
+QByteArray QQmlPropertyCacheCreatorBase::createClassNameTypeByUrl(const QUrl &url)
{
- switch (type) {
- case QV4::CompiledData::BuiltinType::Var: return QMetaType::QVariant;
- case QV4::CompiledData::BuiltinType::Variant: return QMetaType::QVariant;
- case QV4::CompiledData::BuiltinType::Int: return QMetaType::Int;
- case QV4::CompiledData::BuiltinType::Bool: return QMetaType::Bool;
- case QV4::CompiledData::BuiltinType::Real: return QMetaType::Double;
- case QV4::CompiledData::BuiltinType::String: return QMetaType::QString;
- case QV4::CompiledData::BuiltinType::Url: return QMetaType::QUrl;
- case QV4::CompiledData::BuiltinType::Color: return QMetaType::QColor;
- case QV4::CompiledData::BuiltinType::Font: return QMetaType::QFont;
- case QV4::CompiledData::BuiltinType::Time: return QMetaType::QTime;
- case QV4::CompiledData::BuiltinType::Date: return QMetaType::QDate;
- case QV4::CompiledData::BuiltinType::DateTime: return QMetaType::QDateTime;
- case QV4::CompiledData::BuiltinType::Rect: return QMetaType::QRectF;
- case QV4::CompiledData::BuiltinType::Point: return QMetaType::QPointF;
- case QV4::CompiledData::BuiltinType::Size: return QMetaType::QSizeF;
- case QV4::CompiledData::BuiltinType::Vector2D: return QMetaType::QVector2D;
- case QV4::CompiledData::BuiltinType::Vector3D: return QMetaType::QVector3D;
- case QV4::CompiledData::BuiltinType::Vector4D: return QMetaType::QVector4D;
- case QV4::CompiledData::BuiltinType::Matrix4x4: return QMetaType::QMatrix4x4;
- case QV4::CompiledData::BuiltinType::Quaternion: return QMetaType::QQuaternion;
- case QV4::CompiledData::BuiltinType::InvalidBuiltin: break;
- };
- return QMetaType::UnknownType;
+ return processUrlForClassName(url, [](QStringView nameBase) {
+ return nameBase.toUtf8() + QByteArray("_QMLTYPE_");
+ }, []() {
+ return QByteArray("ANON_QML_TYPE_");
+ }) + QByteArray::number(classIndexCounter.fetchAndAddRelaxed(1));
}
-QQmlBindingInstantiationContext::QQmlBindingInstantiationContext(int referencingObjectIndex, const QV4::CompiledData::Binding *instantiatingBinding,
- const QString &instantiatingPropertyName, QQmlPropertyCache *referencingObjectPropertyCache)
+QByteArray QQmlPropertyCacheCreatorBase::createClassNameForInlineComponent(
+ const QUrl &baseUrl, const QString &name)
+{
+ 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,
+ const QQmlPropertyCache::ConstPtr &referencingObjectPropertyCache)
: referencingObjectIndex(referencingObjectIndex)
, instantiatingBinding(instantiatingBinding)
, instantiatingPropertyName(instantiatingPropertyName)
@@ -85,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;
@@ -99,19 +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()) {
- return enginePrivate->rawPropertyCacheForType(instantiatingProperty->propType(), instantiatingProperty->typeMinorVersion());
- } else if (const QMetaObject *vtmo = QQmlValueTypeFactory::metaObjectForMetaType(instantiatingProperty->propType())) {
- return enginePrivate->cache(vtmo, instantiatingProperty->typeMinorVersion());
+ // rawPropertyCacheForType assumes a given unspecified version means "any version".
+ // There is another overload that takes no version, which we shall not use here.
+ 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;
@@ -119,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 39778aa328..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
@@ -55,69 +19,168 @@
#include <private/qqmlmetaobject_p.h>
#include <private/qqmlpropertyresolver_p.h>
#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
-inline QQmlJS::DiagnosticMessage qQmlCompileError(const QV4::CompiledData::Location &location,
+inline QQmlError qQmlCompileError(const QV4::CompiledData::Location &location,
const QString &description)
{
- QQmlJS::DiagnosticMessage error;
- error.line = location.line;
- error.column = location.column;
- error.message = description;
+ QQmlError error;
+ 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 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 int metaTypeForPropertyType(QV4::CompiledData::BuiltinType type);
+ 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);
-
- QQmlJS::DiagnosticMessage buildMetaObjects();
-
+ 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();
+
+ /*!
+ \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,
+ Always
+ };
protected:
- QQmlJS::DiagnosticMessage buildMetaObjectRecursively(int objectIndex, const QQmlBindingInstantiationContext &context);
- QQmlRefPointer<QQmlPropertyCache> propertyCacheForObject(const CompiledObject *obj, const QQmlBindingInstantiationContext &context, QQmlJS::DiagnosticMessage *error) const;
- QQmlJS::DiagnosticMessage createMetaObject(int objectIndex, const CompiledObject *obj, const QQmlRefPointer<QQmlPropertyCache> &baseTypeCache);
+ QQmlError buildMetaObjectRecursively(int objectIndex, const QQmlBindingInstantiationContext &context, VMEMetaObjectIsRequired isVMERequired);
+ QQmlPropertyCache::ConstPtr propertyCacheForObject(const CompiledObject *obj, const QQmlBindingInstantiationContext &context, QQmlError *error) const;
+ QQmlError createMetaObject(int objectIndex, const CompiledObject *obj, const QQmlPropertyCache::ConstPtr &baseTypeCache);
- int metaTypeForParameter(const QV4::CompiledData::ParameterType &param, QString *customTypeName = nullptr);
+ QMetaType metaTypeForParameter(const QV4::CompiledData::ParameterType &param, QString *customTypeName = nullptr);
QString stringAt(int index) const { return objectContainer->stringAt(index); }
@@ -126,31 +189,99 @@ protected:
const QQmlImports * const imports;
QQmlPropertyCacheVector *propertyCaches;
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>
inline QQmlPropertyCacheCreator<ObjectContainer>::QQmlPropertyCacheCreator(QQmlPropertyCacheVector *propertyCaches,
QQmlPendingGroupPropertyBindings *pendingGroupPropertyBindings,
QQmlEnginePrivate *enginePrivate,
- const ObjectContainer *objectContainer, const QQmlImports *imports)
+ const ObjectContainer *objectContainer, const QQmlImports *imports,
+ const QByteArray &typeClassName)
: enginePrivate(enginePrivate)
, objectContainer(objectContainer)
, imports(imports)
, propertyCaches(propertyCaches)
, pendingGroupPropertyBindings(pendingGroupPropertyBindings)
+ , typeClassName(typeClassName)
+ , currentRoot(-1)
+{
+ propertyCaches->resetAndResize(objectContainer->objectCount());
+
+ using namespace icutils;
+
+ // get a list of all inline components
+
+ for (int i=0; i != objectContainer->objectCount(); ++i) {
+ const CompiledObject *obj = objectContainer->objectAt(i);
+ for (auto it = obj->inlineComponentsBegin(); it != obj->inlineComponentsEnd(); ++it) {
+ allICs.push_back(*it);
+ }
+ }
+
+ // create a graph on inline components referencing inline components
+ 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);
+
+ nodesSorted = topoSort(nodes, adjacencyList, hasCycle);
+ nodeIt = nodesSorted.rbegin();
+}
+
+template <typename ObjectContainer>
+inline QQmlError QQmlPropertyCacheCreator<ObjectContainer>::verifyNoICCycle()
{
- propertyCaches->resize(objectContainer->objectCount());
+ if (hasCycle) {
+ QQmlError diag;
+ diag.setDescription(QLatin1String("Inline components form a cycle!"));
+ return diag;
+ }
+ return {};
}
template <typename ObjectContainer>
-inline QQmlJS::DiagnosticMessage QQmlPropertyCacheCreator<ObjectContainer>::buildMetaObjects()
+inline QQmlPropertyCacheCreatorBase::IncrementalResult
+QQmlPropertyCacheCreator<ObjectContainer>::buildMetaObjectsIncrementally()
{
- QQmlBindingInstantiationContext context;
- return buildMetaObjectRecursively(/*root object*/0, context);
+ // 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
+ if (nodeIt != nodesSorted.rend()) {
+ const auto &ic = allICs[nodeIt->index()];
+ QV4::ResolvedTypeReference *typeRef = objectContainer->resolvedType(ic.nameIndex);
+ 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};
+ ++nodeIt;
+ QQmlError diag = buildMetaObjectRecursively(ic.objectIndex, m_context, VMEMetaObjectIsRequired::Always);
+ if (diag.isValid()) {
+ return {diag, false, 0};
+ }
+ typeRef->setTypePropertyCache(propertyCaches->at(ic.objectIndex));
+ Q_ASSERT(!typeRef->typePropertyCache().isNull());
+ return { QQmlError(), true, int(ic.objectIndex) };
+ }
+
+ auto diag = buildMetaObjectRecursively(/*root object*/0, m_context, VMEMetaObjectIsRequired::Maybe);
+ return {diag, false, 0};
}
template <typename ObjectContainer>
-inline QQmlJS::DiagnosticMessage QQmlPropertyCacheCreator<ObjectContainer>::buildMetaObjectRecursively(int objectIndex, const QQmlBindingInstantiationContext &context)
+inline QQmlError QQmlPropertyCacheCreator<ObjectContainer>::buildMetaObjectRecursively(int objectIndex, const QQmlBindingInstantiationContext &context, VMEMetaObjectIsRequired isVMERequired)
{
auto isAddressable = [](const QUrl &url) {
const QString fileName = url.fileName();
@@ -158,28 +289,32 @@ inline QQmlJS::DiagnosticMessage QQmlPropertyCacheCreator<ObjectContainer>::buil
};
const CompiledObject *obj = objectContainer->objectAt(objectIndex);
- bool needVMEMetaObject = obj->propertyCount() != 0 || obj->aliasCount() != 0
+ 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);
+ && !objectContainer->resolvedType(obj->inheritedTypeNameIndex)->isFullyDynamicType());
if (!needVMEMetaObject) {
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
// because interceptors can't go to the shared value type instances.
- if (context.instantiatingProperty && QQmlValueTypeFactory::isValueType(context.instantiatingProperty->propType())) {
+ if (context.instantiatingProperty && QQmlMetaType::isValueType(context.instantiatingProperty->propType())) {
if (!propertyCaches->needsVMEMetaObject(context.referencingObjectIndex)) {
const CompiledObject *obj = objectContainer->objectAt(context.referencingObjectIndex);
auto *typeRef = objectContainer->resolvedType(obj->inheritedTypeNameIndex);
Q_ASSERT(typeRef);
- QQmlRefPointer<QQmlPropertyCache> baseTypeCache = typeRef->createPropertyCache(QQmlEnginePrivate::get(enginePrivate));
- QQmlJS::DiagnosticMessage 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;
}
@@ -192,9 +327,9 @@ inline QQmlJS::DiagnosticMessage QQmlPropertyCacheCreator<ObjectContainer>::buil
}
}
- QQmlRefPointer<QQmlPropertyCache> baseTypeCache;
+ QQmlPropertyCache::ConstPtr baseTypeCache;
{
- QQmlJS::DiagnosticMessage error;
+ QQmlError error;
baseTypeCache = propertyCacheForObject(obj, context, &error);
if (error.isValid())
return error;
@@ -202,7 +337,7 @@ inline QQmlJS::DiagnosticMessage QQmlPropertyCacheCreator<ObjectContainer>::buil
if (baseTypeCache) {
if (needVMEMetaObject) {
- QQmlJS::DiagnosticMessage error = createMetaObject(objectIndex, obj, baseTypeCache);
+ QQmlError error = createMetaObject(objectIndex, obj, baseTypeCache);
if (error.isValid())
return error;
} else {
@@ -210,40 +345,51 @@ inline QQmlJS::DiagnosticMessage QQmlPropertyCacheCreator<ObjectContainer>::buil
}
}
- 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);
-
- QQmlJS::DiagnosticMessage error = buildMetaObjectRecursively(binding->value.objectIndex, context);
- 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;
}
- QQmlJS::DiagnosticMessage noError;
+ QQmlError noError;
return noError;
}
template <typename ObjectContainer>
-inline QQmlRefPointer<QQmlPropertyCache> QQmlPropertyCacheCreator<ObjectContainer>::propertyCacheForObject(const CompiledObject *obj, const QQmlBindingInstantiationContext &context, QQmlJS::DiagnosticMessage *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);
- if (typeRef->isFullyDynamicType) {
+ if (typeRef->isFullyDynamicType()) {
if (obj->propertyCount() > 0 || obj->aliasCount() > 0) {
*error = qQmlCompileError(obj->location, QQmlPropertyCacheCreatorBase::tr("Fully dynamic types cannot declare new properties."));
return nullptr;
@@ -258,70 +404,82 @@ 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 QQmlJS::DiagnosticMessage 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;
- if (objectIndex == /*root object*/0) {
- const QString path = objectContainer->url().path();
- int lastSlash = path.lastIndexOf(QLatin1Char('/'));
- if (lastSlash > -1) {
- const QStringRef nameBase = path.midRef(lastSlash + 1, path.length() - lastSlash - 5);
- if (!nameBase.isEmpty() && nameBase.at(0).isUpper())
- newClassName = nameBase.toUtf8() + "_QMLTYPE_" +
- QByteArray::number(classIndexCounter.fetchAndAddRelaxed(1));
- }
+ if (objectIndex == /*root object*/0 || int(currentRoot) == objectIndex) {
+ 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;
- int varPropCount = 0;
+ 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) {
- if (p->builtinType() == QV4::CompiledData::BuiltinType::Var)
- varPropCount++;
-
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"));
}
@@ -330,7 +488,7 @@ inline QQmlJS::DiagnosticMessage QQmlPropertyCacheCreator<ObjectContainer>::crea
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"));
}
@@ -341,19 +499,32 @@ inline QQmlJS::DiagnosticMessage QQmlPropertyCacheCreator<ObjectContainer>::crea
// 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;
}
}
@@ -367,8 +538,9 @@ inline QQmlJS::DiagnosticMessage QQmlPropertyCacheCreator<ObjectContainer>::crea
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++);
}
@@ -378,8 +550,9 @@ inline QQmlJS::DiagnosticMessage QQmlPropertyCacheCreator<ObjectContainer>::crea
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++);
}
@@ -407,10 +580,9 @@ inline QQmlJS::DiagnosticMessage QQmlPropertyCacheCreator<ObjectContainer>::crea
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();
@@ -419,23 +591,39 @@ inline QQmlJS::DiagnosticMessage QQmlPropertyCacheCreator<ObjectContainer>::crea
names.append(stringAt(param->nameIndex).toUtf8());
QString customTypeName;
- auto type = metaTypeForParameter(param->type, &customTypeName);
- if (type == QMetaType::UnknownType)
+ QMetaType type = metaTypeForParameter(param->type, &customTypeName);
+ if (!type.isValid())
return qQmlCompileError(s->location, QQmlPropertyCacheCreatorBase::tr("Invalid signal parameter type: %1").arg(customTypeName));
- paramTypes[i + 1] = type;
+ paramTypes[i] = type;
}
}
auto flags = QQmlPropertyData::defaultSignalFlags();
if (paramCount)
- flags.hasArguments = true;
+ 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);
}
@@ -448,27 +636,42 @@ inline QQmlJS::DiagnosticMessage QQmlPropertyCacheCreator<ObjectContainer>::crea
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.hasArguments = true;
+ flags.setHasArguments(true);
parameterNames << stringAt(formal->nameIndex).toUtf8();
- int type = metaTypeForParameter(formal->type);
- 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);
- 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);
}
@@ -480,101 +683,140 @@ inline QQmlJS::DiagnosticMessage QQmlPropertyCacheCreator<ObjectContainer>::crea
p = obj->propertiesBegin();
pend = obj->propertiesEnd();
for ( ; p != pend; ++p, ++propertyIdx) {
- int propertyType = 0;
- int propertTypeMinorVersion = 0;
+ QMetaType propertyType;
+ QTypeRevision propertyTypeVersion = QTypeRevision::zero();
QQmlPropertyData::Flags propertyFlags;
- const QV4::CompiledData::BuiltinType type = p->builtinType();
-
- if (type == QV4::CompiledData::BuiltinType::Var)
- propertyFlags.type = QQmlPropertyData::Flags::VarPropertyType;
-
+ const QV4::CompiledData::CommonType type = p->commonType();
- if (type != QV4::CompiledData::BuiltinType::InvalidBuiltin) {
- propertyType = metaTypeForPropertyType(type);
+ 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::Variant)
- propertyFlags.type = QQmlPropertyData::Flags::QVariantType;
+ if (type != QV4::CompiledData::CommonType::Invalid) {
+ propertyType = p->isList()
+ ? listTypeForPropertyType(type)
+ : metaTypeForPropertyType(type);
} else {
- Q_ASSERT(!p->isBuiltinType);
+ Q_ASSERT(!p->isCommonType());
QQmlType qmltype;
- if (!imports->resolveType(stringAt(p->builtinTypeOrTypeNameIndex), &qmltype, nullptr, nullptr, nullptr)) {
+ bool selfReference = false;
+ 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());
- if (qmltype.isComposite()) {
- QQmlRefPointer<QQmlTypeData> tdata = enginePrivate->typeLoader.getType(qmltype.sourceUrl());
- Q_ASSERT(tdata);
- Q_ASSERT(tdata->isComplete());
-
- auto compilationUnit = tdata->compilationUnit();
+ if (qmltype.isComposite() || qmltype.isInlineComponentType()) {
+ QQmlType compositeType;
+ if (qmltype.isInlineComponentType()) {
+ compositeType = qmltype;
+ Q_ASSERT(compositeType.isValid());
+ } else if (selfReference) {
+ compositeType = objectContainer->qmlTypeForComponent();
+ } else {
+ // 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());
+ compositeType = tdata->compilationUnit()->qmlTypeForComponent();
+ }
- if (p->isList) {
- propertyType = compilationUnit->listMetaTypeId;
+ if (p->isList()) {
+ propertyType = compositeType.qListTypeId();
} else {
- propertyType = compilationUnit->metaTypeId;
+ propertyType = compositeType.typeId();
}
} else {
- if (p->isList) {
+ if (p->isList())
propertyType = qmltype.qListTypeId();
- } else {
+ else
propertyType = qmltype.typeId();
- propertTypeMinorVersion = qmltype.minorVersion();
- }
+ 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)
- propertyFlags.isWritable = true;
+ 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, propertTypeMinorVersion, effectiveSignalIndex);
+ propertyType, propertyTypeVersion, effectiveSignalIndex);
effectiveSignalIndex++;
}
- QQmlJS::DiagnosticMessage noError;
+ QQmlError noError;
return noError;
}
template <typename ObjectContainer>
-inline int 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;
- if (!imports->resolveType(typeName, &qmltype, nullptr, nullptr, nullptr))
- return QMetaType::UnknownType;
-
- if (!qmltype.isComposite())
- return qmltype.typeId();
+ bool selfReference = false;
+ if (!imports->resolveType(
+ &enginePrivate->typeLoader, typeName, &qmltype, nullptr, nullptr, nullptr,
+ QQmlType::AnyRegistrationType, &selfReference))
+ return QMetaType();
+
+ 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->metaTypeId;
+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>
@@ -583,140 +825,49 @@ class QQmlPropertyCacheAliasCreator
public:
typedef typename ObjectContainer::CompiledObject CompiledObject;
- QQmlPropertyCacheAliasCreator(QQmlPropertyCacheVector *propertyCaches, const ObjectContainer *objectContainer);
-
- void appendAliasPropertiesToMetaObjects(QQmlEnginePrivate *enginePriv);
-
- QQmlJS::DiagnosticMessage 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);
- QQmlJS::DiagnosticMessage propertyDataForAlias(const CompiledObject &component, const QV4::CompiledData::Alias &alias, int *type, int *rev, 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>
-inline QQmlJS::DiagnosticMessage QQmlPropertyCacheAliasCreator<ObjectContainer>::propertyDataForAlias(const CompiledObject &component, const QV4::CompiledData::Alias &alias, int *type, int *minorVersion,
- QQmlPropertyData::Flags *propertyFlags, QQmlEnginePrivate *enginePriv)
+inline QQmlError QQmlPropertyCacheAliasCreator<ObjectContainer>::propertyDataForAlias(
+ const CompiledObject &component, const QV4::CompiledData::Alias &alias, QMetaType *type,
+ QTypeRevision *version, QQmlPropertyData::Flags *propertyFlags,
+ QQmlEnginePrivate *enginePriv)
{
- *type = 0;
+ *type = QMetaType();
bool writable = false;
bool resettable = false;
+ bool bindable = false;
- propertyFlags->isAlias = true;
+ 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);
@@ -733,17 +884,18 @@ inline QQmlJS::DiagnosticMessage QQmlPropertyCacheAliasCreator<ObjectContainer>:
seenAliases.append(targetAlias);
lastAlias = targetAlias;
- } while (lastAlias->aliasToLocalAlias);
+ } while (lastAlias->isAliasToLocalAlias());
- return propertyDataForAlias(component, *lastAlias, type, minorVersion, 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.:
@@ -753,118 +905,135 @@ inline QQmlJS::DiagnosticMessage QQmlPropertyCacheAliasCreator<ObjectContainer>:
QQmlPropertyCacheCreatorBase::tr("Invalid alias target"));
}
- if (typeRef->type.isValid())
- *type = typeRef->type.typeId();
- else
- *type = typeRef->compilationUnit->metaTypeId;
+ const auto referencedType = typeRef->type();
+ if (referencedType.isValid()) {
+ *type = referencedType.typeId();
+ if (!type->isValid() && referencedType.isInlineComponentType()) {
+ *type = objectContainer->qmlTypeForComponent(referencedType.elementName()).typeId();
+ Q_ASSERT(type->isValid());
+ }
+ } else {
+ *type = typeRef->compilationUnit()->metaType();
+ }
- *minorVersion = typeRef->minorVersion;
+ *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 (!QQmlValueTypeFactory::isValueType(targetProperty->propType()) && valueTypeIndex != -1) {
+ if (!QQmlMetaType::isValueType(targetPropType) && valueTypeIndex != -1) {
// deep alias property
- *type = targetProperty->propType();
- targetCache = enginePriv->propertyCacheForType(*type);
- Q_ASSERT(targetCache);
- targetProperty = targetCache->property(valueTypeIndex);
+ QQmlPropertyCache::ConstPtr typeCache
+ = QQmlMetaType::propertyCacheForType(targetPropType);
- *type = targetProperty->propType();
- writable = targetProperty->isWritable();
- resettable = targetProperty->isResettable();
+ if (!typeCache) {
+ // See if it's a half-resolved composite type
+ if (const QV4::ResolvedTypeReference *typeRef
+ = objectContainer->resolvedType(targetPropType)) {
+ typeCache = typeRef->typePropertyCache();
+ }
+ }
+ 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();
+ populateWithPropertyData(targetProperty);
if (valueTypeIndex != -1) {
- const QMetaObject *valueTypeMetaObject = QQmlValueTypeFactory::metaObjectForMetaType(*type);
- if (valueTypeMetaObject->property(valueTypeIndex).isEnumType())
- *type = QVariant::Int;
- else
- *type = valueTypeMetaObject->property(valueTypeIndex).userType();
- } else {
- if (targetProperty->isEnum()) {
- *type = QVariant::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->isWritable = !(alias.flags & QV4::CompiledData::Alias::IsReadOnly) && writable;
- propertyFlags->isResettable = resettable;
- return QQmlJS::DiagnosticMessage();
+ propertyFlags->setIsWritable(
+ writable && !alias.hasFlag(QV4::CompiledData::Alias::IsReadOnly));
+ propertyFlags->setIsResettable(resettable);
+ propertyFlags->setIsBindable(bindable);
+ return QQmlError();
}
template <typename ObjectContainer>
-inline QQmlJS::DiagnosticMessage QQmlPropertyCacheAliasCreator<ObjectContainer>::appendAliasesToPropertyCache(
+inline QQmlError QQmlPropertyCacheAliasCreator<ObjectContainer>::appendAliasesToPropertyCache(
const CompiledObject &component, int objectIndex, QQmlEnginePrivate *enginePriv)
{
const CompiledObject &object = *objectContainer->objectAt(objectIndex);
if (!object.aliasCount())
- return QQmlJS::DiagnosticMessage();
+ 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));
- int type = 0;
- int minorVersion = 0;
+ QMetaType type;
+ QTypeRevision version = QTypeRevision::zero();
QQmlPropertyData::Flags propertyFlags;
- QQmlJS::DiagnosticMessage error = propertyDataForAlias(component, *alias, &type, &minorVersion, &propertyFlags, enginePriv);
+ QQmlError error = propertyDataForAlias(component, *alias, &type, &version,
+ &propertyFlags, enginePriv);
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++,
- type, minorVersion, effectiveSignalIndex++);
+ type, version, effectiveSignalIndex++);
}
- return QQmlJS::DiagnosticMessage();
-}
-
-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;
+ return QQmlError();
}
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlpropertycachemethodarguments_p.h b/src/qml/qml/qqmlpropertycachemethodarguments_p.h
index 62f09bdfff..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,15 +28,8 @@ class QQmlPropertyCacheMethodArguments
{
public:
QQmlPropertyCacheMethodArguments *next;
-
- //for signal handler rewrites
- QString *signalParameterStringForJS;
- 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 1dff7c61a6..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,52 +15,129 @@
// We mean it.
//
-#include <private/qflagpointer_p.h>
#include <private/qqmlpropertycache_p.h>
+#include <private/qbipointer_p.h>
+
+#include <QtCore/qtaggedpointer.h>
QT_BEGIN_NAMESPACE
class QQmlPropertyCacheVector
{
public:
- QQmlPropertyCacheVector() {}
- QQmlPropertyCacheVector(QQmlPropertyCacheVector &&other)
- : data(std::move(other.data)) {}
- QQmlPropertyCacheVector &operator=(QQmlPropertyCacheVector &&other) {
- QVector<QFlagPointer<QQmlPropertyCache>> 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(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());
+ }
+ }
+
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<QFlagPointer<QQmlPropertyCache>> 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 dec696226e..bdfa41ab7a 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
@@ -52,6 +16,8 @@
//
#include <private/qobject_p.h>
+#include <QtCore/qglobal.h>
+#include <QtCore/qversionnumber.h>
QT_BEGIN_NAMESPACE
@@ -62,65 +28,161 @@ public:
enum WriteFlag {
BypassInterceptor = 0x01,
DontRemoveBinding = 0x02,
- RemoveBindingOnAliasWrite = 0x04
+ RemoveBindingOnAliasWrite = 0x04,
+ HasInternalIndex = 0x8,
};
Q_DECLARE_FLAGS(WriteFlags, WriteFlag)
typedef QObjectPrivate::StaticMetaCallFunction StaticMetaCallFunction;
struct Flags {
- enum Types {
+ friend class QQmlPropertyData;
+ 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.
// (Note: this padding is done here, because certain compilers have surprising behavior
// when an enum is declared in-between two bit fields.)
- enum { BitsLeftInFlags = 10 };
+ enum { BitsLeftInFlags = 16 };
unsigned otherBits : BitsLeftInFlags; // align to 32 bits
- // Can apply to all properties, except IsFunction
- unsigned isConstant : 1; // Has CONST flag
- unsigned isWritable : 1; // Has WRITE function
- unsigned isResettable : 1; // Has RESET function
- unsigned isAlias : 1; // Is a QML alias to another property
- unsigned isFinal : 1; // Has FINAL flag
- unsigned isOverridden : 1; // Is overridden by a extension property
- unsigned isDirect : 1; // Exists on a C++ QMetaObject
-
- unsigned type : 4; // stores an entry of Types
-
- // Apply only to IsFunctions
- unsigned isVMEFunction : 1; // Function was added by QML
- unsigned hasArguments : 1; // Function takes arguments
- unsigned isSignal : 1; // Function is a signal
- unsigned isVMESignal : 1; // Signal was added by QML
- unsigned isV4Function : 1; // Function takes QQmlV4Function* args
- unsigned isSignalHandler : 1; // Function is a signal handler
- unsigned isOverload : 1; // Function is an overload of another function
- unsigned isCloned : 1; // The function was marked as cloned
- unsigned isConstructor : 1; // The function was marked is a constructor
+ // Members of the form aORb can only be a when type is not FunctionType, and only be
+ // 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, 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
+ 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 QQmlV4FunctionPtr args
+ unsigned isSignalHandler : 1; // Function is a signal handler
+
+ // 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 isOverridden : 1; // Is overridden by a extension property
+ unsigned hasMetaObject : 1;
+ unsigned type : 3; // stores an entry of Types
// Internal QQmlPropertyCache flags
- unsigned notFullyResolved : 1; // True if the type data is to be lazily resolved
- 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) {
+ isConst = b;
+ }
+
+ void setIsWritable(bool b) {
+ Q_ASSERT(type != FunctionType);
+ isWritableORhasArguments = b;
+ }
+
+ void setIsResettable(bool b) {
+ Q_ASSERT(type != FunctionType);
+ isResettableORisSignal = b;
+ }
+
+ void setIsAlias(bool b) {
+ Q_ASSERT(type != FunctionType);
+ isAliasORisVMESignal = b;
+ }
+
+ void setIsFinal(bool b) {
+ Q_ASSERT(type != FunctionType);
+ isFinalORisV4Function = b;
+ }
+
+ void setIsOverridden(bool b) {
+ isOverridden = b;
+ }
+
+ void setIsBindable(bool b) {
+ Q_ASSERT(type != FunctionType);
+ isConstructorORisBindable = b;
+ }
+
+ void setIsRequired(bool b) {
+ Q_ASSERT(type != FunctionType);
+ isRequiredORisCloned = b;
+ }
+
+ void setIsVMEFunction(bool b) {
+ Q_ASSERT(type == FunctionType);
+ isVMEFunction = b;
+ }
+ void setHasArguments(bool b) {
+ Q_ASSERT(type == FunctionType);
+ isWritableORhasArguments = b;
+ }
+ void setIsSignal(bool b) {
+ Q_ASSERT(type == FunctionType);
+ isResettableORisSignal = b;
+ }
+ void setIsVMESignal(bool b) {
+ Q_ASSERT(type == FunctionType);
+ isAliasORisVMESignal = b;
+ }
+
+ void setIsV4Function(bool b) {
+ Q_ASSERT(type == FunctionType);
+ isFinalORisV4Function = b;
+ }
+
+ void setIsSignalHandler(bool b) {
+ Q_ASSERT(type == FunctionType);
+ isSignalHandler = b;
+ }
+
+ // TODO: Remove this once we can. Signals should not be overridable.
+ void setIsOverridableSignal(bool b) {
+ Q_ASSERT(type == FunctionType);
+ Q_ASSERT(isResettableORisSignal);
+ isOverridableSignal = b;
+ }
+
+ void setIsCloned(bool b) {
+ Q_ASSERT(type == FunctionType);
+ isRequiredORisCloned = b;
+ }
+
+ void setIsConstructor(bool b) {
+ Q_ASSERT(type == FunctionType);
+ isConstructorORisBindable = b;
+ }
+
+ void setHasMetaObject(bool b) {
+ hasMetaObject = b;
+ }
+
+ void setType(Type newType) {
+ type = newType;
+ }
};
+
inline bool operator==(const QQmlPropertyData &) const;
Flags flags() const { return m_flags; }
@@ -133,45 +195,43 @@ public:
bool isValid() const { return coreIndex() != -1; }
- bool isConstant() const { return m_flags.isConstant; }
- bool isWritable() const { return m_flags.isWritable; }
- void setWritable(bool onoff) { m_flags.isWritable = onoff; }
- bool isResettable() const { return m_flags.isResettable; }
- bool isAlias() const { return m_flags.isAlias; }
- bool isFinal() const { return m_flags.isFinal; }
+ 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 m_flags.isVMEFunction; }
- bool hasArguments() const { return m_flags.hasArguments; }
- bool isSignal() const { return m_flags.isSignal; }
- bool isVMESignal() const { return m_flags.isVMESignal; }
- bool isV4Function() const { return m_flags.isV4Function; }
+ 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 isCloned() const { return m_flags.isCloned; }
- bool isConstructor() const { return m_flags.isConstructor; }
+ bool hasMetaObject() const { return m_flags.hasMetaObject; }
- bool hasOverride() const { return overrideIndex() >= 0; }
- bool hasRevision() const { return revision() != 0; }
+ // TODO: Remove this once we can. Signals should not be overridable.
+ bool isOverridableSignal() const { return m_flags.isOverridableSignal; }
- bool isFullyResolved() const { return !m_flags.notFullyResolved; }
+ bool isCloned() const { return isFunction() && m_flags.isRequiredORisCloned; }
+ bool isConstructor() const { return isFunction() && m_flags.isConstructorORisBindable; }
+ bool isBindable() const { return !isFunction() && m_flags.isConstructorORisBindable; }
- int propType() const { Q_ASSERT(isFullyResolved()); return m_propType; }
- void setPropType(int pt)
+ bool hasOverride() const { return overrideIndex() >= 0; }
+ bool hasRevision() const { return revision() != QTypeRevision::zero(); }
+
+ QMetaType propType() const { return m_propType; }
+ void setPropType(QMetaType pt)
{
- Q_ASSERT(pt >= 0);
- Q_ASSERT(pt <= std::numeric_limits<qint16>::max());
- m_propType = quint16(pt);
+ m_propType = pt;
}
int notifyIndex() const { return m_notifyIndex; }
@@ -201,12 +261,8 @@ public:
m_coreIndex = qint16(idx);
}
- quint8 revision() const { return m_revision; }
- void setRevision(quint8 rev)
- {
- Q_ASSERT(rev <= std::numeric_limits<quint8>::max());
- m_revision = quint8(rev);
- }
+ QTypeRevision revision() const { return m_revision; }
+ void setRevision(QTypeRevision revision) { m_revision = revision; }
/* If a property is a C++ type, then we store the minor
* version of this type.
@@ -226,15 +282,39 @@ public:
*
*/
- quint8 typeMinorVersion() const { return m_typeMinorVersion; }
- void setTypeMinorVersion(quint8 rev)
+ QTypeRevision typeVersion() const { return m_typeVersion; }
+ void setTypeVersion(QTypeRevision typeVersion) { m_typeVersion = typeVersion; }
+
+ 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(rev <= std::numeric_limits<quint8>::max());
- m_typeMinorVersion = quint8(rev);
+ Q_ASSERT(!hasArguments() || !m_arguments);
+ m_flags.setHasMetaObject(true);
+ m_metaObject = metaObject;
}
- QQmlPropertyCacheMethodArguments *arguments() const { return m_arguments; }
- void setArguments(QQmlPropertyCacheMethodArguments *args) { m_arguments = args; }
+ 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)
@@ -244,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;
@@ -257,10 +338,19 @@ public:
static Flags flagsForProperty(const QMetaProperty &);
void load(const QMetaProperty &);
void load(const QMetaMethod &);
- QString name(QObject *) const;
- QString name(const QMetaObject *) const;
- void markAsOverrideOf(QQmlPropertyData *predecessor);
+ QString name(QObject *object) const { return object ? name(object->metaObject()) : QString(); }
+ QString name(const QMetaObject *metaObject) const
+ {
+ if (!metaObject || m_coreIndex == -1)
+ return QString();
+
+ return QString::fromUtf8(isFunction()
+ ? metaObject->method(m_coreIndex).name().constData()
+ : metaObject->property(m_coreIndex).name());
+ }
+
+ bool markAsOverrideOf(QQmlPropertyData *predecessor);
inline void readProperty(QObject *target, void *property) const
{
@@ -268,14 +358,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
@@ -284,51 +383,60 @@ 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.isSignal = true;
- f.type = Flags::FunctionType;
- f.isVMESignal = true;
+ f.setType(Flags::FunctionType);
+ f.setIsSignal(true);
+ f.setIsVMESignal(true);
return f;
}
static Flags defaultSlotFlags()
{
Flags f;
- f.type = Flags::FunctionType;
- f.isVMEFunction = true;
+ f.setType(Flags::FunctionType);
+ f.setIsVMEFunction(true);
return f;
}
private:
friend class QQmlPropertyCache;
- void lazyLoad(const QMetaProperty &);
- void lazyLoad(const QMetaMethod &);
- bool notFullyResolved() const { return m_flags.notFullyResolved; }
Flags m_flags;
qint16 m_coreIndex = -1;
- quint16 m_propType = 0;
// The notify index is in the range returned by QObjectPrivate::signalIndex().
// This is different from QMetaMethod::methodIndex().
qint16 m_notifyIndex = -1;
qint16 m_overrideIndex = -1;
- quint8 m_revision = 0;
- quint8 m_typeMinorVersion = 0;
qint16 m_metaObjectOffset = -1;
- QQmlPropertyCacheMethodArguments *m_arguments = nullptr;
- StaticMetaCallFunction m_staticMetaCallFunction = nullptr;
+ QTypeRevision m_revision = QTypeRevision::zero();
+ QTypeRevision m_typeVersion = QTypeRevision::zero();
+
+ QMetaType m_propType = {};
+
+ union {
+ QQmlPropertyCacheMethodArguments *m_arguments = nullptr;
+ StaticMetaCallFunction m_staticMetaCallFunction;
+ const QMetaObject *m_metaObject;
+ };
};
#if QT_POINTER_SIZE == 4
@@ -337,6 +445,8 @@ private:
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() &&
@@ -348,46 +458,37 @@ bool QQmlPropertyData::operator==(const QQmlPropertyData &other) const
QQmlPropertyData::Flags::Flags()
: otherBits(0)
- , isConstant(false)
- , isWritable(false)
- , isResettable(false)
- , isAlias(false)
- , isFinal(false)
- , isOverridden(false)
- , isDirect(false)
- , type(OtherType)
+ , isConst(false)
, isVMEFunction(false)
- , hasArguments(false)
- , isSignal(false)
- , isVMESignal(false)
- , isV4Function(false)
+ , isWritableORhasArguments(false)
+ , isResettableORisSignal(false)
+ , isAliasORisVMESignal(false)
+ , isFinalORisV4Function(false)
, isSignalHandler(false)
- , isOverload(false)
- , isCloned(false)
- , isConstructor(false)
- , notFullyResolved(false)
+ , isOverridableSignal(false)
+ , isRequiredORisCloned(false)
+ , isConstructorORisBindable(false)
+ , isOverridden(false)
+ , hasMetaObject(false)
+ , type(OtherType)
, overrideIndexIsProperty(false)
-{}
+{
+}
bool QQmlPropertyData::Flags::operator==(const QQmlPropertyData::Flags &other) const
{
- return isConstant == other.isConstant &&
- isWritable == other.isWritable &&
- isResettable == other.isResettable &&
- isAlias == other.isAlias &&
- isFinal == other.isFinal &&
- isOverridden == other.isOverridden &&
- type == other.type &&
+ return isConst == other.isConst &&
isVMEFunction == other.isVMEFunction &&
- hasArguments == other.hasArguments &&
- isSignal == other.isSignal &&
- isVMESignal == other.isVMESignal &&
- isV4Function == other.isV4Function &&
+ isWritableORhasArguments == other.isWritableORhasArguments &&
+ isResettableORisSignal == other.isResettableORisSignal &&
+ isAliasORisVMESignal == other.isAliasORisVMESignal &&
+ isFinalORisV4Function == other.isFinalORisV4Function &&
+ isOverridden == other.isOverridden &&
isSignalHandler == other.isSignalHandler &&
- isOverload == other.isOverload &&
- isCloned == other.isCloned &&
- isConstructor == other.isConstructor &&
- notFullyResolved == other.notFullyResolved &&
+ isRequiredORisCloned == other.isRequiredORisCloned &&
+ hasMetaObject == other.hasMetaObject &&
+ type == other.type &&
+ isConstructorORisBindable == other.isConstructorORisBindable &&
overrideIndexIsProperty == other.overrideIndexIsProperty;
}
@@ -397,8 +498,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 90eaca0b90..0217f7b7b5 100644
--- a/src/qml/qml/qqmlpropertyresolver.cpp
+++ b/src/qml/qml/qqmlpropertyresolver.cpp
@@ -1,52 +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())
@@ -61,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()))
@@ -78,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 d7361ea2c6..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)
@@ -73,7 +40,7 @@ QQmlPropertyValidator::QQmlPropertyValidator(QQmlEnginePrivate *enginePrivate, c
bindingPropertyDataPerObject->resize(compilationUnit->objectCount());
}
-QVector<QQmlJS::DiagnosticMessage> QQmlPropertyValidator::validate()
+QVector<QQmlError> QQmlPropertyValidator::validate()
{
return validateObject(/*root object*/0, /*instantiatingBinding*/nullptr);
}
@@ -96,26 +63,39 @@ struct BindingFinder
}
};
-QVector<QQmlJS::DiagnosticMessage> QQmlPropertyValidator::validateObject(
+QVector<QQmlError> QQmlPropertyValidator::validateObject(
int objectIndex, const QV4::CompiledData::Binding *instantiatingBinding, bool populatingValueTypeGroupProperty) const
{
const QV4::CompiledData::Object *obj = compilationUnit->objectAt(objectIndex);
+ for (auto it = obj->inlineComponentsBegin(); it != obj->inlineComponentsEnd(); ++it) {
+ const auto errors = validateObject(it->objectIndex, /* instantiatingBinding*/ nullptr);
+ if (!errors.isEmpty())
+ return errors;
+ }
- if (obj->flags & QV4::CompiledData::Object::IsComponent) {
+ 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<QQmlJS::DiagnosticMessage>();
+ return QVector<QQmlError>();
QQmlCustomParser *customParser = nullptr;
if (auto typeRef = resolvedType(obj->inheritedTypeNameIndex)) {
- if (typeRef->type.isValid())
- customParser = typeRef->type.customParser();
+
+ // 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();
}
QList<const QV4::CompiledData::Binding*> customBindings;
@@ -128,7 +108,7 @@ QVector<QQmlJS::DiagnosticMessage> QQmlPropertyValidator::validateObject(
if (!binding->isGroupProperty())
continue;
- if (binding->flags & QV4::CompiledData::Binding::IsOnAssignment)
+ if (binding->hasFlag(QV4::CompiledData::Binding::IsOnAssignment))
continue;
if (populatingValueTypeGroupProperty) {
@@ -142,9 +122,9 @@ QVector<QQmlJS::DiagnosticMessage> 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 {
@@ -152,19 +132,21 @@ QVector<QQmlJS::DiagnosticMessage> 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;
@@ -172,13 +154,14 @@ QVector<QQmlJS::DiagnosticMessage> 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,
@@ -187,9 +170,16 @@ QVector<QQmlJS::DiagnosticMessage> QQmlPropertyValidator::validateObject(
if (notInRevision) {
QString typeName = stringAt(obj->inheritedTypeNameIndex);
- auto *objectType = resolvedType(obj->inheritedTypeNameIndex);
- if (objectType && objectType->type.isValid()) {
- return recordError(binding->location, tr("\"%1.%2\" is not available in %3 %4.%5.").arg(typeName).arg(name).arg(objectType->type.module()).arg(objectType->majorVersion).arg(objectType->minorVersion));
+ if (auto *objectType = resolvedType(obj->inheritedTypeNameIndex)) {
+ const auto type = objectType->type();
+ if (type.isValid()) {
+ const auto version = objectType->version();
+ return recordError(binding->location,
+ tr("\"%1.%2\" is not available in %3 %4.%5.")
+ .arg(typeName).arg(name).arg(type.module())
+ .arg(version.majorVersion())
+ .arg(version.minorVersion()));
+ }
} else {
return recordError(binding->location, tr("\"%1.%2\" is not available due to component versioning.").arg(typeName).arg(name));
}
@@ -209,18 +199,21 @@ QVector<QQmlJS::DiagnosticMessage> QQmlPropertyValidator::validateObject(
if (name.constData()->isUpper() && !binding->isAttachedProperty()) {
QQmlType type;
QQmlImportNamespace *typeNamespace = nullptr;
- imports.resolveType(stringAt(binding->propertyNameIndex), &type, nullptr, 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
- && QQmlValueTypeFactory::metaObjectForMetaType(pd->propType())
- && !(binding->flags & QV4::CompiledData::Binding::IsOnAssignment);
- const QVector<QQmlJS::DiagnosticMessage> subObjectValidatorErrors
+ && QQmlMetaType::metaObjectForValueType(pd->propType())
+ && !binding->hasFlag(QV4::CompiledData::Binding::IsOnAssignment);
+ const QVector<QQmlError> subObjectValidatorErrors
= validateObject(binding->value.objectIndex, binding,
populatingValueTypeGroupProperty);
if (!subObjectValidatorErrors.isEmpty())
@@ -228,15 +221,25 @@ QVector<QQmlJS::DiagnosticMessage> 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) {
@@ -246,17 +249,17 @@ QVector<QQmlJS::DiagnosticMessage> 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() == qMetaTypeId<QQmlScriptString>())
+ if (pd->propType() == QMetaType::fromType<QQmlScriptString>())
error = tr( "Cannot assign multiple values to a script property");
else
error = tr( "Cannot assign multiple values to a singular property");
@@ -265,28 +268,28 @@ QVector<QQmlJS::DiagnosticMessage> 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)
loc = (*assignedGroupProperty)->valueLocation;
- if (pd && QQmlValueTypeFactory::isValueType(pd->propType()))
+ if (pd && QQmlMetaType::isValueType(pd->propType()))
return recordError(loc, tr("Property has already been assigned a value"));
return recordError(loc, tr("Cannot assign a value directly to a grouped property"));
}
- if (binding->type < QV4::CompiledData::Binding::Type_Script) {
- QQmlJS::DiagnosticMessage bindingError = validateLiteralBinding(propertyCache, pd, binding);
+ 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) {
- QQmlJS::DiagnosticMessage bindingError = validateObjectBinding(pd, name, binding);
+ } 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 (QQmlValueTypeFactory::isValueType(pd->propType())) {
- if (QQmlValueTypeFactory::metaObjectForMetaType(pd->propType())) {
+ if (QQmlMetaType::isValueType(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));
}
@@ -294,22 +297,30 @@ QVector<QQmlJS::DiagnosticMessage> QQmlPropertyValidator::validateObject(
return recordError(binding->location, tr("Invalid grouped property access"));
}
} else {
- const int typeId = pd->propType();
- 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::typeName(typeId)))
+ .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::typeName(typeId)))
- );
+ 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
}
}
}
@@ -338,32 +349,42 @@ QVector<QQmlJS::DiagnosticMessage> 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;
- QVector<QQmlJS::DiagnosticMessage> parserErrors = customParser->errors();
+ QVector<QQmlError> parserErrors = customParser->errors();
if (!parserErrors.isEmpty())
return parserErrors;
}
(*bindingPropertyDataPerObject)[objectIndex] = collectedBindingPropertyData;
- QVector<QQmlJS::DiagnosticMessage> noError;
+ QVector<QQmlError> noError;
return noError;
}
-QQmlJS::DiagnosticMessage 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"));
}
- QQmlJS::DiagnosticMessage noError;
+ 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);
@@ -381,49 +402,43 @@ QQmlJS::DiagnosticMessage QQmlPropertyValidator::validateLiteralBinding(QQmlProp
}
auto warnOrError = [&](const QString &error) {
- if (binding->type == QV4::CompiledData::Binding::Type_Null) {
- QQmlError warning;
- warning.setUrl(compilationUnit->url());
- warning.setLine(binding->valueLocation.line);
- warning.setColumn(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);
};
- switch (property->propType()) {
+ const QV4::CompiledData::Binding::Type bindingType = binding->type();
+ const auto isStringBinding = [&]() -> bool {
+ // validateLiteralBinding is not supposed to be used on scripts
+ Q_ASSERT(bindingType != QV4::CompiledData::Binding::Type_Script);
+ return bindingType == QV4::CompiledData::Binding::Type_String;
+ };
+
+ switch (property->propType().id()) {
case QMetaType::QVariant:
break;
- case QVariant::String: {
+ case QMetaType::QString: {
if (!binding->evaluatesToString()) {
return warnOrError(tr("Invalid property assignment: string expected"));
}
}
break;
- case QVariant::StringList: {
+ case QMetaType::QStringList: {
if (!binding->evaluatesToString()) {
return warnOrError(tr("Invalid property assignment: string or string list expected"));
}
}
break;
- case QVariant::ByteArray: {
- if (binding->type != QV4::CompiledData::Binding::Type_String) {
+ case QMetaType::QByteArray: {
+ if (bindingType != QV4::CompiledData::Binding::Type_String)
return warnOrError(tr("Invalid property assignment: byte array expected"));
- }
}
break;
- case QVariant::Url: {
- if (binding->type != QV4::CompiledData::Binding::Type_String) {
+ case QMetaType::QUrl: {
+ if (bindingType != QV4::CompiledData::Binding::Type_String)
return warnOrError(tr("Invalid property assignment: url expected"));
- }
}
break;
- case QVariant::UInt: {
- if (binding->type == QV4::CompiledData::Binding::Type_Number) {
+ case QMetaType::UInt: {
+ if (bindingType == QV4::CompiledData::Binding::Type_Number) {
double d = compilationUnit->bindingValueAsNumber(binding);
if (double(uint(d)) == d)
return noError;
@@ -431,8 +446,8 @@ QQmlJS::DiagnosticMessage QQmlPropertyValidator::validateLiteralBinding(QQmlProp
return warnOrError(tr("Invalid property assignment: unsigned int expected"));
}
break;
- case QVariant::Int: {
- if (binding->type == QV4::CompiledData::Binding::Type_Number) {
+ case QMetaType::Int: {
+ if (bindingType == QV4::CompiledData::Binding::Type_Number) {
double d = compilationUnit->bindingValueAsNumber(binding);
if (double(int(d)) == d)
return noError;
@@ -441,162 +456,148 @@ QQmlJS::DiagnosticMessage QQmlPropertyValidator::validateLiteralBinding(QQmlProp
}
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 QVariant::Double: {
- if (binding->type != QV4::CompiledData::Binding::Type_Number) {
+ case QMetaType::Double: {
+ if (bindingType != QV4::CompiledData::Binding::Type_Number) {
return warnOrError(tr("Invalid property assignment: number expected"));
}
}
break;
- case QVariant::Color: {
+ case QMetaType::QColor: {
bool ok = false;
- QQmlStringConverters::rgbaFromString(compilationUnit->bindingValueAsString(binding), &ok);
+ if (isStringBinding())
+ QQmlStringConverters::rgbaFromString(compilationUnit->bindingValueAsString(binding), &ok);
if (!ok) {
return warnOrError(tr("Invalid property assignment: color expected"));
}
}
break;
#if QT_CONFIG(datestring)
- case QVariant::Date: {
+ case QMetaType::QDate: {
bool ok = false;
- QQmlStringConverters::dateFromString(compilationUnit->bindingValueAsString(binding), &ok);
+ if (isStringBinding())
+ QQmlStringConverters::dateFromString(compilationUnit->bindingValueAsString(binding), &ok);
if (!ok) {
return warnOrError(tr("Invalid property assignment: date expected"));
}
}
break;
- case QVariant::Time: {
+ case QMetaType::QTime: {
bool ok = false;
- QQmlStringConverters::timeFromString(compilationUnit->bindingValueAsString(binding), &ok);
+ if (isStringBinding())
+ QQmlStringConverters::timeFromString(compilationUnit->bindingValueAsString(binding), &ok);
if (!ok) {
return warnOrError(tr("Invalid property assignment: time expected"));
}
}
break;
- case QVariant::DateTime: {
+ case QMetaType::QDateTime: {
bool ok = false;
- QQmlStringConverters::dateTimeFromString(compilationUnit->bindingValueAsString(binding), &ok);
+ if (isStringBinding())
+ QQmlStringConverters::dateTimeFromString(compilationUnit->bindingValueAsString(binding), &ok);
if (!ok) {
return warnOrError(tr("Invalid property assignment: datetime expected"));
}
}
break;
#endif // datestring
- case QVariant::Point: {
+ case QMetaType::QPoint: {
bool ok = false;
- QQmlStringConverters::pointFFromString(compilationUnit->bindingValueAsString(binding), &ok);
+ if (isStringBinding())
+ QQmlStringConverters::pointFFromString(compilationUnit->bindingValueAsString(binding), &ok);
if (!ok) {
return warnOrError(tr("Invalid property assignment: point expected"));
}
}
break;
- case QVariant::PointF: {
+ case QMetaType::QPointF: {
bool ok = false;
- QQmlStringConverters::pointFFromString(compilationUnit->bindingValueAsString(binding), &ok);
+ if (isStringBinding())
+ QQmlStringConverters::pointFFromString(compilationUnit->bindingValueAsString(binding), &ok);
if (!ok) {
return warnOrError(tr("Invalid property assignment: point expected"));
}
}
break;
- case QVariant::Size: {
+ case QMetaType::QSize: {
bool ok = false;
- QQmlStringConverters::sizeFFromString(compilationUnit->bindingValueAsString(binding), &ok);
+ if (isStringBinding())
+ QQmlStringConverters::sizeFFromString(compilationUnit->bindingValueAsString(binding), &ok);
if (!ok) {
return warnOrError(tr("Invalid property assignment: size expected"));
}
}
break;
- case QVariant::SizeF: {
+ case QMetaType::QSizeF: {
bool ok = false;
- QQmlStringConverters::sizeFFromString(compilationUnit->bindingValueAsString(binding), &ok);
+ if (isStringBinding())
+ QQmlStringConverters::sizeFFromString(compilationUnit->bindingValueAsString(binding), &ok);
if (!ok) {
return warnOrError(tr("Invalid property assignment: size expected"));
}
}
break;
- case QVariant::Rect: {
+ case QMetaType::QRect: {
bool ok = false;
- QQmlStringConverters::rectFFromString(compilationUnit->bindingValueAsString(binding), &ok);
+ if (isStringBinding())
+ QQmlStringConverters::rectFFromString(compilationUnit->bindingValueAsString(binding), &ok);
if (!ok) {
return warnOrError(tr("Invalid property assignment: rect expected"));
}
}
break;
- case QVariant::RectF: {
+ case QMetaType::QRectF: {
bool ok = false;
- QQmlStringConverters::rectFFromString(compilationUnit->bindingValueAsString(binding), &ok);
+ if (isStringBinding())
+ QQmlStringConverters::rectFFromString(compilationUnit->bindingValueAsString(binding), &ok);
if (!ok) {
return warnOrError(tr("Invalid property assignment: point expected"));
}
}
break;
- case QVariant::Bool: {
- if (binding->type != QV4::CompiledData::Binding::Type_Boolean) {
+ case QMetaType::Bool: {
+ if (bindingType != QV4::CompiledData::Binding::Type_Boolean) {
return warnOrError(tr("Invalid property assignment: boolean expected"));
}
}
break;
- case QVariant::Vector2D: {
- struct {
- float xp;
- float yp;
- } vec;
- if (!QQmlStringConverters::createFromString(QMetaType::QVector2D, compilationUnit->bindingValueAsString(binding), &vec, sizeof(vec))) {
- return warnOrError(tr("Invalid property assignment: 2D vector expected"));
- }
- }
- break;
- case QVariant::Vector3D: {
- struct {
- float xp;
- float yp;
- float zy;
- } vec;
- if (!QQmlStringConverters::createFromString(QMetaType::QVector3D, compilationUnit->bindingValueAsString(binding), &vec, sizeof(vec))) {
- return warnOrError(tr("Invalid property assignment: 3D vector expected"));
- }
- }
- break;
- case QVariant::Vector4D: {
- struct {
- float xp;
- float yp;
- float zy;
- float wp;
- } vec;
- if (!QQmlStringConverters::createFromString(QMetaType::QVector4D, compilationUnit->bindingValueAsString(binding), &vec, sizeof(vec))) {
- return warnOrError(tr("Invalid property assignment: 4D vector expected"));
- }
- }
- break;
- case QVariant::Quaternion: {
- struct {
- float wp;
- float xp;
- float yp;
- float zp;
- } vec;
- if (!QQmlStringConverters::createFromString(QMetaType::QQuaternion, compilationUnit->bindingValueAsString(binding), &vec, sizeof(vec))) {
- return warnOrError(tr("Invalid property assignment: quaternion expected"));
+ case QMetaType::QVector2D:
+ case QMetaType::QVector3D:
+ case QMetaType::QVector4D:
+ case QMetaType::QQuaternion: {
+ auto typeName = [&]() {
+ switch (property->propType().id()) {
+ case QMetaType::QVector2D: return QStringLiteral("2D vector");
+ case QMetaType::QVector3D: return QStringLiteral("3D vector");
+ case QMetaType::QVector4D: return QStringLiteral("4D vector");
+ case QMetaType::QQuaternion: return QStringLiteral("quaternion");
+ default: return QString();
+ }
+ };
+ const QVariant result = QQmlValueTypeProvider::createValueType(
+ compilationUnit->bindingValueAsString(binding),
+ property->propType());
+ if (!result.isValid()) {
+ return warnOrError(tr("Invalid property assignment: %1 expected")
+ .arg(typeName()));
}
}
break;
- case QVariant::RegExp:
- case QVariant::RegularExpression:
+ case QMetaType::QRegularExpression:
return warnOrError(tr("Invalid property assignment: regular expression expected; use /pattern/ syntax"));
default: {
// generate single literal value assignment to a list property if required
- if (property->propType() == qMetaTypeId<QList<qreal> >()) {
- if (binding->type != QV4::CompiledData::Binding::Type_Number) {
+ if (property->propType() == QMetaType::fromType<QList<qreal> >()) {
+ if (bindingType != QV4::CompiledData::Binding::Type_Number) {
return warnOrError(tr("Invalid property assignment: number or array of numbers expected"));
}
break;
- } else if (property->propType() == qMetaTypeId<QList<int> >()) {
- bool ok = (binding->type == QV4::CompiledData::Binding::Type_Number);
+ } else if (property->propType() == QMetaType::fromType<QList<int> >()) {
+ bool ok = (bindingType == QV4::CompiledData::Binding::Type_Number);
if (ok) {
double n = compilationUnit->bindingValueAsNumber(binding);
if (double(int(n)) != n)
@@ -605,35 +606,33 @@ QQmlJS::DiagnosticMessage QQmlPropertyValidator::validateLiteralBinding(QQmlProp
if (!ok)
return warnOrError(tr("Invalid property assignment: int or array of ints expected"));
break;
- } else if (property->propType() == qMetaTypeId<QList<bool> >()) {
- if (binding->type != QV4::CompiledData::Binding::Type_Boolean) {
+ } else if (property->propType() == QMetaType::fromType<QList<bool> >()) {
+ if (bindingType != QV4::CompiledData::Binding::Type_Boolean) {
return warnOrError(tr("Invalid property assignment: bool or array of bools expected"));
}
break;
- } else if (property->propType() == qMetaTypeId<QList<QUrl> >()) {
- if (binding->type != QV4::CompiledData::Binding::Type_String) {
+ } else if (property->propType() == QMetaType::fromType<QList<QUrl> >()) {
+ if (bindingType != QV4::CompiledData::Binding::Type_String) {
return warnOrError(tr("Invalid property assignment: url or array of urls expected"));
}
break;
- } else if (property->propType() == qMetaTypeId<QList<QString> >()) {
+ } else if (property->propType() == QMetaType::fromType<QList<QString> >()) {
if (!binding->evaluatesToString()) {
return warnOrError(tr("Invalid property assignment: string or array of strings expected"));
}
break;
- } else if (property->propType() == qMetaTypeId<QJSValue>()) {
+ } else if (property->propType() == QMetaType::fromType<QJSValue>()) {
break;
- } else if (property->propType() == qMetaTypeId<QQmlScriptString>()) {
+ } 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());
- if (!converter) {
- return warnOrError(tr("Invalid property assignment: unsupported type \"%1\"").arg(QString::fromLatin1(QMetaType::typeName(property->propType()))));
- }
+ return warnOrError(tr("Invalid property assignment: unsupported type \"%1\"").arg(QLatin1StringView(property->propType().name())));
}
break;
}
@@ -644,9 +643,22 @@ QQmlJS::DiagnosticMessage QQmlPropertyValidator::validateLiteralBinding(QQmlProp
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.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.qmlType.typeId() == to) {
+ toMo = compilationUnit->propertyCaches.at(icDatum.objectIndex);
+ break;
+ }
+ }
+ }
while (fromMo) {
if (fromMo == toMo)
@@ -656,40 +668,39 @@ bool QQmlPropertyValidator::canCoerce(int to, QQmlPropertyCache *fromMo) const
return false;
}
-QVector<QQmlJS::DiagnosticMessage> QQmlPropertyValidator::recordError(const QV4::CompiledData::Location &location, const QString &description) const
+QVector<QQmlError> QQmlPropertyValidator::recordError(const QV4::CompiledData::Location &location, const QString &description) const
{
- QVector<QQmlJS::DiagnosticMessage> errors;
+ QVector<QQmlError> errors;
errors.append(qQmlCompileError(location, description));
return errors;
}
-QVector<QQmlJS::DiagnosticMessage> QQmlPropertyValidator::recordError(const QQmlJS::DiagnosticMessage &error) const
+QVector<QQmlError> QQmlPropertyValidator::recordError(const QQmlError &error) const
{
- QVector<QQmlJS::DiagnosticMessage> errors;
+ QVector<QQmlError> errors;
errors.append(error);
return errors;
}
-QQmlJS::DiagnosticMessage 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
{
- QQmlJS::DiagnosticMessage noError;
+ 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;
@@ -702,7 +713,7 @@ QQmlJS::DiagnosticMessage QQmlPropertyValidator::validateObjectBinding(QQmlPrope
return noError;
}
- const int propType = property->propType();
+ const QMetaType propType = property->propType();
const auto rhsType = [&]() {
return stringAt(compilationUnit->objectAt(binding->value.objectIndex)
->inheritedTypeNameIndex);
@@ -712,43 +723,59 @@ QQmlJS::DiagnosticMessage QQmlPropertyValidator::validateObjectBinding(QQmlPrope
// 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 = enginePrivate->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::typeName(propType));
- return qQmlCompileError(binding->location, tr("Can not assign value of type \"%1\" to property \"%2\", expecting \"%3\"")
+ auto typeName = QString::fromUtf8(QMetaType(propType).name());
+ return qQmlCompileError(binding->location, tr("Cannot assign value of type \"%1\" to property \"%2\", expecting \"%3\"")
.arg(rhsType())
.arg(propertyName)
.arg(typeName));
- } else if (QQmlValueTypeFactory::isValueType(propType)) {
- return qQmlCompileError(binding->location, tr("Can not assign value of type \"%1\" to property \"%2\", expecting an object")
- .arg(rhsType()).arg(propertyName));
- } 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")
+ .arg(rhsType()).arg(propertyName));
} else {
// We want to use the raw metaObject here as the raw metaobject is the
// actual property type before we applied any extensions that might
// effect the properties on the type, but don't effect assignability
- // Using -1 for the minor version ensures that we get the raw metaObject.
- QQmlPropertyCache *propertyMetaObject = enginePrivate->rawPropertyCacheForType(propType, -1);
+ // Not passing a version ensures that we get the raw metaObject.
+ 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.qmlType.typeId() == property->propType()) {
+ propertyMetaObject
+ = compilationUnit->propertyCaches.at(icDatum.objectIndex);
+ break;
+ }
+ }
+ }
if (propertyMetaObject) {
// 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();
@@ -756,11 +783,11 @@ QQmlJS::DiagnosticMessage QQmlPropertyValidator::validateObjectBinding(QQmlPrope
if (!isAssignable) {
return qQmlCompileError(binding->valueLocation, tr("Cannot assign object of type \"%1\" to property of type \"%2\" as the former is neither the same as the latter nor a sub-class of it.")
- .arg(rhsType()).arg(QLatin1String(QMetaType::typeName(propType))));
+ .arg(rhsType()).arg(QLatin1String(property->propType().name())));
}
} else {
return qQmlCompileError(binding->valueLocation, tr("Cannot assign to property of unknown type \"%1\".")
- .arg(QLatin1String(QMetaType::typeName(propType))));
+ .arg(QLatin1String(property->propType().name())));
}
}
diff --git a/src/qml/qml/qqmlpropertyvalidator_p.h b/src/qml/qml/qqmlpropertyvalidator_p.h
index 74a1281927..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,27 +28,31 @@ 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<QQmlJS::DiagnosticMessage> validate();
+ QVector<QQmlError> validate();
+
+ QQmlPropertyCache::ConstPtr rootPropertyCache() const { return propertyCaches.at(0); }
+ QUrl documentSourceUrl() const { return compilationUnit->url(); }
private:
- QVector<QQmlJS::DiagnosticMessage> validateObject(
+ QVector<QQmlError> validateObject(
int objectIndex, const QV4::CompiledData::Binding *instantiatingBinding,
bool populatingValueTypeGroupProperty = false) const;
- QQmlJS::DiagnosticMessage validateLiteralBinding(
- QQmlPropertyCache *propertyCache, QQmlPropertyData *property,
+ QQmlError validateLiteralBinding(
+ const QQmlPropertyCache::ConstPtr &propertyCache, const QQmlPropertyData *property,
const QV4::CompiledData::Binding *binding) const;
- QQmlJS::DiagnosticMessage validateObjectBinding(
- QQmlPropertyData *property, const QString &propertyName,
+ QQmlError validateObjectBinding(
+ 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<QQmlJS::DiagnosticMessage> recordError(
+ Q_REQUIRED_RESULT QVector<QQmlError> recordError(
const QV4::CompiledData::Location &location, const QString &description) const;
- Q_REQUIRED_RESULT QVector<QQmlJS::DiagnosticMessage> recordError(
- const QQmlJS::DiagnosticMessage &error) const;
+ Q_REQUIRED_RESULT QVector<QQmlError> recordError(const QQmlError &error) const;
QString stringAt(int index) const { return compilationUnit->stringAt(index); }
QV4::ResolvedTypeReference *resolvedType(int id) const
{
@@ -92,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 e1500f70fb..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;
}
@@ -65,54 +29,96 @@ QQmlProxyMetaObject::~QQmlProxyMetaObject()
proxies = nullptr;
}
+QObject *QQmlProxyMetaObject::getProxy(int index)
+{
+ if (!proxies) {
+ proxies = new QObject *[metaObjects->size()];
+ ::memset(proxies, 0, sizeof(QObject *) * metaObjects->size());
+ }
+
+ if (!proxies[index]) {
+ const ProxyData &data = metaObjects->at(index);
+ if (!data.createFunc)
+ return nullptr;
+
+ QObject *proxy = data.createFunc(object);
+ const QMetaObject *metaObject = proxy->metaObject();
+ proxies[index] = proxy;
+
+ int localOffset = data.metaObject->methodOffset();
+ int methodOffset = metaObject->methodOffset();
+ int methods = metaObject->methodCount() - methodOffset;
+
+ // ### - Can this be done more optimally?
+ for (int jj = 0; jj < methods; ++jj) {
+ QMetaMethod method =
+ metaObject->method(jj + methodOffset);
+ if (method.methodType() == QMetaMethod::Signal)
+ QQmlPropertyPrivate::connect(proxy, methodOffset + jj, object, localOffset + jj);
+ }
+ }
+
+ return proxies[index];
+}
+
int QQmlProxyMetaObject::metaCall(QObject *o, QMetaObject::Call c, int id, void **a)
{
Q_ASSERT(object == o);
- if ((c == QMetaObject::ReadProperty ||
- c == QMetaObject::WriteProperty) &&
- id >= metaObjects->constLast().propertyOffset) {
-
- for (int ii = 0; ii < metaObjects->count(); ++ii) {
- const ProxyData &data = metaObjects->at(ii);
- if (id >= data.propertyOffset) {
- if (!proxies) {
- proxies = new QObject*[metaObjects->count()];
- ::memset(proxies, 0,
- sizeof(QObject *) * metaObjects->count());
- }
-
- if (!proxies[ii]) {
- QObject *proxy = data.createFunc(object);
- const QMetaObject *metaObject = proxy->metaObject();
- proxies[ii] = proxy;
-
- int localOffset = data.metaObject->methodOffset();
- int methodOffset = metaObject->methodOffset();
- int methods = metaObject->methodCount() - methodOffset;
-
- // ### - Can this be done more optimally?
- for (int jj = 0; jj < methods; ++jj) {
- QMetaMethod method =
- metaObject->method(jj + methodOffset);
- if (method.methodType() == QMetaMethod::Signal)
- QQmlPropertyPrivate::connect(proxy, methodOffset + jj, object, localOffset + jj);
- }
- }
-
- int proxyOffset = proxies[ii]->metaObject()->propertyOffset();
- int proxyId = id - data.propertyOffset + proxyOffset;
-
- return proxies[ii]->qt_metacall(c, proxyId, a);
- }
+ switch (c) {
+ case QMetaObject::ReadProperty:
+ case QMetaObject::WriteProperty: {
+ if (id < metaObjects->constLast().propertyOffset)
+ break;
+
+ for (int ii = 0; ii < metaObjects->size(); ++ii) {
+ const int globalPropertyOffset = metaObjects->at(ii).propertyOffset;
+ 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;
}
+
+ 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)
@@ -121,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 2b7a980361..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,18 +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:
- QList<ProxyData> *metaObjects;
+ QObject *getProxy(int index);
+
+ 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 6ac30d3ab5..fa9a41e801 100644
--- a/src/qml/qml/qqmlscriptblob.cpp
+++ b/src/qml/qml/qqmlscriptblob.cpp
@@ -1,46 +1,12 @@
-/****************************************************************************
-**
-** 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>
#include <private/qqmlscriptblob_p.h>
#include <private/qqmlscriptdata_p.h>
+#include <private/qqmlsourcecoordinate_p.h>
+#include <private/qqmlcontextdata_p.h>
#include <private/qv4runtimecodegen_p.h>
#include <private/qv4script_p.h>
@@ -66,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 (!diskCacheDisabled() || diskCacheForced()) {
- 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;
@@ -95,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;
@@ -130,28 +100,26 @@ void QQmlScriptBlob::dataReceived(const SourceCodeData &data)
unit = std::move(irUnit.javaScriptCompilationUnit);
}
- auto executableUnit = QV4::ExecutableCompilationUnit::create(std::move(unit));
-
- if ((!diskCacheDisabled() || diskCacheForced()) && !isDebugging()) {
+ 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 QV4::CompiledData::Unit *unit)
+void QQmlScriptBlob::initializeFromCachedUnit(const QQmlPrivate::CachedQmlUnit *cachedUnit)
{
- initializeFromCompilationUnit(QV4::ExecutableCompilationUnit::create(
- QV4::CompiledData::CompilationUnit(unit, urlString(), finalUrlString())));
+ initializeFromCompilationUnit(QQml::makeRefPointer<QV4::CompiledData::CompilationUnit>(
+ cachedUnit->qmlData, cachedUnit->aotCompiledFunctions, urlString(), finalUrlString()));
}
void QQmlScriptBlob::done()
@@ -160,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(script.location.line);
- error.setColumn(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);
@@ -181,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);
@@ -195,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();
}
@@ -216,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);
- if (!addImport(import, &errors)) {
+ 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;
@@ -245,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 10c0437e7b..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,17 +39,19 @@ public:
};
QQmlRefPointer<QQmlScriptData> scriptData() const;
+ bool isNative() const;
protected:
void dataReceived(const SourceCodeData &) override;
- void initializeFromCachedUnit(const QV4::CompiledData::Unit *unit) override;
+ void initializeFromCachedUnit(const QQmlPrivate::CachedQmlUnit *unit) override;
void done() override;
QString stringAt(int index) const override;
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 ae268ca904..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,84 +13,81 @@
QT_BEGIN_NAMESPACE
-QQmlScriptData::QQmlScriptData()
- : typeNameCache(nullptr)
- , m_loaded(false)
+QQmlRefPointer<QQmlContextData> QQmlScriptData::qmlContextDataForContext(
+ const QQmlRefPointer<QQmlContextData> &parentQmlContextData)
{
-}
-
-QQmlContextData *QQmlScriptData::qmlContextDataForContext(QQmlContextData *parentQmlContextData)
-{
- Q_ASSERT(parentQmlContextData && parentQmlContextData->engine);
+ Q_ASSERT(parentQmlContextData && parentQmlContextData->engine());
- if (m_precompiledScript->isESModule())
+ if (!m_precompiledScript || m_precompiledScript->isESModule())
return nullptr;
- auto qmlContextData = new QQmlContextData();
+ QQmlRefPointer<QQmlContextData> qmlContextData = m_precompiledScript->isSharedLibrary()
+ ? QQmlContextData::createRefCounted(QQmlRefPointer<QQmlContextData>())
+ : QQmlContextData::createRefCounted(parentQmlContextData);
- qmlContextData->isInternal = true;
- qmlContextData->isJSContext = true;
+ qmlContextData->setInternal(true);
+ qmlContextData->setJSContext(true);
if (m_precompiledScript->isSharedLibrary())
- qmlContextData->isPragmaLibraryContext = true;
+ qmlContextData->setPragmaLibraryContext(true);
else
- qmlContextData->isPragmaLibraryContext = parentQmlContextData->isPragmaLibraryContext;
- qmlContextData->baseUrl = url;
- qmlContextData->baseUrlString = urlString;
+ qmlContextData->setPragmaLibraryContext(parentQmlContextData->isPragmaLibraryContext());
+ qmlContextData->setBaseUrl(url);
+ qmlContextData->setBaseUrlString(urlString);
// For backward compatibility, if there are no imports, we need to use the
// imports from the parent context. See QTBUG-17518.
if (!typeNameCache->isEmpty()) {
- qmlContextData->imports = typeNameCache;
+ qmlContextData->setImports(typeNameCache);
} else if (!m_precompiledScript->isSharedLibrary()) {
- qmlContextData->imports = parentQmlContextData->imports;
- qmlContextData->importedScripts = parentQmlContextData->importedScripts;
+ qmlContextData->setImports(parentQmlContextData->imports());
+ qmlContextData->setImportedScripts(parentQmlContextData->importedScripts());
}
- if (!m_precompiledScript->isSharedLibrary()) {
- qmlContextData->setParent(parentQmlContextData);
- } else {
- qmlContextData->engine = parentQmlContextData->engine; // Fix for QTBUG-21620
- }
+ if (m_precompiledScript->isSharedLibrary())
+ qmlContextData->setEngine(parentQmlContextData->engine()); // Fix for QTBUG-21620
- QV4::ExecutionEngine *v4 = parentQmlContextData->engine->handle();
+ QV4::ExecutionEngine *v4 = parentQmlContextData->engine()->handle();
QV4::Scope scope(v4);
QV4::ScopedObject scriptsArray(scope);
- if (qmlContextData->importedScripts.isNullOrUndefined()) {
- scriptsArray = v4->newArrayObject(scripts.count());
- qmlContextData->importedScripts.set(v4, scriptsArray);
+ if (qmlContextData->importedScripts().isNullOrUndefined()) {
+ scriptsArray = v4->newArrayObject(scripts.size());
+ qmlContextData->setImportedScripts(
+ QV4::PersistentValue(v4, scriptsArray.asReturnedValue()));
} else {
- scriptsArray = qmlContextData->importedScripts.valueRef();
+ scriptsArray = qmlContextData->importedScripts().valueRef();
}
QV4::ScopedValue v(scope);
- for (int ii = 0; ii < scripts.count(); ++ii)
- scriptsArray->put(ii, (v = scripts.at(ii)->scriptData()->scriptValueForContext(qmlContextData)));
+ for (int ii = 0; ii < scripts.size(); ++ii) {
+ v = scripts.at(ii)->scriptData()->scriptValueForContext(qmlContextData);
+ scriptsArray->put(ii, v);
+ }
return qmlContextData;
}
-QV4::ReturnedValue QQmlScriptData::scriptValueForContext(QQmlContextData *parentQmlContextData)
+QV4::ReturnedValue QQmlScriptData::scriptValueForContext(
+ const QQmlRefPointer<QQmlContextData> &parentQmlContextData)
{
if (m_loaded)
return m_value.value();
- Q_ASSERT(parentQmlContextData && parentQmlContextData->engine);
- QV4::ExecutionEngine *v4 = parentQmlContextData->engine->handle();
+ Q_ASSERT(parentQmlContextData && parentQmlContextData->engine());
+ QV4::ExecutionEngine *v4 = parentQmlContextData->engine()->handle();
QV4::Scope scope(v4);
- if (!hasEngine()) {
- addToEngine(parentQmlContextData->engine);
- addref();
+ QV4::Scoped<QV4::QmlContext> qmlExecutionContext(scope);
+ if (auto qmlContextData = qmlContextDataForContext(parentQmlContextData)) {
+ qmlExecutionContext = QV4::QmlContext::create(v4->rootContext(), std::move(qmlContextData),
+ /* scopeObject: */ nullptr);
}
- QQmlContextDataRef qmlContextData = qmlContextDataForContext(parentQmlContextData);
- QV4::Scoped<QV4::QmlContext> qmlExecutionContext(scope);
- if (qmlContextData)
- qmlExecutionContext =
- QV4::QmlContext::create(v4->rootContext(), qmlContextData, /* scopeObject: */ nullptr);
+ QV4::Scoped<QV4::Module> module(
+ scope,
+ v4->executableCompilationUnit(QQmlRefPointer<QV4::CompiledData::CompilationUnit>(
+ m_precompiledScript))->instantiate());
- QV4::Scoped<QV4::Module> module(scope, m_precompiledScript->instantiate(v4));
if (module) {
- if (qmlContextData) {
+ if (qmlExecutionContext) {
module->d()->scope->outer.set(v4, qmlExecutionContext->d());
qmlExecutionContext->d()->qml()->module.set(v4, module->d());
}
@@ -141,7 +102,7 @@ QV4::ReturnedValue QQmlScriptData::scriptValueForContext(QQmlContextData *parent
}
QV4::ScopedValue value(scope);
- if (qmlContextData)
+ if (qmlExecutionContext)
value = qmlExecutionContext->d()->qml();
else if (module)
value = module->d();
@@ -154,13 +115,4 @@ QV4::ReturnedValue QQmlScriptData::scriptValueForContext(QQmlContextData *parent
return value->asReturnedValue();
}
-void QQmlScriptData::clear()
-{
- typeNameCache = nullptr;
- scripts.clear();
-
- // An addref() was made when the QQmlCleanup was added to the engine.
- release();
-}
-
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlscriptdata_p.h b/src/qml/qml/qqmlscriptdata_p.h
index 80b65b699c..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
@@ -52,11 +16,10 @@
//
#include <private/qqmlrefcount_p.h>
-#include <private/qqmlcleanup_p.h>
#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>
@@ -65,19 +28,12 @@ QT_BEGIN_NAMESPACE
class QQmlTypeNameCache;
class QQmlContextData;
-// QQmlScriptData instances are created, uninitialized, by the loader in the
-// load thread. The first time they are used by the VME, they are initialized which
-// creates their v8 objects and they are referenced and added to the engine's cleanup
-// list. During QQmlCleanup::clear() all v8 resources are destroyed, and the
-// reference that was created is released but final deletion only occurs once all the
-// references as released. This is all intended to ensure that the v8 resources are
-// only created and destroyed in the main thread :)
-class Q_AUTOTEST_EXPORT QQmlScriptData : public QQmlCleanup, public QQmlRefCount
+class Q_AUTOTEST_EXPORT QQmlScriptData final : public QQmlRefCounted<QQmlScriptData>
{
private:
friend class QQmlTypeLoader;
- QQmlScriptData();
+ QQmlScriptData() = default;
public:
QUrl url;
@@ -85,21 +41,21 @@ public:
QQmlRefPointer<QQmlTypeNameCache> typeNameCache;
QVector<QQmlRefPointer<QQmlScriptBlob>> scripts;
- QV4::ReturnedValue scriptValueForContext(QQmlContextData *parentCtxt);
+ QV4::ReturnedValue scriptValueForContext(const QQmlRefPointer<QQmlContextData> &parentCtxt);
- QQmlRefPointer<QV4::ExecutableCompilationUnit> compilationUnit() const { return m_precompiledScript; }
-
-protected:
- void clear() override; // From QQmlCleanup
+ QQmlRefPointer<QV4::CompiledData::CompilationUnit> compilationUnit() const
+ {
+ return m_precompiledScript;
+ }
private:
friend class QQmlScriptBlob;
- void initialize(QQmlEngine *);
- QQmlContextData *qmlContextDataForContext(QQmlContextData *parentQmlContextData);
+ 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 1f30c5a046..debc3d16c1 100644
--- a/src/qml/qml/qqmlscriptstring.h
+++ b/src/qml/qml/qqmlscriptstring.h
@@ -1,46 +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
#ifndef QQMLSCRIPTSTRING_H
#define QQMLSCRIPTSTRING_H
#include <QtQml/qtqmlglobal.h>
+#include <QtQml/qqml.h>
#include <QtCore/qstring.h>
#include <QtCore/qshareddata.h>
#include <QtCore/qmetatype.h>
@@ -57,6 +22,7 @@ namespace QV4 {
}
class Q_QML_EXPORT QQmlScriptString
{
+ Q_GADGET
public:
QQmlScriptString();
QQmlScriptString(const QQmlScriptString &);
@@ -83,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/qqmlstaticmetaobject.cpp b/src/qml/qml/qqmlstaticmetaobject.cpp
deleted file mode 100644
index 218d0134fd..0000000000
--- a/src/qml/qml/qqmlstaticmetaobject.cpp
+++ /dev/null
@@ -1,51 +0,0 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
-
-#include "qqmlstaticmetaobject_p.h"
-
-QT_BEGIN_NAMESPACE
-
-int *QQmlStaticMetaObject::constructorParameterTypes(int index, ArgTypeStorage *dummy,
- QByteArray *unknownTypeError) const
-{
- QMetaMethod m = _m.asT2()->constructor(index);
- return methodParameterTypes(m, dummy, unknownTypeError);
-}
-
-QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlstaticmetaobject_p.h b/src/qml/qml/qqmlstaticmetaobject_p.h
deleted file mode 100644
index e1ca496080..0000000000
--- a/src/qml/qml/qqmlstaticmetaobject_p.h
+++ /dev/null
@@ -1,68 +0,0 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
-
-#ifndef QQMLSTATICMETAOBJECT_P_H
-#define QQMLSTATICMETAOBJECT_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/qqmlobjectorgadget_p.h>
-
-QT_BEGIN_NAMESPACE
-
-class QQmlStaticMetaObject : public QQmlObjectOrGadget {
-public:
- QQmlStaticMetaObject(const QMetaObject* metaObject)
- : QQmlObjectOrGadget(metaObject)
- {}
- int *constructorParameterTypes(int index, ArgTypeStorage *dummy, QByteArray *unknownTypeError) const;
-};
-
-QT_END_NAMESPACE
-
-#endif // QQMLSTATICMETAOBJECT_P_H
diff --git a/src/qml/qml/qqmlstringconverters.cpp b/src/qml/qml/qqmlstringconverters.cpp
index e53f90b45b..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,25 +12,9 @@
QT_BEGIN_NAMESPACE
-QVariant QQmlStringConverters::variantFromString(const QString &s)
+QVariant QQmlStringConverters::variantFromString(const QString &s, QMetaType preferredType, bool *ok)
{
- if (s.isEmpty())
- return QVariant(s);
-
- bool ok = false;
- QRectF r = rectFFromString(s, &ok);
- if (ok) return QVariant(r);
- QPointF p = pointFFromString(s, &ok);
- if (ok) return QVariant(p);
- QSizeF sz = sizeFFromString(s, &ok);
- if (ok) return QVariant(sz);
-
- return QQml_valueTypeProvider()->createVariantFromString(s);
-}
-
-QVariant QQmlStringConverters::variantFromString(const QString &s, int preferredType, bool *ok)
-{
- switch (preferredType) {
+ switch (preferredType.id()) {
case QMetaType::Int:
return QVariant(int(qRound(s.toDouble(ok))));
case QMetaType::UInt:
@@ -91,8 +39,17 @@ QVariant QQmlStringConverters::variantFromString(const QString &s, int preferred
return QVariant::fromValue(rectFFromString(s, ok));
case QMetaType::QRect:
return QVariant::fromValue(rectFFromString(s, ok).toRect());
- default:
- return QQml_valueTypeProvider()->createVariantFromString(preferredType, s, ok);
+ default: {
+ const QVariant ret = QQmlValueTypeProvider::createValueType(s, preferredType);
+ if (ret.isValid()) {
+ if (ok)
+ *ok = true;
+ return ret;
+ }
+ if (ok)
+ *ok = false;
+ return QVariant();
+ }
}
}
@@ -125,9 +82,6 @@ QDateTime QQmlStringConverters::dateTimeFromString(const QString &s, bool *ok)
{
QDateTime d = QDateTime::fromString(s, Qt::ISODate);
if (ok) *ok = d.isValid();
- // V8 never parses a date string as local time. For consistency do the same here.
- if (d.timeSpec() == Qt::LocalTime)
- d.setTimeSpec(Qt::UTC);
return d;
}
#endif // datestring
@@ -135,168 +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 = s.leftRef(index).toDouble(&xGood);
- qreal yCoord = s.midRef(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 = s.leftRef(index).toDouble(&wGood);
- qreal height = s.midRef(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 = s.leftRef(index).toDouble(&xGood);
- int index2 = s.indexOf(QLatin1Char(','), index+1);
- qreal y = s.midRef(index+1, index2-index-1).toDouble(&yGood);
- index = s.indexOf(QLatin1Char('x'), index2+1);
- qreal width = s.midRef(index2+1, index-index2-1).toDouble(&wGood);
- qreal height = s.midRef(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);
-}
-
-bool QQmlStringConverters::createFromString(int type, const QString &s, void *data, size_t n)
-{
- Q_ASSERT(data);
-
- bool ok = false;
-
- switch (type) {
- case QMetaType::Int:
- {
- Q_ASSERT(n >= sizeof(int));
- int *p = reinterpret_cast<int *>(data);
- *p = int(qRound(s.toDouble(&ok)));
- return ok;
- }
- case QMetaType::UInt:
- {
- Q_ASSERT(n >= sizeof(uint));
- uint *p = reinterpret_cast<uint *>(data);
- *p = uint(qRound(s.toDouble(&ok)));
- return ok;
- }
-#if QT_CONFIG(datestring)
- case QMetaType::QDate:
- {
- Q_ASSERT(n >= sizeof(QDate));
- QDate *p = reinterpret_cast<QDate *>(data);
- *p = dateFromString(s, &ok);
- return ok;
- }
- case QMetaType::QTime:
- {
- Q_ASSERT(n >= sizeof(QTime));
- QTime *p = reinterpret_cast<QTime *>(data);
- *p = timeFromString(s, &ok);
- return ok;
- }
- case QMetaType::QDateTime:
- {
- Q_ASSERT(n >= sizeof(QDateTime));
- QDateTime *p = reinterpret_cast<QDateTime *>(data);
- *p = dateTimeFromString(s, &ok);
- return ok;
- }
-#endif // datestring
- case QMetaType::QPointF:
- {
- Q_ASSERT(n >= sizeof(QPointF));
- QPointF *p = reinterpret_cast<QPointF *>(data);
- *p = pointFFromString(s, &ok);
- return ok;
- }
- case QMetaType::QPoint:
- {
- Q_ASSERT(n >= sizeof(QPoint));
- QPoint *p = reinterpret_cast<QPoint *>(data);
- *p = pointFFromString(s, &ok).toPoint();
- return ok;
- }
- case QMetaType::QSizeF:
- {
- Q_ASSERT(n >= sizeof(QSizeF));
- QSizeF *p = reinterpret_cast<QSizeF *>(data);
- *p = sizeFFromString(s, &ok);
- return ok;
- }
- case QMetaType::QSize:
- {
- Q_ASSERT(n >= sizeof(QSize));
- QSize *p = reinterpret_cast<QSize *>(data);
- *p = sizeFFromString(s, &ok).toSize();
- return ok;
- }
- case QMetaType::QRectF:
- {
- Q_ASSERT(n >= sizeof(QRectF));
- QRectF *p = reinterpret_cast<QRectF *>(data);
- *p = rectFFromString(s, &ok);
- return ok;
- }
- case QMetaType::QRect:
- {
- Q_ASSERT(n >= sizeof(QRect));
- QRect *p = reinterpret_cast<QRect *>(data);
- *p = rectFFromString(s, &ok).toRect();
- return ok;
- }
- default:
- return QQml_valueTypeProvider()->createValueFromString(type, s, data, n);
- }
+ 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 215f0c0aaf..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,22 +30,92 @@ class QByteArray;
namespace QQmlStringConverters
{
- Q_QML_PRIVATE_EXPORT QVariant variantFromString(const QString &);
- 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);
- Q_QML_PRIVATE_EXPORT bool createFromString(int, const QString &, void *, size_t);
+ // 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 874bcd4bca..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,36 +17,44 @@
QT_BEGIN_NAMESPACE
QQmlTypePrivate::QQmlTypePrivate(QQmlType::RegistrationType type)
- : regType(type), iid(nullptr), typeId(0), listId(0), revision(0),
- 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->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.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:
+ new (&extraData.inlineComponentTypeData) QUrl();
+ break;
+ case QQmlType::SequentialContainerType:
+ new (&extraData.sequentialContainerTypeData) QMetaSequence();
break;
default: qFatal("QQmlTypePrivate Internal Error.");
}
@@ -90,21 +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:
+ extraData.inlineComponentTypeData.~QUrl();
+ break;
+ case QQmlType::SequentialContainerType:
+ extraData.sequentialContainerTypeData.~QMetaSequence();
break;
default: //Also InterfaceType, because it has no extra data
break;
@@ -126,34 +109,33 @@ QHashedString QQmlType::module() const
return d->module;
}
-int QQmlType::majorVersion() const
+QTypeRevision QQmlType::version() const
{
if (!d)
- return -1;
- return d->version_maj;
+ return QTypeRevision();
+ return d->version;
}
-int QQmlType::minorVersion() const
+bool QQmlType::availableInVersion(QTypeRevision version) const
{
if (!d)
- return -1;
- return d->version_min;
-}
+ return false;
-bool QQmlType::availableInVersion(int vmajor, int vminor) const
-{
- Q_ASSERT(vmajor >= 0 && vminor >= 0);
- if (!d)
+ if (!version.hasMajorVersion())
+ return true;
+
+ if (version.majorVersion() != d->version.majorVersion())
return false;
- return vmajor == d->version_maj && vminor >= d->version_min;
+
+ return !version.hasMinorVersion() || version.minorVersion() >= d->version.minorVersion();
}
-bool QQmlType::availableInVersion(const QHashedStringRef &module, int vmajor, int vminor) const
+bool QQmlType::availableInVersion(const QHashedStringRef &module, QTypeRevision version) const
{
- Q_ASSERT(vmajor >= 0 && vminor >= 0);
- if (!d)
+ if (!d || module != d->module)
return false;
- return module == d->module && vmajor == d->version_maj && vminor >= d->version_min;
+
+ return availableInVersion(version);
}
QQmlType QQmlTypePrivate::resolveCompositeBaseType(QQmlEnginePrivate *engine) const
@@ -164,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());
@@ -178,69 +161,72 @@ 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)
{
- int i = index;
- i -= mo->propertyOffset();
- if (i < 0 && mo->d.superdata)
- return isPropertyRevisioned(mo->d.superdata, index);
-
- const QMetaObjectPrivate *mop = reinterpret_cast<const QMetaObjectPrivate*>(mo->d.data);
- if (i >= 0 && i < mop->propertyCount) {
- int handle = mop->propertyData + 3*i;
- int flags = mo->d.data[handle + 2];
-
- return (flags & Revisioned);
- }
-
- return false;
+ return mo->property(index).revision();
}
-void QQmlTypePrivate::init() const
+const QQmlTypePrivate::ProxyMetaObjects *QQmlTypePrivate::init() const
{
- if (isSetup)
- return;
+ if (const ProxyMetaObjects *result = proxyMetaObjects.loadRelaxed())
+ return result;
- QMutexLocker lock(QQmlMetaType::typeRegistrationLock());
- if (isSetup)
- 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();
}
- if (regType == QQmlType::CppType) {
- // Setup extended meta object
+ QList<QQmlProxyMetaObject::ProxyData> metaObjects;
+
+ auto setupExtendedMetaObject = [&](const QMetaObject *extMetaObject,
+ QObject *(*extFunc)(QObject *)) {
+ if (!extMetaObject)
+ return;
+
// XXX - very inefficient
- if (extraData.cd->extFunc) {
- QMetaObjectBuilder builder;
- QQmlMetaType::clone(builder, extraData.cd->extMetaObject, extraData.cd->extMetaObject,
- extraData.cd->extMetaObject);
- builder.setFlags(QMetaObjectBuilder::DynamicMetaObject);
- QMetaObject *mmo = builder.toMetaObject();
- mmo->d.superdata = mo;
- QQmlProxyMetaObject::ProxyData data = { mmo, extraData.cd->extFunc, 0, 0 };
- metaObjects << data;
- }
- }
+ QMetaObjectBuilder builder;
+ 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.singletonTypeData->extMetaObject, extraData.singletonTypeData->extFunc);
+ else if (regType == QQmlType::CppType)
+ 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;
@@ -260,52 +246,75 @@ void QQmlTypePrivate::init() const
}
}
- isSetup = 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 && isComposite())
- ? compositePropertyCache(engine)
- : nullptr;
+ if (const Enums *result = enums.loadRelaxed())
+ return result;
- const QMetaObject *metaObject = !isEnumFromCacheSetup
- ? baseMetaObject // beware: It could be a singleton type without metaobject
- : 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();
+ // beware: It could be a singleton type without metaobject
- QMutexLocker lock(QQmlMetaType::typeRegistrationLock());
+ if (cache)
+ insertEnumsFromPropertyCache(newEnums, cache);
- if (cache) {
- insertEnumsFromPropertyCache(cache);
- isEnumFromCacheSetup = 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(metaObject);
- isEnumFromBaseSetup = 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);
@@ -322,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);
}
}
}
@@ -395,35 +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);
+ insertEnums(enums, cppMetaObject);
}
void QQmlTypePrivate::setName(const QString &uri, const QString &element)
@@ -437,7 +452,7 @@ 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();
}
@@ -458,46 +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;
-
- d->init();
-
- QObject *rv = (QObject *)operator new(d->extraData.cd->allocationSize);
- d->extraData.cd->newFunc(rv);
+ void *unused;
+ return create(&unused, 0);
+}
- if (rv && !d->metaObjects.isEmpty())
- (void)new QQmlProxyMetaObject(rv, &d->metaObjects);
+/*!
+ \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.
- return rv;
-}
+ \note This function is used to allocate the QQmlData next to the object in the
+ QQmlObjectCreator.
-void QQmlType::create(QObject **out, void **memory, size_t additionalMemory) const
+ \overload
+ */
+QObject *QQmlType::create(void **memory, size_t additionalMemory) const
{
if (!d || !isCreatable())
- return;
-
- d->init();
+ return nullptr;
- QObject *rv = (QObject *)operator new(d->extraData.cd->allocationSize + additionalMemory);
- d->extraData.cd->newFunc(rv);
+ QObject *rv = (QObject *)operator new(d->extraData.cppTypeData->allocationSize + additionalMemory);
+ d->extraData.cppTypeData->newFunc(rv, d->extraData.cppTypeData->userdata);
- if (rv && !d->metaObjects.isEmpty())
- (void)new QQmlProxyMetaObject(rv, &d->metaObjects);
+ createProxy(rv);
+ *memory = ((char *)rv) + d->extraData.cppTypeData->allocationSize;
+ return rv;
+}
- *out = rv;
- *memory = ((char *)rv) + d->extraData.cd->allocationSize;
+/*!
+ \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
+{
+ 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
@@ -506,42 +543,82 @@ 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.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
{
- if (!d || d->regType != CppType)
+ if (!d)
return nullptr;
- return d->extraData.cd->extFunc;
+
+ switch (d->regType) {
+ case CppType:
+ return d->extraData.cppTypeData->extFunc;
+ case SingletonType:
+ return d->extraData.singletonTypeData->extFunc;
+ default:
+ return nullptr;
+ }
}
-bool QQmlType::isExtendedType() const
+const QMetaObject *QQmlType::extensionMetaObject() const
{
if (!d)
- return false;
- d->init();
+ return nullptr;
- return !d->metaObjects.isEmpty();
+ switch (d->regType) {
+ case CppType:
+ return d->extraData.cppTypeData->extMetaObject;
+ case SingletonType:
+ return d->extraData.singletonTypeData->extMetaObject;
+ default:
+ return nullptr;
+ }
+}
+
+bool QQmlType::isExtendedType() const
+{
+ return d && !d->init()->data.isEmpty();
}
bool QQmlType::isSingleton() const
@@ -561,40 +638,57 @@ bool QQmlType::isComposite() const
bool QQmlType::isCompositeSingleton() const
{
- return d && d->regType == CompositeSingletonType;
+ // if the outer type is a composite singleton, d->regType will indicate that even for
+ // the inline component type
+ // however, inline components can -at least for now- never be singletons
+ // so we just do one additional check
+ return d && d->regType == CompositeSingletonType && !isInlineComponentType();
}
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;
}
-int QQmlType::typeId() const
+bool QQmlType::isSequentialContainer() const
{
- return d ? d->typeId : -1;
+ return d && d->regType == SequentialContainerType;
}
-int QQmlType::qListTypeId() const
+bool QQmlType::isValueType() const
{
- return d ? d->listId : -1;
+ return d && d->isValueType();
}
-const QMetaObject *QQmlType::metaObject() const
+QMetaType QQmlType::typeId() const
{
- if (!d)
- return nullptr;
- d->init();
+ return d ? d->typeId : QMetaType{};
+}
- if (d->metaObjects.isEmpty())
- return d->baseMetaObject;
- else
- return d->metaObjects.constFirst().metaObject;
+QMetaType QQmlType::qListTypeId() const
+{
+ return d ? d->listId : QMetaType{};
+}
+
+QMetaSequence QQmlType::listMetaSequence() const
+{
+ return isSequentialContainer() ? d->extraData.sequentialContainerTypeData : QMetaSequence();
+}
+
+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
@@ -604,90 +698,61 @@ const QMetaObject *QQmlType::baseMetaObject() const
bool QQmlType::containsRevisionedAttributes() const
{
- if (!d)
- return false;
- d->init();
-
- return d->containsRevisionedAttributes;
+ return d && d->init()->containsRevisionedAttributes;
}
-int QQmlType::metaObjectRevision() const
+QTypeRevision QQmlType::metaObjectRevision() const
{
- return d ? d->revision : -1;
+ return d ? d->revision : QTypeRevision();
}
QQmlAttachedPropertiesFunc QQmlType::attachedPropertiesFunction(QQmlEnginePrivate *engine) const
{
- if (!d)
- return nullptr;
- if (d->regType == CppType)
- return d->extraData.cd->attachedPropertiesFunc;
-
- QQmlType base;
- if (d->regType == CompositeType)
- base = d->resolveCompositeBaseType(engine);
- return base.attachedPropertiesFunction(engine);
+ if (const QQmlTypePrivate *base = d ? d->attachedPropertiesBase(engine) : nullptr)
+ return base->extraData.cppTypeData->attachedPropertiesFunc;
+ return nullptr;
}
const QMetaObject *QQmlType::attachedPropertiesType(QQmlEnginePrivate *engine) const
{
- if (!d)
- return nullptr;
- if (d->regType == CppType)
- return d->extraData.cd->attachedPropertiesType;
-
- QQmlType base;
- if (d->regType == CompositeType)
- base = d->resolveCompositeBaseType(engine);
- return base.attachedPropertiesType(engine);
+ if (const QQmlTypePrivate *base = d ? d->attachedPropertiesBase(engine) : nullptr)
+ return base->extraData.cppTypeData->attachedPropertiesType;
+ return nullptr;
}
-#if QT_DEPRECATED_SINCE(5, 14)
-/*
-This is the id passed to qmlAttachedPropertiesById(). This is different from the index
-for the case that a single class is registered under two or more names (eg. Item in
-Qt 4.7 and QtQuick 1.0).
-*/
-int QQmlType::attachedPropertiesId(QQmlEnginePrivate *engine) const
+int QQmlType::parserStatusCast() const
{
- if (!d)
+ if (!d || d->regType != CppType)
return -1;
- if (d->regType == CppType)
- return d->extraData.cd->attachedPropertiesType ? d->index : -1;
-
- QQmlType base;
- if (d->regType == CompositeType)
- base = d->resolveCompositeBaseType(engine);
- return base.attachedPropertiesId(engine);
+ return d->extraData.cppTypeData->parserStatusCast;
}
-#endif
-int QQmlType::parserStatusCast() const
+int QQmlType::propertyValueSourceCast() const
{
if (!d || d->regType != CppType)
return -1;
- return d->extraData.cd->parserStatusCast;
+ return d->extraData.cppTypeData->propertyValueSourceCast;
}
-int QQmlType::propertyValueSourceCast() const
+int QQmlType::propertyValueInterceptorCast() const
{
if (!d || d->regType != CppType)
return -1;
- return d->extraData.cd->propertyValueSourceCast;
+ return d->extraData.cppTypeData->propertyValueInterceptorCast;
}
-int QQmlType::propertyValueInterceptorCast() const
+int QQmlType::finalizerCast() const
{
if (!d || d->regType != CppType)
return -1;
- return d->extraData.cd->propertyValueInterceptorCast;
+ 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
@@ -695,6 +760,10 @@ int QQmlType::index() const
return d ? d->index : -1;
}
+bool QQmlType::isInlineComponentType() const {
+ return d ? d->regType == QQmlType::InlineComponentType : false;
+}
+
QUrl QQmlType::sourceUrl() const
{
return d ? d->sourceUrl() : QUrl();
@@ -702,165 +771,42 @@ QUrl QQmlType::sourceUrl() const
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;
-}
-
-int QQmlType::scopedEnumValue(QQmlEnginePrivate *engine, const QByteArray &scopedEnumName, const QByteArray &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;
+ return QQmlTypePrivate::scopedEnumValue(d, engine, index, name, ok);
}
-int QQmlType::scopedEnumValue(QQmlEnginePrivate *engine, const QStringRef &scopedEnumName, const QStringRef &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(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;
+ return QQmlTypePrivate::scopedEnumValue(d, engine, scopedEnumName, name, ok);
}
void QQmlType::refHandle(const QQmlTypePrivate *priv)
@@ -882,4 +828,11 @@ int QQmlType::refCount(const QQmlTypePrivate *priv)
return -1;
}
+void QQmlType::createProxy(QObject *instance) const
+{
+ 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 ec27b38a73..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
@@ -60,6 +24,7 @@
#include <QtQml/qjsvalue.h>
#include <QtCore/qobject.h>
+#include <QtCore/qversionnumber.h>
QT_BEGIN_NAMESPACE
@@ -75,7 +40,7 @@ namespace QV4 {
struct String;
}
-class Q_QML_PRIVATE_EXPORT QQmlType
+class Q_QML_EXPORT QQmlType
{
public:
QQmlType();
@@ -86,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;
@@ -97,22 +58,30 @@ public:
QString elementName() const;
QHashedString module() const;
- int majorVersion() const;
- int minorVersion() const;
+ QTypeRevision version() const;
+
+ bool availableInVersion(QTypeRevision version) const;
+ bool availableInVersion(const QHashedStringRef &module, QTypeRevision version) const;
- bool availableInVersion(int vmajor, int vminor) const;
- bool availableInVersion(const QHashedStringRef &module, int vmajor, int vminor) const;
+ 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 *);
+ typedef void (*CreateFunc)(void *, void *);
CreateFunc createFunction() const;
+
QQmlCustomParser *customParser() const;
bool isCreatable() const;
typedef QObject *(*ExtensionFunc)(QObject *);
ExtensionFunc extensionFunction() const;
+ const QMetaObject *extensionMetaObject() const;
bool isExtendedType() const;
QString noCreationReason() const;
@@ -122,37 +91,53 @@ public:
bool isCompositeSingleton() const;
bool isQObjectSingleton() const;
bool isQJSValueSingleton() const;
+ bool isSequentialContainer() const;
+ bool isValueType() const;
- int typeId() const;
- int qListTypeId() 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;
- int metaObjectRevision() const;
+ QTypeRevision metaObjectRevision() const;
bool containsRevisionedAttributes() const;
QQmlAttachedPropertiesFunc attachedPropertiesFunction(QQmlEnginePrivate *engine) const;
const QMetaObject *attachedPropertiesType(QQmlEnginePrivate *engine) const;
-#if QT_DEPRECATED_SINCE(5, 14)
- QT_DEPRECATED int attachedPropertiesId(QQmlEnginePrivate *engine) const;
-#endif
int parserStatusCast() const;
const char *interfaceIId() const;
int propertyValueSourceCast() const;
int propertyValueInterceptorCast() const;
+ int finalizerCast() const;
int index() const;
- struct Q_QML_PRIVATE_EXPORT SingletonInstanceInfo
+ bool isInlineComponentType() const;
+
+ struct Q_QML_EXPORT SingletonInstanceInfo final
+ : public QQmlRefCounted<SingletonInstanceInfo>
{
- QJSValue (*scriptCallback)(QQmlEngine *, QJSEngine *) = nullptr;
+ 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;
@@ -164,8 +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, const QStringRef &, const QStringRef &, bool *ok) const;
+ int scopedEnumValue(QQmlEnginePrivate *engine, const QHashedStringRef &, const QHashedStringRef &, bool *ok) const;
const QQmlTypePrivate *priv() const { return d.data(); }
static void refHandle(const QQmlTypePrivate *priv);
@@ -178,15 +162,29 @@ public:
InterfaceType = 2,
CompositeType = 3,
CompositeSingletonType = 4,
+ InlineComponentType = 5,
+ SequentialContainerType = 6,
AnyRegistrationType = 255
};
+ void createProxy(QObject *instance) const;
+
private:
- friend uint qHash(const QQmlType &t, uint seed);
+ 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;
};
-inline uint qHash(const QQmlType &t, uint seed = 0)
+inline size_t qHash(const QQmlType &t, size_t seed = 0)
{
return qHash(reinterpret_cast<quintptr>(t.d.data()), seed);
}
diff --git a/src/qml/qml/qqmltype_p_p.h b/src/qml/qml/qqmltype_p_p.h
index 6a2d961de8..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
@@ -56,47 +20,90 @@
#include <private/qqmlproxymetaobject_p.h>
#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;
+ 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.inlineComponentTypeData;
default:
return QUrl();
}
}
+ const QQmlTypePrivate *attachedPropertiesBase(QQmlEnginePrivate *engine) const
+ {
+ for (const QQmlTypePrivate *d = this; d; d = d->resolveCompositeBaseType(engine).d.data()) {
+ if (d->regType == QQmlType::CppType)
+ return d->extraData.cppTypeData->attachedPropertiesType ? d : nullptr;
+
+ if (d->regType != QQmlType::CompositeType)
+ return nullptr;
+ }
+ return nullptr;
+ }
+
bool isComposite() const
{
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
{
int allocationSize;
- void (*newFunc)(void *);
+ void (*newFunc)(void *, void *);
+ void *userdata = nullptr;
QString noCreationReason;
+ QVariant (*createValueTypeFunc)(const QJSValue &);
int parserStatusCast;
QObject *(*extFunc)(QObject *);
const QMetaObject *extMetaObject;
@@ -105,52 +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;
- };
+ int index = -1;
union extraData {
- QQmlCppTypeData* cd;
- QQmlSingletonTypeData* sd;
- QQmlCompositeTypeData* fd;
+ 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;
- int version_maj;
- int version_min;
- int typeId;
- int listId;
- int revision;
- mutable bool containsRevisionedAttributes;
- mutable QQmlType superType;
- const QMetaObject *baseMetaObject;
-
- int index;
- mutable volatile bool isSetup:1;
- mutable volatile bool isEnumFromCacheSetup:1;
- mutable volatile bool isEnumFromBaseSetup:1;
- mutable bool haveSuperType:1;
- 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;
+ QMetaType typeId;
+ QMetaType listId;
+ QQmlType::RegistrationType regType;
+ QTypeRevision version;
+ QTypeRevision revision = QTypeRevision::zero();
+ const QMetaObject *baseMetaObject = nullptr;
void setName(const QString &uri, const QString &element);
+ 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;
@@ -161,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 9ff0e3fb9e..94e6e8f351 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,25 +19,30 @@
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)
- , typeData(typeData)
, dependencyHasher(dependencyHasher)
- , typeNameCache(typeNameCache)
, document(parsedQML)
+ , typeData(typeData)
{
}
-QQmlRefPointer<QV4::ExecutableCompilationUnit> QQmlTypeCompiler::compile()
+QQmlRefPointer<QV4::CompiledData::CompilationUnit> QQmlTypeCompiler::compile()
{
// Build property caches and VME meta object data
for (auto it = resolvedTypes->constBegin(), end = resolvedTypes->constEnd();
it != end; ++it) {
- QQmlCustomParser *customParser = (*it)->type.customParser();
+ QQmlCustomParser *customParser = (*it)->type().customParser();
if (customParser)
customParsers.insert(it.key(), customParser);
}
@@ -81,12 +52,31 @@ QQmlRefPointer<QV4::ExecutableCompilationUnit> QQmlTypeCompiler::compile()
{
QQmlPropertyCacheCreator<QQmlTypeCompiler> propertyCacheBuilder(&m_propertyCaches, &pendingGroupPropertyBindings,
- engine, this, imports());
- QQmlJS::DiagnosticMessage error = propertyCacheBuilder.buildMetaObjects();
- if (error.isValid()) {
- recordError(error);
+ engine, this, imports(), typeData->typeClassName());
+ 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);
}
{
@@ -95,8 +85,8 @@ QQmlRefPointer<QV4::ExecutableCompilationUnit> QQmlTypeCompiler::compile()
}
{
- SignalHandlerConverter converter(this);
- if (!converter.convertSignalHandlerExpressionsToFunctionDeclarations())
+ SignalHandlerResolver converter(this);
+ if (!converter.resolveSignalHandlerExpressions())
return nullptr;
}
@@ -116,24 +106,13 @@ QQmlRefPointer<QV4::ExecutableCompilationUnit> QQmlTypeCompiler::compile()
annotator.annotateBindingsToAliases();
}
- // 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);
- }
-
{
QQmlDeferredAndCustomParserBindingScanner deferredAndCustomParserBindingScanner(this);
if (!deferredAndCustomParserBindingScanner.scanObject())
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
@@ -145,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);
}
@@ -161,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(location.line);
- error.setColumn(location.column);
+ error.setLine(qmlConvertSourceCoordinate<quint32, int>(location.line()));
+ error.setColumn(qmlConvertSourceCoordinate<quint32, int>(location.column()));
error.setDescription(description);
error.setUrl(url());
errors << error;
@@ -185,8 +159,15 @@ void QQmlTypeCompiler::recordError(const QQmlJS::DiagnosticMessage &message)
{
QQmlError error;
error.setDescription(message.message);
- error.setLine(message.line);
- error.setColumn(message.column);
+ error.setLine(qmlConvertSourceCoordinate<quint32, int>(message.loc.startLine));
+ error.setColumn(qmlConvertSourceCoordinate<quint32, int>(message.loc.startColumn));
+ error.setUrl(url());
+ errors << error;
+}
+
+void QQmlTypeCompiler::recordError(const QQmlError &e)
+{
+ QQmlError error = e;
error.setUrl(url());
errors << error;
}
@@ -208,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
@@ -221,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
@@ -232,17 +212,12 @@ const QQmlPropertyCacheVector *QQmlTypeCompiler::propertyCaches() const
return &m_propertyCaches;
}
-QQmlPropertyCacheVector &&QQmlTypeCompiler::takePropertyCaches()
-{
- return std::move(m_propertyCaches);
-}
-
QQmlJS::MemoryPool *QQmlTypeCompiler::memoryPool()
{
return document->jsParserEngine.pool();
}
-QStringRef QQmlTypeCompiler::newStringRef(const QString &string)
+QStringView QQmlTypeCompiler::newStringRef(const QString &string)
{
return document->jsParserEngine.newStringRef(string);
}
@@ -257,12 +232,12 @@ QString QQmlTypeCompiler::bindingAsString(const QmlIR::Object *object, int scrip
return object->bindingAsString(document, scriptIndex);
}
-void QQmlTypeCompiler::addImport(const QString &module, const QString &qualifier, int majorVersion, int minorVersion)
+void QQmlTypeCompiler::addImport(const QString &module, const QString &qualifier, QTypeRevision version)
{
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
@@ -272,21 +247,23 @@ void QQmlTypeCompiler::addImport(const QString &module, const QString &qualifier
auto pool = memoryPool();
QV4::CompiledData::Import *import = pool->New<QV4::CompiledData::Import>();
import->type = QV4::CompiledData::Import::ImportLibrary;
- import->majorVersion = majorVersion;
- import->minorVersion = minorVersion;
+ import->version = version;
import->uriIndex = moduleIdx;
import->qualifierIndex = qualifierIdx;
document->imports.append(import);
}
+QQmlType QQmlTypeCompiler::qmlTypeForComponent(const QString &inlineComponentName) const
+{
+ return typeData->qmlType(inlineComponentName);
+}
+
QQmlCompilePass::QQmlCompilePass(QQmlTypeCompiler *typeCompiler)
: compiler(typeCompiler)
{
}
-
-
-SignalHandlerConverter::SignalHandlerConverter(QQmlTypeCompiler *typeCompiler)
+SignalHandlerResolver::SignalHandlerResolver(QQmlTypeCompiler *typeCompiler)
: QQmlCompilePass(typeCompiler)
, enginePrivate(typeCompiler->enginePrivate())
, qmlObjects(*typeCompiler->qmlObjects())
@@ -297,11 +274,11 @@ SignalHandlerConverter::SignalHandlerConverter(QQmlTypeCompiler *typeCompiler)
{
}
-bool SignalHandlerConverter::convertSignalHandlerExpressionsToFunctionDeclarations()
+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)) {
@@ -309,65 +286,74 @@ bool SignalHandlerConverter::convertSignalHandlerExpressionsToFunctionDeclaratio
continue;
}
const QString elementName = stringAt(obj->inheritedTypeNameIndex);
- if (!convertSignalHandlerExpressionsToFunctionDeclarations(obj, elementName, cache))
+ if (!resolveSignalHandlerExpressions(obj, elementName, cache))
return false;
}
return true;
}
-bool SignalHandlerConverter::convertSignalHandlerExpressionsToFunctionDeclarations(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;
for (QmlIR::Binding *binding = obj->firstBinding(); binding; binding = binding->next) {
- QString propertyName = stringAt(binding->propertyNameIndex);
+ 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(propertyName, &type, nullptr, nullptr, nullptr);
+ QQmlType type = typeRef ? typeRef->type() : QQmlType();
+ 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);
- if (!convertSignalHandlerExpressionsToFunctionDeclarations(attachedObj, propertyName, cache))
+ QQmlPropertyCache::ConstPtr cache = QQmlMetaType::propertyCache(attachedType);
+ if (!resolveSignalHandlerExpressions(attachedObj, bindingPropertyName, cache))
return false;
continue;
}
- if (!QmlIR::IRBuilder::isSignalPropertyName(propertyName))
+ 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);
- Q_ASSERT(propertyName.startsWith(QLatin1String("on")));
- propertyName.remove(0, 2);
-
- // Note that the property name could start with any alpha or '_' or '$' character,
- // so we need to do the lower-casing of the first alpha character.
- for (int firstAlphaIndex = 0; firstAlphaIndex < propertyName.size(); ++firstAlphaIndex) {
- if (propertyName.at(firstAlphaIndex).isUpper()) {
- propertyName[firstAlphaIndex] = propertyName.at(firstAlphaIndex).toLower();
- break;
- }
- }
-
- QList<QString> parameters;
-
bool notInRevision = false;
- QQmlPropertyData *signal = resolver.signal(propertyName, &notInRevision);
- if (signal) {
+ 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;
+ QV4::CompiledData::Binding::Flag flag
+ = QV4::CompiledData::Binding::IsSignalHandlerExpression;
+
+ const bool isPropertyObserver = !signalPropertyData && qPropertyData && qPropertyData->isBindable();
+ if (signal && !(qPropertyData && qPropertyData->isAlias() && isPropertyObserver)) {
int sigIndex = propertyCache->methodIndexToSignalIndex(signal->coreIndex());
sigIndex = propertyCache->originalClone(sigIndex);
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;
@@ -376,20 +362,25 @@ bool SignalHandlerConverter::convertSignalHandlerExpressionsToFunctionDeclaratio
} else if (illegalNames.contains(param)) {
COMPILE_EXCEPTION(binding, tr("Signal parameter \"%1\" hides global variable.").arg(param));
}
- parameters += param;
}
+ } else if (isPropertyObserver) {
+ finalSignalHandlerPropertyName = qPropertyName;
+ flag = QV4::CompiledData::Binding::IsPropertyObserver;
} else {
if (notInRevision) {
// Try assinging it as a property later
- if (resolver.property(propertyName, /*notInRevision ptr*/nullptr))
+ if (signalPropertyData)
continue;
const QString &originalPropertyName = stringAt(binding->propertyNameIndex);
auto *typeRef = resolvedType(obj->inheritedTypeNameIndex);
- const QQmlType type = typeRef ? typeRef->type : QQmlType();
+ const QQmlType type = typeRef ? typeRef->type() : QQmlType();
if (type.isValid()) {
- COMPILE_EXCEPTION(binding, tr("\"%1.%2\" is not available in %3 %4.%5.").arg(typeName).arg(originalPropertyName).arg(type.module()).arg(type.majorVersion()).arg(type.minorVersion()));
+ COMPILE_EXCEPTION(binding, tr("\"%1.%2\" is not available in %3 %4.%5.")
+ .arg(typeName).arg(originalPropertyName).arg(type.module())
+ .arg(type.version().majorVersion())
+ .arg(type.version().minorVersion()));
} else {
COMPILE_EXCEPTION(binding, tr("\"%1.%2\" is not available due to component versioning.").arg(typeName).arg(originalPropertyName));
}
@@ -410,74 +401,33 @@ bool SignalHandlerConverter::convertSignalHandlerExpressionsToFunctionDeclaratio
}
}
- QHash<QString, QStringList>::ConstIterator entry = customSignals.constFind(propertyName);
- if (entry == customSignals.constEnd() && propertyName.endsWith(QLatin1String("Changed"))) {
- QString alternateName = propertyName.mid(0, propertyName.length() - static_cast<int>(strlen("Changed")));
- entry = customSignals.constFind(alternateName);
- }
+ QHash<QString, QStringList>::ConstIterator entry = customSignals.constFind(signalName);
+ if (entry == customSignals.constEnd() && !qPropertyName.isEmpty())
+ entry = customSignals.constFind(qPropertyName);
if (entry == customSignals.constEnd()) {
// Can't find even a custom signal, then just don't do anything and try
// keeping the binding as a regular property assignment.
continue;
}
-
- parameters = entry.value();
}
// 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"));
}
}
- QQmlJS::MemoryPool *pool = compiler->memoryPool();
-
- QQmlJS::AST::FormalParameterList *paramList = nullptr;
- for (const QString &param : qAsConst(parameters)) {
- QStringRef paramNameRef = compiler->newStringRef(param);
-
- QQmlJS::AST::PatternElement *b = new (pool) QQmlJS::AST::PatternElement(paramNameRef, nullptr);
- paramList = new (pool) QQmlJS::AST::FormalParameterList(paramList, b);
- }
-
- if (paramList)
- paramList = paramList->finish(pool);
-
- QmlIR::CompiledFunctionOrExpression *foe = obj->functionsAndExpressions->slowAt(binding->value.compiledScriptIndex);
- QQmlJS::AST::FunctionDeclaration *functionDeclaration = nullptr;
- if (QQmlJS::AST::ExpressionStatement *es = QQmlJS::AST::cast<QQmlJS::AST::ExpressionStatement*>(foe->node)) {
- if (QQmlJS::AST::FunctionExpression *fe = QQmlJS::AST::cast<QQmlJS::AST::FunctionExpression*>(es->expression)) {
- functionDeclaration = new (pool) QQmlJS::AST::FunctionDeclaration(fe->name, fe->formals, fe->body);
- functionDeclaration->functionToken = fe->functionToken;
- functionDeclaration->identifierToken = fe->identifierToken;
- functionDeclaration->lparenToken = fe->lparenToken;
- functionDeclaration->rparenToken = fe->rparenToken;
- functionDeclaration->lbraceToken = fe->lbraceToken;
- functionDeclaration->rbraceToken = fe->rbraceToken;
- }
- }
- if (!functionDeclaration) {
- QQmlJS::AST::Statement *statement = static_cast<QQmlJS::AST::Statement*>(foe->node);
- QQmlJS::AST::StatementList *body = new (pool) QQmlJS::AST::StatementList(statement);
- body = body->finish();
-
- functionDeclaration = new (pool) QQmlJS::AST::FunctionDeclaration(compiler->newStringRef(stringAt(binding->propertyNameIndex)), paramList, body);
- functionDeclaration->lbraceToken = functionDeclaration->functionToken
- = foe->node->firstSourceLocation();
- functionDeclaration->rbraceToken = foe->node->lastSourceLocation();
- }
- foe->node = functionDeclaration;
- binding->propertyNameIndex = compiler->registerString(propertyName);
- binding->flags |= QV4::CompiledData::Binding::IsSignalHandlerExpression;
+ binding->propertyNameIndex = compiler->registerString(finalSignalHandlerPropertyName);
+ binding->setFlag(flag);
}
return true;
}
@@ -492,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);
@@ -501,20 +451,22 @@ 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)
+ 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() != QMetaType::Int)
+ if (!pd->isEnum() && pd->propType().id() != QMetaType::Int)
continue;
if (!tryQualifiedEnumAssignment(obj, propertyCache, pd, binding))
@@ -525,48 +477,51 @@ bool QQmlEnumTypeResolver::resolveEnumBindings()
return true;
}
-struct StaticQtMetaObject : public QObject
-{
- static const QMetaObject *get()
- { return &staticQtMetaObject; }
-};
-
-bool QQmlEnumTypeResolver::assignEnumToBinding(QmlIR::Binding *binding, const QStringRef &enumName, int enumValue, bool isQtObject)
+bool QQmlEnumTypeResolver::assignEnumToBinding(QmlIR::Binding *binding, QStringView, int enumValue, bool)
{
- if (enumName.length() > 0 && enumName[0].isLower() && !isQtObject) {
- COMPILE_EXCEPTION(binding, tr("Invalid property assignment: Enum value \"%1\" cannot start with a lowercase letter").arg(enumName.toString()));
- }
- 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() == QMetaType::Int) && !prop->isEnum();
+ 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)
@@ -575,9 +530,9 @@ bool QQmlEnumTypeResolver::tryQualifiedEnumAssignment(const QmlIR::Object *obj,
QHashedStringRef typeName(string.constData(), dot);
const bool isQtObject = (typeName == QLatin1String("Qt"));
- const QStringRef scopedEnumName = (dot2 != -1 ? string.midRef(dot + 1, dot2 - dot - 1) : QStringRef());
+ const QStringView scopedEnumName = (dot2 != -1 ? QStringView{string}.mid(dot + 1, dot2 - dot - 1) : QStringView());
// ### consider supporting scoped enums in Qt namespace
- const QStringRef enumValue = string.midRef(!isQtObject && dot2 != -1 ? dot2 + 1 : dot + 1);
+ const QStringView enumValue = QStringView{string}.mid(!isQtObject && dot2 != -1 ? dot2 + 1 : dot + 1);
if (isIntProp) { // ### C++11 allows enums to be other integral types. Should we support other integral types here?
// Allow enum assignment to ints.
@@ -590,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;
@@ -599,10 +555,20 @@ bool QQmlEnumTypeResolver::tryQualifiedEnumAssignment(const QmlIR::Object *obj,
bool ok = false;
auto *tr = resolvedType(obj->inheritedTypeNameIndex);
- if (type.isValid() && tr && tr->type == type) {
- // When these two match, we can short cut the search
- QMetaProperty mprop = propertyCache->firstCppMetaObject()->property(prop->coreIndex());
- QMetaEnum menum = mprop.enumerator();
+
+ // When these two match, we can short cut the search, unless...
+ bool useFastPath = type.isValid() && tr && tr->type() == type;
+ QMetaProperty mprop;
+ QMetaEnum menum;
+ if (useFastPath) {
+ mprop = propertyCache->firstCppMetaObject()->property(prop->coreIndex());
+ menum = mprop.enumerator();
+ // ...the enumerator merely comes from a related metaobject, but the enum scope does not match
+ // the typename we resolved
+ if (!menum.isScoped() && scopedEnumName.isEmpty() && typeName != QString::fromUtf8(menum.scope()))
+ useFastPath = false;;
+ }
+ if (useFastPath) {
QByteArray enumName = enumValue.toUtf8();
if (menum.isScoped() && !scopedEnumName.isEmpty() && enumName != scopedEnumName.toUtf8())
return true;
@@ -621,7 +587,7 @@ bool QQmlEnumTypeResolver::tryQualifiedEnumAssignment(const QmlIR::Object *obj,
value = type.enumValue(compiler->enginePrivate(), QHashedStringRef(enumValue), &ok);
} else {
QByteArray enumName = enumValue.toUtf8();
- const QMetaObject *metaObject = StaticQtMetaObject::get();
+ const QMetaObject *metaObject = &Qt::staticMetaObject;
for (int ii = metaObject->enumeratorCount() - 1; !ok && ii >= 0; --ii) {
QMetaEnum e = metaObject->enumerator(ii);
value = e.keyToValue(enumName.constData(), &ok);
@@ -635,22 +601,23 @@ bool QQmlEnumTypeResolver::tryQualifiedEnumAssignment(const QmlIR::Object *obj,
return assignEnumToBinding(binding, enumValue, value, isQtObject);
}
-int QQmlEnumTypeResolver::evaluateEnum(const QString &scope, const QStringRef &enumName, const QStringRef &enumValue, bool *ok) const
+int QQmlEnumTypeResolver::evaluateEnum(const QString &scope, QStringView enumName, QStringView enumValue, bool *ok) const
{
Q_ASSERT_X(ok, "QQmlEnumTypeResolver::evaluateEnum", "ok must not be a null pointer");
*ok = false;
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 = StaticQtMetaObject::get();
+ const QMetaObject *mo = &Qt::staticMetaObject;
int i = mo->enumeratorCount();
const QByteArray ba = enumValue.toUtf8();
while (i--) {
@@ -671,6 +638,9 @@ QQmlCustomParserScriptIndexer::QQmlCustomParserScriptIndexer(QQmlTypeCompiler *t
void QQmlCustomParserScriptIndexer::annotateBindingsWithScriptStrings()
{
scanObjectRecursively(/*root object*/0);
+ for (int i = 0; i < qmlObjects.size(); ++i)
+ if (qmlObjects.at(i)->flags & QV4::CompiledData::Object::IsInlineComponentRoot)
+ scanObjectRecursively(i);
}
void QQmlCustomParserScriptIndexer::scanObjectRecursively(int objectIndex, bool annotateScriptBindings)
@@ -679,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;
+ }
}
}
@@ -700,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);
}
}
}
@@ -731,22 +707,22 @@ QQmlScriptStringScanner::QQmlScriptStringScanner(QQmlTypeCompiler *typeCompiler)
void QQmlScriptStringScanner::scan()
{
- const int scriptStringMetaType = qMetaTypeId<QQmlScriptString>();
- for (int i = 0; i < qmlObjects.count(); ++i) {
- QQmlPropertyCache *propertyCache = propertyCaches->at(i);
+ const QMetaType scriptStringMetaType = QMetaType::fromType<QQmlScriptString>();
+ 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;
@@ -756,300 +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;
- if (tr->type.isValid())
- firstMetaObject = tr->type.metaObject();
- else if (tr->compilationUnit)
- firstMetaObject = tr->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;
-
- QQmlPropertyCache *pc = enginePrivate->rawPropertyCacheForType(pd->propType(), pd->typeMinorVersion());
- 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.majorVersion(), componentType.minorVersion());
-
- QmlIR::Object *syntheticComponent = pool->New<QmlIR::Object>();
- syntheticComponent->init(pool, compiler->registerString(qualifier + QLatin1Char('.') + componentType.elementName()), compiler->registerString(QString()));
- syntheticComponent->location = binding->valueLocation;
- syntheticComponent->flags |= QV4::CompiledData::Object::IsComponent;
-
- if (!containsResolvedType(syntheticComponent->inheritedTypeNameIndex)) {
- auto typeRef = new QV4::ResolvedTypeReference;
- typeRef->type = componentType;
- typeRef->majorVersion = componentType.majorVersion();
- typeRef->minorVersion = componentType.minorVersion();
- 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);
- 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(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);
-
- bool atLeastOneAliasResolved;
- do {
- atLeastOneAliasResolved = false;
- QVector<int> pendingObjects;
-
- for (int objectIndex: qAsConst(_objectsWithAliases)) {
+ Q_UNUSED(component);
- QQmlJS::DiagnosticMessage error;
- const auto result = resolveAliasesInObject(objectIndex, &error);
-
- if (error.isValid()) {
- recordError(error);
- return false;
- }
-
- if (result == AllAliasesResolved) {
- QQmlJS::DiagnosticMessage 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,
- QQmlJS::DiagnosticMessage *error)
-{
- const QmlIR::Object * const obj = qmlObjects->at(objectIndex);
+ const QmlIR::Object * const obj = m_compiler->objectAt(objectIndex);
if (!obj->aliasCount())
return AllAliasesResolved;
@@ -1057,60 +832,60 @@ 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,
- tr("Invalid alias reference. Unable to find id \"%1\"").arg(stringAt(idIndex)));
+ QQmlComponentAndAliasResolverBase::tr("Invalid alias reference. Unable to find id \"%1\"").arg(stringAt(idIndex)));
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);
- QStringRef property;
- QStringRef subProperty;
+ QStringView property;
+ QStringView subProperty;
const int propertySeparator = aliasPropertyValue.indexOf(QLatin1Char('.'));
if (propertySeparator != -1) {
- property = aliasPropertyValue.leftRef(propertySeparator);
- subProperty = aliasPropertyValue.midRef(propertySeparator + 1);
+ property = QStringView{aliasPropertyValue}.left(propertySeparator);
+ subProperty = QStringView{aliasPropertyValue}.mid(propertySeparator + 1);
} else
- property = QStringRef(&aliasPropertyValue, 0, aliasPropertyValue.length());
+ property = QStringView(aliasPropertyValue);
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,
- tr("Invalid alias target location: %1").arg(property.toString()));
+ QQmlComponentAndAliasResolverBase::tr("Invalid alias target location: %1").arg(property.toString()));
break;
}
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;
}
@@ -1118,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;
}
@@ -1134,14 +909,14 @@ QQmlComponentAndAliasResolver::resolveAliasesInObject(int objectIndex,
if (!targetProperty || targetProperty->coreIndex() > 0x0000FFFF) {
*error = qQmlCompileError(
alias->referenceLocation,
- tr("Invalid alias target location: %1").arg(property.toString()));
+ QQmlComponentAndAliasResolverBase::tr("Invalid alias target location: %1").arg(property.toString()));
break;
}
propIdx = QQmlPropertyIndex(targetProperty->coreIndex());
if (!subProperty.isEmpty()) {
- const QMetaObject *valueTypeMetaObject = QQmlValueTypeFactory::metaObjectForMetaType(targetProperty->propType());
+ const QMetaObject *valueTypeMetaObject = QQmlMetaType::metaObjectForValueType(targetProperty->propType());
if (!valueTypeMetaObject) {
// could be a deep alias
bool isDeepAlias = subProperty.at(0).isLower();
@@ -1149,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;
@@ -1162,7 +937,7 @@ QQmlComponentAndAliasResolver::resolveAliasesInObject(int objectIndex,
if (!isDeepAlias) {
*error = qQmlCompileError(
alias->referenceLocation,
- tr("Invalid alias target location: %1").arg(subProperty.toString()));
+ QQmlComponentAndAliasResolverBase::tr("Invalid alias target location: %1").arg(subProperty.toString()));
break;
}
} else {
@@ -1172,7 +947,7 @@ QQmlComponentAndAliasResolver::resolveAliasesInObject(int objectIndex,
if (valueTypeIndex == -1) {
*error = qQmlCompileError(
alias->referenceLocation,
- tr("Invalid alias target location: %1").arg(subProperty.toString()));
+ QQmlComponentAndAliasResolverBase::tr("Invalid alias target location: %1").arg(subProperty.toString()));
break;
}
Q_ASSERT(valueTypeIndex <= 0x0000FFFF);
@@ -1181,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++;
}
@@ -1207,30 +982,40 @@ QQmlDeferredAndCustomParserBindingScanner::QQmlDeferredAndCustomParserBindingSca
bool QQmlDeferredAndCustomParserBindingScanner::scanObject()
{
- 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) {
+ 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 {
@@ -1243,74 +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)
- 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;
@@ -1326,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 40b0337848..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
@@ -79,26 +43,43 @@ struct QQmlTypeCompiler
{
Q_DECLARE_TR_FUNCTIONS(QQmlTypeCompiler)
public:
- QQmlTypeCompiler(QQmlEnginePrivate *engine, QQmlTypeData *typeData, QmlIR::Document *document,
- const QQmlRefPointer<QQmlTypeNameCache> &typeNameCache,
- QV4::ResolvedTypeReferenceMap *resolvedTypeCache,
+ QQmlTypeCompiler(QQmlEnginePrivate *engine,
+ QQmlTypeData *typeData,
+ QmlIR::Document *document,
+ 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);
- void recordError(const QQmlJS::DiagnosticMessage &error);
+ void recordError(const QQmlJS::DiagnosticMessage &message);
+ void recordError(const QQmlError &e);
int registerString(const QString &str);
int registerConstant(QV4::ReturnedValue v);
@@ -109,39 +90,46 @@ 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();
- QStringRef newStringRef(const QString &string);
+ QStringView newStringRef(const QString &string);
const QV4::Compiler::StringTableGenerator *stringPool() const;
const QHash<int, QQmlCustomParser*> &customParserCache() const { return customParsers; }
QString bindingAsString(const QmlIR::Object *object, int scriptIndex) const;
- void addImport(const QString &module, const QString &qualifier, int majorVersion, int minorVersion);
+ void addImport(const QString &module, const QString &qualifier, QTypeRevision version);
QV4::ResolvedTypeReference *resolvedType(int id) const
{
return resolvedTypes->value(id);
}
+ 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;
QQmlEnginePrivate *engine;
- QQmlTypeData *typeData;
const QV4::CompiledData::DependentTypesHasher &dependencyHasher;
- QQmlRefPointer<QQmlTypeNameCache> typeNameCache;
QmlIR::Document *document;
// index is string index of type name (use obj->inheritedTypeNameIndex)
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;
+
+ QQmlTypeData *typeData;
};
struct QQmlCompilePass
@@ -152,34 +140,27 @@ struct QQmlCompilePass
protected:
void recordError(const QV4::CompiledData::Location &location, const QString &description) const
{ compiler->recordError(location, description); }
- void recordError(const QQmlJS::DiagnosticMessage &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;
};
-// "Converts" signal expressions to full-fleged function declarations with
-// parameters taken from the signal declarations
-// It also updates the QV4::CompiledData::Binding objects to set the property name
-// to the final signal name (onTextChanged -> textChanged) and sets the IsSignalExpression flag.
-struct SignalHandlerConverter : public QQmlCompilePass
+// Resolves signal handlers. Updates the QV4::CompiledData::Binding objects to
+// set the property name to the final signal name (onTextChanged -> textChanged)
+// and sets the IsSignalExpression flag.
+struct SignalHandlerResolver : public QQmlCompilePass
{
- Q_DECLARE_TR_FUNCTIONS(SignalHandlerConverter)
+ Q_DECLARE_TR_FUNCTIONS(SignalHandlerResolver)
public:
- SignalHandlerConverter(QQmlTypeCompiler *typeCompiler);
+ SignalHandlerResolver(QQmlTypeCompiler *typeCompiler);
- bool convertSignalHandlerExpressionsToFunctionDeclarations();
+ bool resolveSignalHandlerExpressions();
private:
- bool convertSignalHandlerExpressionsToFunctionDeclarations(const QmlIR::Object *obj, const QString &typeName, QQmlPropertyCache *propertyCache);
+ bool resolveSignalHandlerExpressions(const QmlIR::Object *obj, const QString &typeName,
+ const QQmlPropertyCache::ConstPtr &propertyCache);
QQmlEnginePrivate *enginePrivate;
const QVector<QmlIR::Object*> &qmlObjects;
@@ -201,15 +182,15 @@ public:
bool resolveEnumBindings();
private:
- bool assignEnumToBinding(QmlIR::Binding *binding, const QStringRef &enumName, int enumValue, bool isQtObject);
+ bool assignEnumToBinding(QmlIR::Binding *binding, QStringView enumName, int enumValue, bool isQtObject);
bool assignEnumToBinding(QmlIR::Binding *binding, const QString &enumName, int enumValue, bool isQtObject)
{
- return assignEnumToBinding(binding, QStringRef(&enumName), enumValue, isQtObject);
+ return assignEnumToBinding(binding, QStringView(enumName), enumValue, isQtObject);
}
- bool tryQualifiedEnumAssignment(const QmlIR::Object *obj, const QQmlPropertyCache *propertyCache,
- const QQmlPropertyData *prop,
- QmlIR::Binding *binding);
- int evaluateEnum(const QString &scope, const QStringRef &enumName, const QStringRef &enumValue, bool *ok) const;
+ 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;
const QVector<QmlIR::Object*> &qmlObjects;
@@ -255,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, QQmlJS::DiagnosticMessage *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 cfdcf6aad5..2b189cd264 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,12 +51,7 @@ 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();
}
@@ -105,19 +69,19 @@ void QQmlTypeData::unregisterCallback(TypeDataCallback *callback)
Q_ASSERT(!m_callbacks.contains(callback));
}
-bool QQmlTypeData::tryLoadFromDiskCache()
+QQmlType QQmlTypeData::qmlType(const QString &inlineComponentName) const
{
- if (diskCacheDisabled() && !diskCacheForced())
- return false;
-
- if (isDebugging())
- return false;
+ if (inlineComponentName.isEmpty())
+ return m_qmlType;
+ return m_inlineComponentData[inlineComponentName].qmlType;
+}
- QV4::ExecutionEngine *v4 = typeLoader()->engine()->handle();
- if (!v4)
+bool QQmlTypeData::tryLoadFromDiskCache()
+{
+ if (!readCacheFile())
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)) {
@@ -127,16 +91,23 @@ 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);
- for (int i = 0, count = m_compiledData->objectCount(); i < count; ++i)
- m_typeReferences.collectFromObject(m_compiledData->objectAt(i));
+ QVector<QV4::CompiledData::InlineComponent> ics;
+ for (int i = 0, count = m_compiledData->objectCount(); i < count; ++i) {
+ auto object = m_compiledData->objectAt(i);
+ m_typeReferences.collectFromObject(object);
+ const auto inlineComponentTable = object->inlineComponentTable();
+ for (auto i = 0; i != object->nInlineComponents; ++i) {
+ ics.push_back(inlineComponentTable[i]);
+ }
+ }
- 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
@@ -152,10 +123,12 @@ bool QQmlTypeData::tryLoadFromDiskCache()
const QV4::CompiledData::Import *import = m_compiledData->importAt(i);
if (m_compiledData->stringAt(import->uriIndex) == QLatin1String(".")
&& import->qualifierIndex == 0
- && import->majorVersion == -1
- && import->minorVersion == -1) {
+ && !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;
@@ -169,61 +142,162 @@ bool QQmlTypeData::tryLoadFromDiskCache()
for (int i = 0, count = m_compiledData->importCount(); i < count; ++i) {
const QV4::CompiledData::Import *import = m_compiledData->importAt(i);
QList<QQmlError> errors;
- if (!addImport(import, &errors)) {
+ 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(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;
}
}
+ for (auto&& ic: ics) {
+ QString const nameString = m_compiledData->stringAt(ic.nameIndex);
+ auto importUrl = finalUrl();
+ importUrl.setFragment(nameString);
+ auto import = new QQmlImportInstance();
+ 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,
+ QQmlComponentAndAliasResolverBase::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);
- QQmlJS::DiagnosticMessage error = propertyCacheCreator.buildMetaObjects();
- if (error.isValid()) {
- setError(error);
- return;
- }
- }
+ m_compiledData.data(), m_importCache.data(), typeClassName());
- QQmlPropertyCacheAliasCreator<QV4::ExecutableCompilationUnit> aliasCreator(
- &m_compiledData->propertyCaches, m_compiledData.data());
- aliasCreator.appendAliasPropertiesToMetaObjects(engine);
+ QQmlError error = propertyCacheCreator.verifyNoICCycle();
+ if (error.isValid())
+ return error;
- pendingGroupPropertyBindings.resolveMissingPropertyCaches(engine, &m_compiledData->propertyCaches);
+ 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
+ }
+
+ } while (result.canResume);
+ }
+
+ 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;
}
@@ -231,28 +305,78 @@ static bool addTypeReferenceChecksumsToHash(const QList<QQmlTypeData::TypeRefere
return true;
}
+// local helper function for inline components
+namespace {
+using InlineComponentData = QV4::CompiledData::InlineComponentData;
+
+template<typename ObjectContainer>
+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) {
+ // 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);
+ }
+ }
+};
+}
+
+template<typename Container>
+void QQmlTypeData::setCompileUnit(const Container &container)
+{
+ for (int i = 0; i != container->objectCount(); ++i) {
+ auto const root = container->objectAt(i);
+ for (auto it = root->inlineComponentsBegin(); it != root->inlineComponentsEnd(); ++it) {
+ auto *typeRef = m_compiledData->resolvedType(it->nameIndex);
+
+ // We don't want the type reference to keep a strong reference to the compilation unit
+ // here. The compilation unit owns the type reference, and having a strong reference
+ // would prevent the compilation unit from ever getting deleted. We can still be sure
+ // that the compilation unit outlives the type reference, due to ownership.
+ typeRef->setReferencesCompilationUnit(false);
+
+ typeRef->setCompilationUnit(m_compiledData); // share compilation unit
+ }
+ }
+}
+
void QQmlTypeData::done()
{
auto cleanup = qScopeGuard([this]{
+ m_backupSourceCode = SourceCodeData();
m_document.reset();
m_typeReferences.clear();
- if (isError())
- m_compiledData = nullptr;
+ if (isError()) {
+ const auto encounteredErrors = errors();
+ for (const QQmlError &e : encounteredErrors)
+ qCDebug(DBG_DISK_CACHE) << e.toString();
+ m_compiledData.reset();
+ }
});
if (isError())
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(script.location.line);
- error.setColumn(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);
@@ -261,48 +385,73 @@ void QQmlTypeData::done()
}
// Check all type dependencies for errors
- for (auto it = m_resolvedTypes.constBegin(), end = m_resolvedTypes.constEnd(); 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());
+ Q_ASSERT(!type.typeData || type.typeData->isCompleteOrError() || type.type.isInlineComponentType());
+
+ 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;
+ }
+ }
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(type.location.line);
- error.setColumn(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(type.location.line);
- error.setColumn(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;
}
}
+ 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);
+ }
+
+ 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;
- QV4::ResolvedTypeReferenceMap resolvedTypeCache;
{
- QQmlJS::DiagnosticMessage error = buildTypeResolutionCaches(&typeNameCache, &resolvedTypeCache);
+ QQmlError error = buildTypeResolutionCaches(&typeNameCache, &resolvedTypeCache);
if (error.isValid()) {
setError(error);
qDeleteAll(resolvedTypeCache);
@@ -310,48 +459,81 @@ 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);
- } else {
- createTypeAndPropertyCaches(typeNameCache, resolvedTypeCache);
+ if (isError())
+ return;
+ else
+ setCompileUnit(m_document);
}
- 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);
- QVector<QQmlJS::DiagnosticMessage> errors = validator.validate();
+ QQmlPropertyValidator validator(enginePrivate, m_importCache.data(), m_compiledData);
+ QVector<QQmlError> errors = validator.validate();
if (!errors.isEmpty()) {
setError(errors);
return;
}
}
- m_compiledData->finalizeCompositeType(enginePrivate);
+ m_compiledData->finalizeCompositeType(qmlType());
}
{
@@ -381,11 +563,11 @@ void QQmlTypeData::done()
{
// 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);
- QStringRef qualifier(&script.qualifier);
+ QStringView qualifier(script.qualifier);
QString enclosingNamespace;
const int lastDotIndex = qualifier.lastIndexOf(QLatin1Char('.'));
@@ -394,7 +576,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;
}
@@ -414,14 +597,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);
@@ -457,14 +654,17 @@ void QQmlTypeData::dataReceived(const SourceCodeData &data)
continueLoadFromIR();
}
-void QQmlTypeData::initializeFromCachedUnit(const QV4::CompiledData::Unit *unit)
+void QQmlTypeData::initializeFromCachedUnit(const QQmlPrivate::CachedQmlUnit *unit)
{
m_document.reset(new QmlIR::Document(isDebugging()));
- QQmlIRLoader loader(unit, m_document.data());
+ QQmlIRLoader loader(unit->qmlData, m_document.data());
loader.load();
m_document->jsModule.fileName = urlString();
m_document->jsModule.finalUrl = finalUrlString();
- m_document->javaScriptCompilationUnit = QV4::CompiledData::CompilationUnit(unit);
+ m_document->javaScriptCompilationUnit
+ = QQmlRefPointer<QV4::CompiledData::CompilationUnit>(
+ new QV4::CompiledData::CompilationUnit(unit->qmlData, unit->aotCompiledFunctions),
+ QQmlRefPointer<QV4::CompiledData::CompilationUnit>::Adopt);
continueLoadFromIR();
}
@@ -484,12 +684,12 @@ 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(msg.line);
- e.setColumn(msg.column);
+ e.setLine(qmlConvertSourceCoordinate<quint32, int>(msg.loc.startLine));
+ e.setColumn(qmlConvertSourceCoordinate<quint32, int>(msg.loc.startColumn));
e.setDescription(msg.message);
errors << e;
}
@@ -499,21 +699,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()
{
+ for (auto const& object: m_document->objects) {
+ for (auto it = object->inlineComponentsBegin(); it != object->inlineComponentsEnd(); ++it) {
+ QString const nameString = m_document->stringAt(it->nameIndex);
+ auto importUrl = finalUrl();
+ importUrl.setFragment(nameString);
+ auto import = new QQmlImportInstance(); // Note: The cache takes ownership of the QQmlImportInstance
+ 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
@@ -526,8 +736,7 @@ void QQmlTypeData::continueLoadFromIR()
// This qmldir is for the implicit import
auto implicitImport = std::make_shared<PendingImport>();
implicitImport->uri = QLatin1String(".");
- implicitImport->majorVersion = -1;
- implicitImport->minorVersion = -1;
+ implicitImport->version = QTypeRevision();
QList<QQmlError> errors;
if (!fetchQmldir(qmldirUrl, implicitImport, 1, &errors)) {
@@ -539,15 +748,18 @@ void QQmlTypeData::continueLoadFromIR()
QList<QQmlError> errors;
- for (const QV4::CompiledData::Import *import : qAsConst(m_document->imports)) {
- if (!addImport(import, &errors)) {
+ 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(import->location.line);
- error.setColumn(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;
}
}
@@ -567,12 +779,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(import->location.line);
- error.setColumn(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);
}
}
@@ -589,7 +803,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);
}
@@ -603,43 +817,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 = (!diskCacheDisabled() || diskCacheForced())
- && !m_document->jsModule.debugMode && !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());
@@ -660,7 +889,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;
@@ -672,17 +901,15 @@ void QQmlTypeData::resolveTypes()
typeName = csRef.typeName;
}
- int majorVersion = csRef.majorVersion > -1 ? csRef.majorVersion : -1;
- int minorVersion = csRef.minorVersion > -1 ? csRef.minorVersion : -1;
-
- if (!resolveType(typeName, majorVersion, minorVersion, ref, -1, -1, true,
- QQmlType::CompositeSingletonType))
+ QTypeRevision version = csRef.version;
+ if (!resolveType(typeName, version, ref, -1, -1, true, QQmlType::CompositeSingletonType))
return;
if (ref.type.isCompositeSingleton()) {
ref.typeData = typeLoader()->getType(ref.type.sourceUrl());
- if (ref.typeData->status() == QQmlDataBlob::ResolvingDependencies || m_waitingOnMe.contains(ref.typeData.data())) {
- // TODO: give an error message? If so, we should record and show the path of the cycle.
+ if (ref.typeData->isWaiting() || m_waitingOnMe.contains(ref.typeData.data())) {
+ qCDebug(lcCycle) << "Possible cyclic dependency detected between"
+ << ref.typeData->urlString() << "and" << urlString();
continue;
}
addDependency(ref.typeData.data());
@@ -699,28 +926,36 @@ void QQmlTypeData::resolveTypes()
const bool reportErrors = unresolvedRef->errorWhenNotFound;
- int majorVersion = -1;
- int minorVersion = -1;
+ QTypeRevision version;
const QString name = stringAt(unresolvedRef.key());
- if (!resolveType(name, majorVersion, minorVersion, ref, unresolvedRef->location.line,
- unresolvedRef->location.column, reportErrors,
- QQmlType::AnyRegistrationType) && reportErrors)
+ bool *selfReferenceDetection = unresolvedRef->needsCreation ? nullptr : &ref.selfReference;
+
+ if (!resolveType(name, version, ref, unresolvedRef->location.line(),
+ unresolvedRef->location.column(), reportErrors,
+ QQmlType::AnyRegistrationType, selfReferenceDetection) && reportErrors)
return;
- if (ref.type.isComposite()) {
+ if (ref.type.isComposite() && !ref.selfReference) {
ref.typeData = typeLoader()->getType(ref.type.sourceUrl());
addDependency(ref.typeData.data());
}
- ref.majorVersion = majorVersion;
- ref.minorVersion = minorVersion;
-
- ref.location.line = unresolvedRef->location.line;
- ref.location.column = unresolvedRef->location.column;
+ if (ref.type.isInlineComponentType()) {
+ 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 = unresolvedRef->location;
ref.needsCreation = unresolvedRef->needsCreation;
-
m_resolvedTypes.insert(unresolvedRef.key(), ref);
}
@@ -729,10 +964,9 @@ void QQmlTypeData::resolveTypes()
loadImplicitImport();
}
-QQmlJS::DiagnosticMessage QQmlTypeData::buildTypeResolutionCaches(
+QQmlError QQmlTypeData::buildTypeResolutionCaches(
QQmlRefPointer<QQmlTypeNameCache> *typeNameCache,
- QV4::ResolvedTypeReferenceMap *resolvedTypeCache
- ) const
+ QV4::CompiledData::ResolvedTypeReferenceMap *resolvedTypeCache) const
{
typeNameCache->adopt(new QQmlTypeNameCache(m_importCache));
@@ -743,59 +977,88 @@ QQmlJS::DiagnosticMessage 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()) {
return qQmlCompileError(resolvedType->location, tr("Composite Singleton Type %1 is not creatable.").arg(qmlType.qmlTypeName()));
}
- ref->compilationUnit = resolvedType->typeData->compilationUnit();
- } else if (qmlType.isValid()) {
- ref->type = qmlType;
- Q_ASSERT(ref->type.isValid());
+ ref->setCompilationUnit(resolvedType->typeData->compilationUnit());
+ if (resolvedType->type.isInlineComponentType()) {
+ // Inline component which is part of an already resolved type
+ 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()) {
+ 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 if (qmlType.isValid() && !resolvedType->selfReference) {
+ ref->setType(qmlType);
+ Q_ASSERT(ref->type().isValid());
- if (resolvedType->needsCreation && !ref->type.isCreatable()) {
- QString reason = ref->type.noCreationReason();
+ if (resolvedType->needsCreation && !qmlType.isCreatable()) {
+ QString reason = qmlType.noCreationReason();
if (reason.isEmpty())
reason = tr("Element is not creatable.");
return qQmlCompileError(resolvedType->location, reason);
}
- if (ref->type.containsRevisionedAttributes()) {
- ref->typePropertyCache = engine->cache(ref->type,
- resolvedType->minorVersion);
+ 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->majorVersion = resolvedType->majorVersion;
- ref->minorVersion = resolvedType->minorVersion;
+ ref->setVersion(resolvedType->version);
ref->doDynamicTypeCheck();
- resolvedTypeCache->insert(resolvedType.key(), ref.take());
+ resolvedTypeCache->insert(resolvedType.key(), ref.release());
}
- QQmlJS::DiagnosticMessage noError;
+ QQmlError noError;
return noError;
}
-bool QQmlTypeData::resolveType(const QString &typeName, int &majorVersion, int &minorVersion,
+bool QQmlTypeData::resolveType(const QString &typeName, QTypeRevision &version,
TypeReference &ref, int lineNumber, int columnNumber,
- bool reportErrors, QQmlType::RegistrationType registrationType)
+ bool reportErrors, QQmlType::RegistrationType registrationType,
+ bool *typeRecursionDetected)
{
QQmlImportNamespace *typeNamespace = nullptr;
QList<QQmlError> errors;
- bool typeFound = m_importCache.resolveType(typeName, &ref.type, &majorVersion, &minorVersion,
- &typeNamespace, &errors, registrationType);
+ 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, &majorVersion, &minorVersion,
- &typeNamespace, &errors, registrationType);
+ typeFound = m_importCache->resolveType(
+ typeLoader(), typeName, &ref.type, &version, &typeNamespace, &errors,
+ registrationType, typeRecursionDetected);
} else {
return false; //loadImplicitImport() hit an error, and called setError already
}
@@ -816,7 +1079,7 @@ bool QQmlTypeData::resolveType(const QString &typeName, int &majorVersion, int &
// 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()));
}
@@ -833,12 +1096,14 @@ bool QQmlTypeData::resolveType(const QString &typeName, int &majorVersion, int &
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 e1d0c900ea..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
@@ -62,13 +26,13 @@ class Q_AUTOTEST_EXPORT QQmlTypeData : public QQmlTypeLoader::Blob
public:
struct TypeReference
{
- TypeReference() : majorVersion(0), minorVersion(0), needsCreation(true) {}
+ TypeReference() : version(QTypeRevision::zero()), needsCreation(true) {}
QV4::CompiledData::Location location;
QQmlType type;
- int majorVersion;
- int minorVersion;
+ QTypeRevision version;
QQmlRefPointer<QQmlTypeData> typeData;
+ bool selfReference = false;
QString prefix; // used by CompositeSingleton types
QString qualifiedName() const;
bool needsCreation;
@@ -85,13 +49,13 @@ private:
friend class QQmlTypeLoader;
QQmlTypeData(const QUrl &, QQmlTypeLoader *);
+ template<typename Container>
+ void setCompileUnit(const Container &container);
public:
~QQmlTypeData() override;
- const QList<ScriptReference> &resolvedScripts() const;
-
- QV4::ExecutableCompilationUnit *compilationUnit() const;
+ QV4::CompiledData::CompilationUnit *compilationUnit() const;
// Used by QQmlComponent to get notifications
struct TypeDataCallback {
@@ -102,38 +66,47 @@ public:
void registerCallback(TypeDataCallback *);
void unregisterCallback(TypeDataCallback *);
+ QQmlType qmlType(const QString &inlineComponentName = QString()) const;
+ QByteArray typeClassName() const { return m_typeClassName; }
+ SourceCodeData backupSourceCode() const { return m_backupSourceCode; }
+
protected:
void done() override;
void completed() override;
void dataReceived(const SourceCodeData &) override;
- void initializeFromCachedUnit(const QV4::CompiledData::Unit *unit) override;
+ void initializeFromCachedUnit(const QQmlPrivate::CachedQmlUnit *unit) override;
void allDependenciesDone() override;
void downloadProgressChanged(qreal) override;
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();
- QQmlJS::DiagnosticMessage buildTypeResolutionCaches(
+ 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);
- bool resolveType(const QString &typeName, int &majorVersion, int &minorVersion,
+ 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);
-
- void scriptImported(const QQmlRefPointer<QQmlScriptBlob> &blob, const QV4::CompiledData::Location &location, const QString &qualifier, const QString &nameSpace) override;
+ QQmlType::RegistrationType registrationType = QQmlType::AnyRegistrationType,
+ bool *typeRecursionDetected = nullptr);
+ 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;
@@ -150,7 +123,15 @@ private:
QMap<int, TypeReference> m_resolvedTypes;
bool m_typesResolved:1;
- QQmlRefPointer<QV4::ExecutableCompilationUnit> m_compiledData;
+ // Used for self-referencing types, otherwise invalid.
+ QQmlType m_qmlType;
+ QByteArray m_typeClassName; // used for meta-object later
+
+ using CompilationUnitPtr = QQmlRefPointer<QV4::CompiledData::CompilationUnit>;
+
+ QHash<QString, InlineComponentData> m_inlineComponentData;
+
+ CompilationUnitPtr m_compiledData;
QList<TypeDataCallback *> m_callbacks;
diff --git a/src/qml/qml/qqmltypeloader.cpp b/src/qml/qml/qqmltypeloader.cpp
index 54f94d6a11..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>
@@ -45,12 +9,15 @@
#include <private/qqmltypedata_p.h>
#include <private/qqmltypeloaderqmldircontent_p.h>
#include <private/qqmltypeloaderthread_p.h>
+#include <private/qqmlsourcecoordinate_p.h>
#include <QtQml/qqmlabstracturlinterceptor.h>
#include <QtQml/qqmlengine.h>
#include <QtQml/qqmlextensioninterface.h>
#include <QtQml/qqmlfile.h>
+#include <qtqml_tracepoints_p.h>
+
#include <QtCore/qdir.h>
#include <QtCore/qdiriterator.h>
#include <QtCore/qfile.h>
@@ -65,8 +32,6 @@
#define ASSERT_LOADTHREAD()
#endif
-DEFINE_BOOL_CONFIG_OPTION(disableDiskCache, QML_DISABLE_DISK_CACHE);
-DEFINE_BOOL_CONFIG_OPTION(forceDiskCache, QML_FORCE_DISK_CACHE);
QT_BEGIN_NAMESPACE
@@ -81,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.
@@ -123,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
}
@@ -171,8 +137,8 @@ struct StaticLoader {
};
struct CachedLoader {
- const QV4::CompiledData::Unit *unit;
- CachedLoader(const QV4::CompiledData::Unit *unit) : unit(unit) {}
+ const QQmlPrivate::CachedQmlUnit *unit;
+ CachedLoader(const QQmlPrivate::CachedQmlUnit *unit) : unit(unit) {}
void loadThread(QQmlTypeLoader *loader, QQmlDataBlob *blob) const
{
@@ -216,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();
}
}
}
@@ -244,26 +208,26 @@ void QQmlTypeLoader::loadWithStaticData(QQmlDataBlob *blob, const QByteArray &da
doLoad(StaticLoader(data), blob, mode);
}
-void QQmlTypeLoader::loadWithCachedUnit(QQmlDataBlob *blob, const QV4::CompiledData::Unit *unit, Mode mode)
+void QQmlTypeLoader::loadWithCachedUnit(QQmlDataBlob *blob, const QQmlPrivate::CachedQmlUnit *unit, Mode mode)
{
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 QV4::CompiledData::Unit *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();
@@ -289,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.);
@@ -299,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()) {
@@ -331,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);
@@ -347,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
@@ -361,8 +324,6 @@ void QQmlTypeLoader::networkReplyFinished(QNetworkReply *reply)
QByteArray data = reply->readAll();
setData(blob, data);
}
-
- blob->release();
}
void QQmlTypeLoader::networkReplyProgress(QNetworkReply *reply,
@@ -370,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());
@@ -391,7 +352,7 @@ QQmlEngine *QQmlTypeLoader::engine() const
return m_engine;
}
-/*!
+/*! \internal
Call the initializeEngine() method on \a iface. Used by QQmlImportDatabase to ensure it
gets called in the correct thread.
*/
@@ -419,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);
@@ -427,16 +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)
{
- QQmlCompilingProfiler prof(profiler(), blob);
+ Q_TRACE_SCOPE(QQmlCompiling, blob->url());
+ QQmlCompilingProfiler prof(profiler(), blob.data());
blob->m_inCallback = true;
@@ -453,9 +415,10 @@ void QQmlTypeLoader::setData(QQmlDataBlob *blob, const QQmlDataBlob::SourceCodeD
blob->tryDone();
}
-void QQmlTypeLoader::setCachedUnit(QQmlDataBlob *blob, const QV4::CompiledData::Unit *unit)
+void QQmlTypeLoader::setCachedUnit(const QQmlDataBlob::Ptr &blob, const QQmlPrivate::CachedQmlUnit *unit)
{
- QQmlCompilingProfiler prof(profiler(), blob);
+ Q_TRACE_SCOPE(QQmlCompiling, blob->url());
+ QQmlCompilingProfiler prof(profiler(), blob.data());
blob->m_inCallback = true;
@@ -478,18 +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);
- majorVersion = import->majorVersion;
- minorVersion = import->minorVersion;
- 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)
{
}
@@ -501,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
@@ -517,188 +482,387 @@ 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());
- if (!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;
- if (!loadImportDependencies(import, qmldirIdentifier, errors))
+ // Use more specific version for dependencies if possible
+ if (version.hasMajorVersion())
+ import->version = version;
+
+ 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, QList<QQmlError> *errors)
+bool QQmlTypeLoader::Blob::addFileImport(const QQmlTypeLoader::Blob::PendingImportPtr &import, QList<QQmlError> *errors)
{
- return addImport(std::make_shared<PendingImport>(this, import), 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, 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;
+ // Use more specific version for dependencies if possible
+ if (actualVersion.hasMajorVersion())
+ import->version = actualVersion;
- if (m_importCache.locateQmldir(importDatabase, import->uri, import->majorVersion, import->minorVersion,
- &qmldirFilePath, &qmldirUrl)) {
- // This is a local library import
- if (!m_importCache.addLibraryImport(importDatabase, import->uri, import->qualifier, import->majorVersion,
- import->minorVersion, qmldirFilePath, qmldirUrl, false, errors))
- return false;
+ 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;
+ });
- if (!import->qualifier.isEmpty()) {
- // Does this library contain any qualified scripts?
- QUrl libraryUrl(qmldirUrl);
- const QQmlTypeLoaderQmldirContent qmldir = typeLoader()->qmldirContent(qmldirFilePath);
- 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);
- }
- }
- } else {
- // Is this a module?
- if (QQmlMetaType::isAnyModule(import->uri)) {
- if (!m_importCache.addLibraryImport(importDatabase, import->uri, import->qualifier, import->majorVersion,
- import->minorVersion, QString(), QString(), false, errors))
- return false;
- } else {
- // We haven't yet resolved this import
- m_unresolvedImports << import;
-
- QQmlAbstractUrlInterceptor *interceptor = typeLoader()->engine()->urlInterceptor();
-
- // Query any network import paths for this library.
- // Interceptor might redirect local paths.
- QStringList remotePathList = importDatabase->importPathList(
- interceptor ? QQmlImportDatabase::LocalOrRemote
- : QQmlImportDatabase::Remote);
- if (!remotePathList.isEmpty()) {
- // Add this library and request the possible locations for it
- if (!m_importCache.addLibraryImport(importDatabase, import->uri, import->qualifier, import->majorVersion,
- import->minorVersion, QString(), QString(), true, errors))
- return false;
+ 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;
+ }
- // Probe for all possible locations
- int priority = 0;
- const QStringList qmlDirPaths = QQmlImports::completeQmldirPaths(import->uri, remotePathList, import->majorVersion, import->minorVersion);
- for (const QString &qmldirPath : qmlDirPaths) {
- if (interceptor) {
- QUrl url = interceptor->intercept(
- 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;
- }
+ // 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 {
- 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;
- }
+ // 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;
- if (!m_importCache.addFileImport(importDatabase, import->uri, import->qualifier, import->majorVersion,
- import->minorVersion, incomplete, errors))
- 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)) {
+ return false;
+ }
- if (incomplete) {
- if (!fetchQmldir(qmldirUrl, import, 1, errors))
- return false;
+ }
}
}
return true;
}
+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);
+}
+
+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
+ }
+
+ 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(import->location.line);
- error.setColumn(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);
- for (const QString &implicitImports: qmldir.imports()) {
+ for (const auto &import : imports) {
+ if (import.flags & QQmlDirParser::Import::Optional)
+ continue;
auto dependencyImport = std::make_shared<PendingImport>();
- dependencyImport->uri = implicitImports;
- dependencyImport->qualifier = currentImport->qualifier;
- dependencyImport->majorVersion = currentImport->majorVersion;
- dependencyImport->minorVersion = currentImport->minorVersion;
- if (!addImport(dependencyImport, 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 dependent import \"%1\" version %2.%3")
+ .arg(dependencyImport->uri)
+ .arg(dependencyImport->version.majorVersion())
+ .arg(dependencyImport->version.minorVersion()));
+ errors->append(error);
return false;
+ }
}
+
+ 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;
}
@@ -707,40 +871,34 @@ bool QQmlTypeLoader::Blob::isDebugging() const
return typeLoader()->engine()->handle()->debugger() != nullptr;
}
-bool QQmlTypeLoader::Blob::diskCacheDisabled()
+bool QQmlTypeLoader::Blob::readCacheFile() const
{
- return disableDiskCache();
+ return typeLoader()->engine()->handle()->diskCacheOptions()
+ & QV4::ExecutionEngine::DiskCache::QmlcRead;
}
-bool QQmlTypeLoader::Blob::diskCacheForced()
+bool QQmlTypeLoader::Blob::writeCacheFile() const
{
- return forceDiskCache();
+ return typeLoader()->engine()->handle()->diskCacheOptions()
+ & QV4::ExecutionEngine::DiskCache::QmlcWrite;
}
-bool QQmlTypeLoader::Blob::qmldirDataAvailable(const QQmlRefPointer<QQmlQmldirData> &data, QList<QQmlError> *errors)
+QQmlMetaType::CacheMode QQmlTypeLoader::Blob::aotCacheMode() 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;
- }
-
- import->priority = priority;
- return true;
- }
- }
+ 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);
+ });
}
/*!
@@ -805,7 +963,11 @@ QQmlRefPointer<QQmlTypeData> QQmlTypeLoader::getType(const QUrl &unNormalizedUrl
// TODO: if (compiledData == 0), is it safe to omit this insertion?
m_typeCache.insert(url, typeData);
QQmlMetaType::CachedUnitLookupError error = QQmlMetaType::CachedUnitLookupError::NoError;
- if (const QV4::CompiledData::Unit *cachedUnit = 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 {
typeData->setCachedUnitStatus(error);
@@ -815,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;
@@ -844,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.
*/
@@ -863,8 +1045,11 @@ QQmlRefPointer<QQmlScriptBlob> QQmlTypeLoader::getScript(const QUrl &unNormalize
scriptBlob = new QQmlScriptBlob(url, this);
m_scriptCache.insert(url, scriptBlob);
- QQmlMetaType::CachedUnitLookupError error;
- if (const QV4::CompiledData::Unit *cachedUnit = QQmlMetaType::findCachedCompilationUnit(scriptBlob->url(), &error)) {
+ QQmlMetaType::CachedUnitLookupError error = QQmlMetaType::CachedUnitLookupError::NoError;
+ 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 {
scriptBlob->setCachedUnitStatus(error);
@@ -913,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));
@@ -947,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) {
@@ -960,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;
@@ -973,48 +1158,56 @@ bool QQmlTypeLoader::fileExists(const QString &path, const QString &file)
return false;
Q_ASSERT(path.endsWith(QLatin1Char('/')));
+
+ LockHolder<QQmlTypeLoader> holder(this);
+ QCache<QString, bool> *fileSet = m_importDirCache.object(path);
+ if (fileSet) {
+ if (bool *value = fileSet->object(file))
+ return *value;
+ } else if (m_importDirCache.contains(path)) {
+ // explicit nullptr in cache
+ return false;
+ }
+
+ auto addToCache = [&](const QFileInfo &fileInfo) {
+ if (!fileSet) {
+ fileSet = fileInfo.dir().exists() ? new QCache<QString, bool> : nullptr;
+ m_importDirCache.insert(path, fileSet);
+ if (!fileSet)
+ return false;
+ }
+
+ const bool exists = fileInfo.exists();
+ fileSet->insert(file, new bool(exists));
+ return exists;
+ };
+
if (path.at(0) == QLatin1Char(':')) {
// qrc resource
- QFileInfo fileInfo(path + file);
- return fileInfo.isFile();
- } else if (path.count() > 3 && path.at(3) == QLatin1Char(':') &&
- path.startsWith(QLatin1String("qrc"), Qt::CaseInsensitive)) {
+ return addToCache(QFileInfo(path + file));
+ }
+
+ if (path.size() > 3 && path.at(3) == QLatin1Char(':')
+ && path.startsWith(QLatin1String("qrc"), Qt::CaseInsensitive)) {
// qrc resource url
- QFileInfo fileInfo(QQmlFile::urlToLocalFileOrQrc(path + file));
- return fileInfo.isFile();
+ return addToCache(QFileInfo(QQmlFile::urlToLocalFileOrQrc(path + file)));
}
+
#if defined(Q_OS_ANDROID)
- else if (path.count() > 7 && path.at(6) == QLatin1Char(':') && path.at(7) == QLatin1Char('/') &&
- path.startsWith(QLatin1String("assets"), Qt::CaseInsensitive)) {
+ 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 + file));
- return fileInfo.isFile();
- } else if (path.count() > 8 && path.at(7) == QLatin1Char(':') && path.at(8) == QLatin1Char('/') &&
- path.startsWith(QLatin1String("content"), Qt::CaseInsensitive)) {
- // content url
- QFileInfo fileInfo(QQmlFile::urlToLocalFileOrQrc(path + file));
- return fileInfo.isFile();
+ return addToCache(QFileInfo(QQmlFile::urlToLocalFileOrQrc(path + file)));
}
-#endif
- LockHolder<QQmlTypeLoader> holder(this);
- if (!m_importDirCache.contains(path)) {
- bool exists = QDir(path).exists();
- QCache<QString, bool> *entry = exists ? new QCache<QString, bool> : nullptr;
- m_importDirCache.insert(path, entry);
+ 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)));
}
- QCache<QString, bool> *fileSet = m_importDirCache.object(path);
- if (!fileSet)
- return false;
+#endif
- bool *value = fileSet->object(file);
- if (value) {
- return *value;
- } else {
- bool exists = QFile::exists(path + file);
- fileSet->insert(file, new bool(exists));
- return exists;
- }
+ return addToCache(QFileInfo(path + file));
}
@@ -1038,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));
@@ -1075,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);
@@ -1125,7 +1318,8 @@ void QQmlTypeLoader::setQmldirContent(const QString &url, const QString &content
m_importQmlDirCache.insert(url, qmldir);
}
- qmldir->setContent(url, content);
+ if (!qmldir->hasContent())
+ qmldir->setContent(url, content);
}
/*!
@@ -1134,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)
@@ -1149,7 +1348,7 @@ void QQmlTypeLoader::clearCache()
m_qmldirCache.clear();
m_importDirCache.clear();
m_importQmlDirCache.clear();
- QQmlMetaType::freeUnusedTypesAndCaches();
+ m_checksumCache.clear();
}
void QQmlTypeLoader::updateTypeCacheTrimThreshold()
@@ -1164,29 +1363,40 @@ void QQmlTypeLoader::updateTypeCacheTrimThreshold()
void QQmlTypeLoader::trimCache()
{
while (true) {
- QList<TypeCache::Iterator> unneededTypes;
- for (TypeCache::Iterator iter = m_typeCache.begin(), end = m_typeCache.end(); iter != end; ++iter) {
+ bool deletedOneType = false;
+ for (TypeCache::Iterator iter = m_typeCache.begin(), end = m_typeCache.end(); iter != end;) {
QQmlTypeData *typeData = iter.value();
// 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
- unneededTypes.append(iter);
+ if (typeData->count() != 1 || (!typeData->isError() && !typeData->isComplete())) {
+ ++iter;
+ continue;
}
- }
- if (unneededTypes.isEmpty())
- break;
+ const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &compilationUnit
+ = typeData->m_compiledData;
+ if (compilationUnit) {
+ if (compilationUnit->count()
+ > QQmlMetaType::countInternalCompositeTypeSelfReferences(
+ compilationUnit) + 1) {
+ ++iter;
+ continue;
+ }
- while (!unneededTypes.isEmpty()) {
- TypeCache::Iterator iter = unneededTypes.takeLast();
+ QQmlMetaType::unregisterInternalCompositeType(compilationUnit);
+ Q_ASSERT(compilationUnit->count() == 1);
+ }
+ // There are no live objects of this type
iter.value()->release();
- m_typeCache.erase(iter);
+ iter = m_typeCache.erase(iter);
+ deletedOneType = true;
}
+
+ if (!deletedOneType)
+ break;
}
updateTypeCacheTrimThreshold();
diff --git a/src/qml/qml/qqmltypeloader_p.h b/src/qml/qml/qqmltypeloader_p.h
index d45f0e095c..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,66 +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;
- int majorVersion = -1;
- int minorVersion = -1;
-
+ 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, QList<QQmlError> *errors);
+ bool addImport(const QV4::CompiledData::Import *import, QQmlImports::ImportFlags,
+ 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 readCacheFile() const;
+ bool writeCacheFile() const;
+ QQmlMetaType::CacheMode aotCacheMode() const;
- static bool diskCacheDisabled();
- static bool diskCacheForced();
-
- QQmlImports m_importCache;
+ QQmlRefPointer<QQmlImports> m_importCache;
QVector<PendingImportPtr> m_unresolvedImports;
QVector<QQmlRefPointer<QQmlQmldirData>> m_qmldirs;
QQmlMetaType::CachedUnitLookupError m_cachedUnitStatus = QQmlMetaType::CachedUnitLookupError::NoError;
@@ -142,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 &);
@@ -170,7 +173,7 @@ public:
void load(QQmlDataBlob *, Mode = PreferSynchronous);
void loadWithStaticData(QQmlDataBlob *, const QByteArray &, Mode = PreferSynchronous);
- void loadWithCachedUnit(QQmlDataBlob *blob, const QV4::CompiledData::Unit *unit, Mode mode = PreferSynchronous);
+ void loadWithCachedUnit(QQmlDataBlob *blob, const QQmlPrivate::CachedQmlUnit *unit, Mode mode = PreferSynchronous);
QQmlEngine *engine() const;
void initializeEngine(QQmlEngineExtensionInterface *, const char *);
@@ -195,36 +198,20 @@ private:
void shutdownThread();
- void loadThread(QQmlDataBlob *);
- void loadWithStaticDataThread(QQmlDataBlob *, const QByteArray &);
- void loadWithCachedUnitThread(QQmlDataBlob *blob, const QV4::CompiledData::Unit *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 QV4::CompiledData::Unit *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;
@@ -249,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 8e983db756..5744cf2bb7 100644
--- a/src/qml/qml/qqmltypeloaderqmldircontent.cpp
+++ b/src/qml/qml/qqmltypeloaderqmldircontent.cpp
@@ -1,121 +1,43 @@
-/****************************************************************************
-**
-** 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>
#include <QtQml/qqmlerror.h>
QT_BEGIN_NAMESPACE
-QQmlTypeLoaderQmldirContent::QQmlTypeLoaderQmldirContent()
-{
-}
-
-bool QQmlTypeLoaderQmldirContent::hasError() const
-{
- return m_parser.hasError();
-}
-
-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;
error.setUrl(url);
- error.setLine(parseError.line);
- error.setColumn(parseError.column);
+ error.setLine(qmlConvertSourceCoordinate<quint32, int>(parseError.loc.startLine));
+ error.setColumn(qmlConvertSourceCoordinate<quint32, int>(parseError.loc.startColumn));
error.setDescription(parseError.message);
errors.append(error);
}
return errors;
}
-QString QQmlTypeLoaderQmldirContent::typeNamespace() const
-{
- return m_parser.typeNamespace();
-}
-
void QQmlTypeLoaderQmldirContent::setContent(const QString &location, const QString &content)
{
+ Q_ASSERT(!m_hasContent);
m_hasContent = true;
m_location = location;
m_parser.parse(content);
+ m_parser.disambiguateFileSelectors();
}
void QQmlTypeLoaderQmldirContent::setError(const QQmlError &error)
{
QQmlJS::DiagnosticMessage parseError;
- parseError.line = error.line();
- parseError.column = error.column();
+ parseError.loc.startLine = error.line();
+ parseError.loc.startColumn = error.column();
parseError.message = error.description();
m_parser.setError(parseError);
}
-QQmlDirComponents QQmlTypeLoaderQmldirContent::components() const
-{
- return m_parser.components();
-}
-
-QQmlDirScripts QQmlTypeLoaderQmldirContent::scripts() const
-{
- return m_parser.scripts();
-}
-
-QQmlDirPlugins QQmlTypeLoaderQmldirContent::plugins() const
-{
- return m_parser.plugins();
-}
-
-QStringList QQmlTypeLoaderQmldirContent::imports() const
-{
- return m_parser.imports();
-}
-
-QString QQmlTypeLoaderQmldirContent::pluginLocation() const
-{
- return m_location;
-}
-
-bool QQmlTypeLoaderQmldirContent::designerSupported() const
-{
- return m_parser.designerSupported();
-}
-
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmltypeloaderqmldircontent_p.h b/src/qml/qml/qqmltypeloaderqmldircontent_p.h
index 698643c7ec..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
@@ -65,24 +29,33 @@ private:
void setError(const QQmlError &);
public:
- QQmlTypeLoaderQmldirContent();
+ QQmlTypeLoaderQmldirContent() = default;
QQmlTypeLoaderQmldirContent(const QQmlTypeLoaderQmldirContent &) = default;
QQmlTypeLoaderQmldirContent &operator=(const QQmlTypeLoaderQmldirContent &) = default;
bool hasContent() const { return m_hasContent; }
- bool hasError() const;
- QList<QQmlError> errors(const QString &uri) const;
+ bool hasError() const { return m_parser.hasError(); }
+ QList<QQmlError> errors(const QString &uri, const QUrl &url) const;
- QString typeNamespace() const;
+ QString typeNamespace() const { return m_parser.typeNamespace(); }
- QQmlDirComponents components() const;
- QQmlDirScripts scripts() const;
- QQmlDirPlugins plugins() const;
- QStringList imports() const;
+ QQmlDirComponents components() const { return m_parser.components(); }
+ QQmlDirScripts scripts() const { return m_parser.scripts(); }
+ QQmlDirPlugins plugins() const { return m_parser.plugins(); }
+ QQmlDirImports imports() const { return m_parser.imports(); }
- QString pluginLocation() const;
+ QString qmldirLocation() const { return m_location; }
+ QString preferredPath() const { return m_parser.preferredPath(); }
- bool designerSupported() const;
+ 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 618bb09039..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 QV4::CompiledData::Unit *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 QV4::CompiledData::Unit *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 QV4::CompiledData::Unit *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 9fb441e6e2..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 QV4::CompiledData::Unit *unit);
- void loadWithCachedUnitAsync(QQmlDataBlob *b, const QV4::CompiledData::Unit *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 QV4::CompiledData::Unit *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 9c9bf3e48f..b188b7fb90 100644
--- a/src/qml/qml/qqmltypemodule.cpp
+++ b/src/qml/qml/qqmltypemodule.cpp
@@ -1,43 +1,7 @@
-/****************************************************************************
-**
-** 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_p.h"
+#include "qqmltypemodule_p.h"
#include <private/qqmltype_p_p.h>
@@ -45,62 +9,36 @@
QT_BEGIN_NAMESPACE
-QQmlTypeModule::QQmlTypeModule(const QString &module, int majorVersion)
- : d(new QQmlTypeModulePrivate(module, majorVersion))
+void QQmlTypeModule::addMinorVersion(quint8 version)
{
-}
-
-QQmlTypeModule::~QQmlTypeModule()
-{
- delete d;
-}
-
-QString QQmlTypeModule::module() const
-{
- // No need to lock. d->module is const
- return d->module;
-}
-
-int QQmlTypeModule::majorVersion() const
-{
- // No need to lock. d->majorVersion is const
- return d->majorVersion;
-}
-
-int QQmlTypeModule::minimumMinorVersion() const
-{
- return d->minMinorVersion.loadRelaxed();
-}
-
-int QQmlTypeModule::maximumMinorVersion() const
-{
- return d->maxMinorVersion.loadRelaxed();
-}
-
-void QQmlTypeModule::addMinorVersion(int version)
-{
- for (int oldVersion = d->minMinorVersion.loadRelaxed();
- oldVersion > version && !d->minMinorVersion.testAndSetOrdered(oldVersion, version);
- oldVersion = d->minMinorVersion.loadRelaxed()) {
+ for (int oldVersion = m_minMinorVersion.loadRelaxed();
+ oldVersion > version && !m_minMinorVersion.testAndSetOrdered(oldVersion, version);
+ oldVersion = m_minMinorVersion.loadRelaxed()) {
}
- for (int oldVersion = d->maxMinorVersion.loadRelaxed();
- oldVersion < version && !d->maxMinorVersion.testAndSetOrdered(oldVersion, version);
- oldVersion = d->maxMinorVersion.loadRelaxed()) {
+ for (int oldVersion = m_maxMinorVersion.loadRelaxed();
+ oldVersion < version && !m_maxMinorVersion.testAndSetOrdered(oldVersion, version);
+ oldVersion = m_maxMinorVersion.loadRelaxed()) {
}
}
void QQmlTypeModule::add(QQmlTypePrivate *type)
{
- QMutexLocker lock(&d->mutex);
- addMinorVersion(type->version_min);
+ QMutexLocker lock(&m_mutex);
- QList<QQmlTypePrivate *> &list = d->typeHash[type->elementName];
- for (int ii = 0; ii < list.count(); ++ii) {
- Q_ASSERT(list.at(ii));
- if (list.at(ii)->version_min < type->version_min) {
+ if (type->version.hasMinorVersion())
+ addMinorVersion(type->version.minorVersion());
+
+ QList<QQmlTypePrivate *> &list = m_typeHash[type->elementName];
+ 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()) {
list.insert(ii, type);
return;
+ } else if (in_list->version.minorVersion() == type->version.minorVersion()) {
+ list[ii] = type;
+ return;
}
}
list.append(type);
@@ -108,51 +46,16 @@ void QQmlTypeModule::add(QQmlTypePrivate *type)
void QQmlTypeModule::remove(const QQmlTypePrivate *type)
{
- QMutexLocker lock(&d->mutex);
- for (auto elementIt = d->typeHash.begin(); elementIt != d->typeHash.end();) {
+ QMutexLocker lock(&m_mutex);
+ for (auto elementIt = m_typeHash.begin(); elementIt != m_typeHash.end(); ++elementIt)
QQmlMetaType::removeQQmlTypePrivate(elementIt.value(), type);
-
-#if 0
- if (list.isEmpty())
- elementIt = typeHash.erase(elementIt);
- else
- ++elementIt;
-#else
- ++elementIt;
-#endif
- }
-}
-
-bool QQmlTypeModule::isLocked() const
-{
- return d->locked.loadRelaxed() != 0;
-}
-
-void QQmlTypeModule::lock()
-{
- d->locked.storeRelaxed(1);
-}
-
-QQmlType QQmlTypeModule::type(const QHashedStringRef &name, int minor) const
-{
- QMutexLocker lock(&d->mutex);
- QList<QQmlTypePrivate *> *types = d->typeHash.value(name);
- if (types) {
- for (int ii = 0; ii < types->count(); ++ii)
- if (types->at(ii)->version_min <= minor)
- return QQmlType(types->at(ii));
- }
-
- return QQmlType();
}
-QQmlType QQmlTypeModule::type(const QV4::String *name, int minor) const
+QQmlType QQmlTypeModule::findType(const QList<QQmlTypePrivate *> *types, QTypeRevision version)
{
- QMutexLocker lock(&d->mutex);
- QList<QQmlTypePrivate *> *types = d->typeHash.value(name);
if (types) {
- for (int ii = 0; ii < types->count(); ++ii)
- if (types->at(ii)->version_min <= minor)
+ for (int ii = 0; ii < types->size(); ++ii)
+ if (types->at(ii)->version.minorVersion() <= version.minorVersion())
return QQmlType(types->at(ii));
}
@@ -161,8 +64,8 @@ QQmlType QQmlTypeModule::type(const QV4::String *name, int minor) const
void QQmlTypeModule::walkCompositeSingletons(const std::function<void(const QQmlType &)> &callback) const
{
- QMutexLocker lock(&d->mutex);
- for (auto typeCandidates = d->typeHash.begin(), end = d->typeHash.end();
+ QMutexLocker lock(&m_mutex);
+ for (auto typeCandidates = m_typeHash.begin(), end = m_typeHash.end();
typeCandidates != end; ++typeCandidates) {
for (auto type: typeCandidates.value()) {
if (type->regType == QQmlType::CompositeSingletonType)
diff --git a/src/qml/qml/qqmltypemodule_p.h b/src/qml/qml/qqmltypemodule_p.h
index b84a91b5db..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
@@ -52,7 +16,11 @@
//
#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>
#include <functional>
@@ -61,40 +29,90 @@ QT_BEGIN_NAMESPACE
class QQmlType;
class QQmlTypePrivate;
struct QQmlMetaTypeData;
-class QHashedString;
-class QHashedStringRef;
namespace QV4 {
struct String;
}
-class QQmlTypeModulePrivate;
class QQmlTypeModule
{
public:
- QQmlTypeModule(const QString &uri = QString(), int majorVersion = 0);
- ~QQmlTypeModule();
+ enum class LockLevel {
+ Open = 0,
+ Weak = 1,
+ Strong = 2
+ };
+
+ QQmlTypeModule() = default;
+ QQmlTypeModule(const QString &uri, quint8 majorVersion)
+ : m_module(uri), m_majorVersion(majorVersion)
+ {}
void add(QQmlTypePrivate *);
void remove(const QQmlTypePrivate *type);
- bool isLocked() const;
- void lock();
+ 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
+ {
+ // No need to lock. m_module is const
+ return m_module;
+ }
+
+ quint8 majorVersion() const
+ {
+ // No need to lock. d->majorVersion is const
+ return m_majorVersion;
+ }
+
+ void addMinorVersion(quint8 minorVersion);
+ quint8 minimumMinorVersion() const { return m_minMinorVersion.loadRelaxed(); }
+ quint8 maximumMinorVersion() const { return m_maxMinorVersion.loadRelaxed(); }
+
+ 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);
+ }
- QString module() const;
- int majorVersion() const;
+ void walkCompositeSingletons(const std::function<void(const QQmlType &)> &callback) const;
- void addMinorVersion(int minorVersion);
- int minimumMinorVersion() const;
- int maximumMinorVersion() const;
+private:
+ static Q_QML_EXPORT QQmlType findType(
+ const QList<QQmlTypePrivate *> *types, QTypeRevision version);
- QQmlType type(const QHashedStringRef &, int) const;
- QQmlType type(const QV4::String *, int) const;
+ const QString m_module;
+ const quint8 m_majorVersion = 0;
- void walkCompositeSingletons(const std::function<void(const QQmlType &)> &callback) const;
+ // Can only ever decrease
+ QAtomicInt m_minMinorVersion = std::numeric_limits<quint8>::max();
-private:
- QQmlTypeModulePrivate *d;
+ // Can only ever increase
+ QAtomicInt m_maxMinorVersion = 0;
+
+ // LockLevel. Can only be increased.
+ QAtomicInt m_lockLevel = int(LockLevel::Open);
+
+ using TypeHash = QStringHash<QList<QQmlTypePrivate *>>;
+ TypeHash m_typeHash;
+
+ mutable QMutex m_mutex;
};
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmltypemodule_p_p.h b/src/qml/qml/qqmltypemodule_p_p.h
deleted file mode 100644
index b1dab1c4a0..0000000000
--- a/src/qml/qml/qqmltypemodule_p_p.h
+++ /dev/null
@@ -1,89 +0,0 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
-
-#ifndef QQMLTYPEMODULE_P_P_H
-#define QQMLTYPEMODULE_P_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/qqmltypemodule_p.h>
-#include <private/qstringhash_p.h>
-#include <private/qqmlmetatypedata_p.h>
-
-#include <QtCore/qmutex.h>
-
-QT_BEGIN_NAMESPACE
-
-class QQmlTypeModulePrivate
-{
-public:
- QQmlTypeModulePrivate(QString module, int majorVersion) :
- module(std::move(module)), majorVersion(majorVersion)
- {}
-
- const QString module;
- const int majorVersion = 0;
-
- // Can only ever decrease
- QAtomicInt minMinorVersion = std::numeric_limits<int>::max();
-
- // Can only ever increase
- QAtomicInt maxMinorVersion = 0;
-
- // Bool. Can only be set to 1 once.
- QAtomicInt locked = 0;
-
- typedef QStringHash<QList<QQmlTypePrivate *> > TypeHash;
- TypeHash typeHash;
-
- QMutex mutex;
-};
-
-QT_END_NAMESPACE
-
-#endif // QQMLTYPEMODULE_P_P_H
diff --git a/src/qml/qml/qqmltypemoduleversion.cpp b/src/qml/qml/qqmltypemoduleversion.cpp
index bbbfa1a7b6..072cf8a1cd 100644
--- a/src/qml/qml/qqmltypemoduleversion.cpp
+++ b/src/qml/qml/qqmltypemoduleversion.cpp
@@ -1,47 +1,8 @@
-/****************************************************************************
-**
-** 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"
-#include <private/qqmltype_p.h>
-#include <private/qqmltypemodule_p.h>
-
QT_BEGIN_NAMESPACE
QQmlTypeModuleVersion::QQmlTypeModuleVersion()
@@ -49,11 +10,10 @@ QQmlTypeModuleVersion::QQmlTypeModuleVersion()
{
}
-QQmlTypeModuleVersion::QQmlTypeModuleVersion(QQmlTypeModule *module, int minor)
- : m_module(module), m_minor(minor)
+QQmlTypeModuleVersion::QQmlTypeModuleVersion(QQmlTypeModule *module, QTypeRevision version)
+ : m_module(module), m_minor(version.minorVersion())
{
Q_ASSERT(m_module);
- Q_ASSERT(m_minor >= 0);
}
QQmlTypeModuleVersion::QQmlTypeModuleVersion(const QQmlTypeModuleVersion &o)
@@ -68,28 +28,4 @@ QQmlTypeModuleVersion &QQmlTypeModuleVersion::operator=(const QQmlTypeModuleVers
return *this;
}
-QQmlTypeModule *QQmlTypeModuleVersion::module() const
-{
- return m_module;
-}
-
-int QQmlTypeModuleVersion::minorVersion() const
-{
- return m_minor;
-}
-
-QQmlType QQmlTypeModuleVersion::type(const QHashedStringRef &name) const
-{
- if (!m_module)
- return QQmlType();
- return m_module->type(name, m_minor);
-}
-
-QQmlType QQmlTypeModuleVersion::type(const QV4::String *name) const
-{
- if (!m_module)
- return QQmlType();
- return m_module->type(name, m_minor);
-}
-
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmltypemoduleversion_p.h b/src/qml/qml/qqmltypemoduleversion_p.h
index 20f4709ecb..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
@@ -52,6 +16,9 @@
//
#include <QtQml/qtqmlglobal.h>
+#include <QtQml/private/qqmltype_p.h>
+#include <QtQml/private/qqmltypemodule_p.h>
+#include <QtCore/qversionnumber.h>
QT_BEGIN_NAMESPACE
@@ -67,19 +34,23 @@ class QQmlTypeModuleVersion
{
public:
QQmlTypeModuleVersion();
- QQmlTypeModuleVersion(QQmlTypeModule *, int);
+ QQmlTypeModuleVersion(QQmlTypeModule *, QTypeRevision);
QQmlTypeModuleVersion(const QQmlTypeModuleVersion &);
QQmlTypeModuleVersion &operator=(const QQmlTypeModuleVersion &);
- QQmlTypeModule *module() const;
- int minorVersion() const;
-
- QQmlType type(const QHashedStringRef &) const;
- QQmlType type(const QV4::String *) const;
+ template<typename String>
+ QQmlType type(String name) const
+ {
+ if (!m_module)
+ return QQmlType();
+ return m_module->type(name, QTypeRevision::isValidSegment(m_minor)
+ ? QTypeRevision::fromMinorVersion(m_minor)
+ : QTypeRevision());
+ }
private:
QQmlTypeModule *m_module;
- int m_minor;
+ quint8 m_minor;
};
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmltypenamecache.cpp b/src/qml/qml/qqmltypenamecache.cpp
index 8f1a61e6ad..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,117 +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, 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, 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 typeFound = m_imports.resolveType(typeName, &t, nullptr, nullptr, &typeNamespace, &errors,
- QQmlType::AnyRegistrationType, recursionRestriction);
- 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, 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 b98fe77ed5..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
@@ -52,7 +16,6 @@
//
#include <private/qqmlrefcount_p.h>
-#include "qqmlcleanup_p.h"
#include "qqmlmetatype_p.h"
#include <private/qstringhash_p.h>
@@ -82,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;
@@ -98,7 +61,6 @@ public:
inline Result(const QQmlImportRef *importNamespace);
inline Result(const QQmlType &type);
inline Result(int scriptIndex);
- inline Result(const Result &);
inline bool isValid() const;
@@ -106,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) {
@@ -131,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) {
@@ -159,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()
@@ -182,11 +261,6 @@ QQmlTypeNameCache::Result::Result(int scriptIndex)
{
}
-QQmlTypeNameCache::Result::Result(const Result &o)
-: type(o.type), importNamespace(o.importNamespace), scriptIndex(o.scriptIndex)
-{
-}
-
bool QQmlTypeNameCache::Result::isValid() const
{
return type.isValid() || importNamespace || scriptIndex != -1;
diff --git a/src/qml/qml/qqmltypenotavailable.cpp b/src/qml/qml/qqmltypenotavailable.cpp
deleted file mode 100644
index ffa4472e4b..0000000000
--- a/src/qml/qml/qqmltypenotavailable.cpp
+++ /dev/null
@@ -1,53 +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);
-}
-
-QQmlTypeNotAvailable::QQmlTypeNotAvailable() { }
-
-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 8db5876b10..0000000000
--- a/src/qml/qml/qqmltypenotavailable_p.h
+++ /dev/null
@@ -1,72 +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_UNCREATABLE("Type not available.")
-
-public:
- QQmlTypeNotAvailable();
-};
-
-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 ef4a628a04..2ab81102c7 100644
--- a/src/qml/qml/qqmltypewrapper.cpp
+++ b/src/qml/qml/qqmltypewrapper.cpp
@@ -1,83 +1,124 @@
-/****************************************************************************
-**
-** 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"
-#include <private/qqmlengine_p.h>
+#include <private/qjsvalue_p.h>
+
#include <private/qqmlcontext_p.h>
+#include <private/qqmlengine_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>
-#include <private/qv4objectproto_p.h>
-#include <private/qv4qobjectwrapper_p.h>
#include <private/qv4identifiertable_p.h>
#include <private/qv4lookup_p.h>
+#include <private/qv4objectproto_p.h>
+#include <private/qv4qobjectwrapper_p.h>
+#include <private/qv4symbol_p.h>
QT_BEGIN_NAMESPACE
using namespace QV4;
DEFINE_OBJECT_VTABLE(QQmlTypeWrapper);
+DEFINE_OBJECT_VTABLE(QQmlTypeConstructor);
DEFINE_OBJECT_VTABLE(QQmlScopedEnumWrapper);
-void Heap::QQmlTypeWrapper::init()
+
+void Heap::QQmlTypeWrapper::init(TypeNameMode m, QObject *o, const QQmlTypePrivate *type)
{
- Object::init();
- mode = IncludeEnums;
- object.init();
+ Q_ASSERT(type);
+ FunctionObject::init();
+ flags = quint8(m) | quint8(Type);
+ object.init(o);
+ QQmlType::refHandle(type);
+ t.typePrivate = type;
+}
+
+void Heap::QQmlTypeWrapper::init(
+ TypeNameMode m, QObject *o, QQmlTypeNameCache *type, const QQmlImportRef *import)
+{
+ Q_ASSERT(type);
+ FunctionObject::init();
+ flags = quint8(m) | quint8(Namespace);
+ object.init(o);
+ n.typeNamespace = type;
+ n.typeNamespace->addref();
+ n.importNamespace = import;
}
void Heap::QQmlTypeWrapper::destroy()
{
- QQmlType::derefHandle(typePrivate);
- typePrivate = nullptr;
- if (typeNamespace)
- typeNamespace->release();
+ switch (kind()) {
+ case Type:
+ Q_ASSERT(t.typePrivate);
+ QQmlType::derefHandle(t.typePrivate);
+ delete[] t.constructors;
+ break;
+ case Namespace:
+ Q_ASSERT(n.typeNamespace);
+ n.typeNamespace->release();
+ break;
+ }
+
object.destroy();
- Object::destroy();
+ FunctionObject::destroy();
}
QQmlType Heap::QQmlTypeWrapper::type() const
{
- return QQmlType(typePrivate);
+ switch (kind()) {
+ case Type:
+ return QQmlType(t.typePrivate);
+ case Namespace:
+ return QQmlType();
+ }
+
+ Q_UNREACHABLE_RETURN(QQmlType());
+}
+
+QQmlTypeNameCache::Result Heap::QQmlTypeWrapper::queryNamespace(
+ const QV4::String *name, QQmlEnginePrivate *enginePrivate) const
+{
+ Q_ASSERT(kind() == Namespace);
+ Q_ASSERT(n.typeNamespace);
+ Q_ASSERT(n.importNamespace);
+ return n.typeNamespace->query(name, n.importNamespace, QQmlTypeLoader::get(enginePrivate));
+
+}
+
+template<typename Callback>
+void warnWithLocation(const Heap::QQmlTypeWrapper *wrapper, Callback &&callback)
+{
+ auto log = qWarning().noquote().nospace();
+ if (const CppStackFrame *frame = wrapper->internalClass->engine->currentStackFrame)
+ log << frame->source() << ':' << frame->lineNumber() << ':';
+ callback(log.space());
+}
+
+void Heap::QQmlTypeWrapper::warnIfUncreatable() const
+{
+ const QQmlType t = type();
+ Q_ASSERT(t.isValid());
+
+ if (t.isValueType())
+ return;
+
+ if (t.isSingleton()) {
+ warnWithLocation(this, [&](QDebug &log) {
+ log << "You are calling a Q_INVOKABLE constructor of" << t.typeName()
+ << "which is a singleton in QML.";
+ });
+ return;
+ }
+
+ if (!t.isCreatable()) {
+ warnWithLocation(this, [&](QDebug &log) {
+ log << "You are calling a Q_INVOKABLE constructor of" << t.typeName()
+ << "which is uncreatable in QML.";
+ });
+ }
}
bool QQmlTypeWrapper::isSingleton() const
@@ -85,6 +126,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,74 +181,97 @@ 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));
return QVariant::fromValue<QObject*>(e->singletonInstance<QObject*>(type));
}
+ReturnedValue QQmlTypeWrapper::method_hasInstance(
+ const FunctionObject *, const Value *thisObject, const Value *argv, int argc)
+{
+ // we want to immediately call instanceOf rather than going through Function
+
+ if (!argc)
+ return Encode(false);
+ if (const Object *o = thisObject->as<Object>())
+ return o->instanceOf(argv[0]);
+ return Encode(false);
+}
+
+ReturnedValue QQmlTypeWrapper::method_toString(
+ const FunctionObject *b, const Value *thisObject, const Value *, int)
+{
+ const QQmlTypeWrapper *typeWrapper = thisObject->as<QQmlTypeWrapper>();
+ if (!typeWrapper)
+ RETURN_UNDEFINED();
+
+ const QString name = typeWrapper->d()->type().qmlTypeName();
+ return Encode(b->engine()->newString(name.isEmpty()
+ ? QLatin1String("Unknown Type")
+ : name));
+}
+
+void QQmlTypeWrapper::initProto(ExecutionEngine *v4)
+{
+ if (v4->typeWrapperPrototype()->d_unchecked())
+ return;
+
+ Scope scope(v4);
+ ScopedObject o(scope, v4->newObject());
+
+ o->defineDefaultProperty(v4->symbol_hasInstance(), method_hasInstance, 1, Attr_ReadOnly);
+ o->defineDefaultProperty(v4->id_toString(), method_toString, 0);
+ o->setPrototypeOf(v4->functionPrototype());
+
+ v4->jsObjects[QV4::ExecutionEngine::TypeWrapperProto] = o->d();
+}
// Returns a type wrapper for type t on o. This allows access of enums, and attached properties.
ReturnedValue QQmlTypeWrapper::create(QV4::ExecutionEngine *engine, QObject *o, const QQmlType &t,
Heap::QQmlTypeWrapper::TypeNameMode mode)
{
Q_ASSERT(t.isValid());
- Scope scope(engine);
+ initProto(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);
- return w.asReturnedValue();
+ QV4::MemoryManager *mm = engine->memoryManager;
+
+ if (const QMetaObject *mo = t.metaObject(); !mo || mo->constructorCount() == 0)
+ return mm->allocate<QQmlTypeWrapper>(mode, o, t.priv())->asReturnedValue();
+
+ return mm->allocate<QQmlTypeConstructor>(mode, o, t.priv())->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);
+ initProto(engine);
+
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;
-}
-
-static ReturnedValue throwLowercaseEnumError(QV4::ExecutionEngine *v4, String *name, const QQmlType &type)
-{
- const QString message =
- QStringLiteral("Cannot access enum value '%1' of '%2', enum values need to start with an uppercase letter.")
- .arg(name->toQString()).arg(QLatin1String(type.typeName()));
- return v4->throwTypeError(message);
+ 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)
@@ -174,7 +282,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());
@@ -183,28 +291,30 @@ ReturnedValue QQmlTypeWrapper::virtualGet(const Managed *m, PropertyKey id, cons
if (hasProperty)
*hasProperty = true;
- QQmlContextData *context = v4->callingQmlContext();
+ QQmlRefPointer<QQmlContextData> context = v4->callingQmlContext();
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;
+ const bool includeEnums
+ = w->d()->typeNameMode() == 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();
@@ -216,24 +326,19 @@ 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;
- // Warn when attempting to access a lowercased enum value, singleton case
- if (!ok && includeEnums && !name->startsWithUpper()) {
- enumForSingleton(v4, name, qobjectSingleton, type, &ok);
- if (ok)
- return throwLowercaseEnumError(v4, name, type);
- }
-
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::convertedToValue(v4, scriptSingleton));
+ QV4::ScopedObject o(scope, QJSValuePrivate::asReturnedValue(&scriptSingleton));
if (!!o)
return o->get(name);
}
@@ -245,11 +350,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();
@@ -265,7 +370,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
}
@@ -275,18 +382,16 @@ ReturnedValue QQmlTypeWrapper::virtualGet(const Managed *m, PropertyKey id, cons
// Fall through to base implementation
- } else if (w->d()->typeNamespace) {
- Q_ASSERT(w->d()->importNamespace);
- QQmlTypeNameCache::Result r = w->d()->typeNamespace->query(name, w->d()->importNamespace);
-
+ } else if (w->d()->kind() == Heap::QQmlTypeWrapper::Namespace) {
+ const QQmlTypeNameCache::Result r = w->d()->queryNamespace(name, enginePrivate);
if (r.isValid()) {
if (r.type.isValid()) {
- return create(scope.engine, object, r.type, w->d()->mode);
+ return create(scope.engine, object, r.type, w->d()->typeNameMode());
} else if (r.scriptIndex != -1) {
- QV4::ScopedObject scripts(scope, context->importedScripts.valueRef());
+ QV4::ScopedObject scripts(scope, context->importedScripts().valueRef());
return scripts->get(r.scriptIndex);
} else if (r.importNamespace) {
- return create(scope.engine, object, context->imports, r.importNamespace);
+ return create(scope.engine, object, context->imports(), r.importNamespace);
}
return QV4::Encode::undefined();
@@ -304,14 +409,6 @@ ReturnedValue QQmlTypeWrapper::virtualGet(const Managed *m, PropertyKey id, cons
if (hasProperty)
*hasProperty = ok;
- // Warn when attempting to access a lowercased enum value, non-singleton case
- if (!ok && type.isValid() && !type.isSingleton() && !name->startsWithUpper()) {
- bool enumOk = false;
- type.enumValue(QQmlEnginePrivate::get(v4->qmlEngine()), name, &enumOk);
- if (enumOk)
- return throwLowercaseEnumError(v4, name, type);
- }
-
return result;
}
@@ -325,11 +422,11 @@ 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());
- QQmlContextData *context = scope.engine->callingQmlContext();
+ QQmlRefPointer<QQmlContextData> context = scope.engine->callingQmlContext();
QQmlType type = w->d()->type();
if (type.isValid() && !type.isSingleton() && w->d()->object) {
@@ -338,18 +435,21 @@ 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);
if (!scriptSingleton.isUndefined()) {
- QV4::ScopedObject apiprivate(scope, QJSValuePrivate::convertedToValue(scope.engine, scriptSingleton));
+ QV4::ScopedObject apiprivate(scope, QJSValuePrivate::asReturnedValue(&scriptSingleton));
if (!apiprivate) {
QString error = QLatin1String("Cannot assign to read-only property \"") + name->toQString() + QLatin1Char('\"');
scope.engine->throwError(error);
@@ -390,44 +490,94 @@ 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, QObject *wrapperObject)
{
- 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 engine->throwTypeError();
-
+ QV4::ExecutionEngine *engine = typeWrapper->internalClass()->engine;
// in case the wrapper outlived the QObject*
- const QObject *wrapperObject = wrapper->object();
if (!wrapperObject)
return engine->throwTypeError();
- const int myTypeId = typeWrapper->d()->type().typeId();
+ const QQmlType type = typeWrapper->d()->type();
+ const QMetaType myTypeId = type.typeId();
QQmlMetaObject myQmlType;
- if (myTypeId == 0) {
+ if (!myTypeId.isValid()) {
// 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->metaTypeId);
+ 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);
+ myQmlType = QQmlMetaType::metaObjectForType(myTypeId);
+ if (myQmlType.isNull())
+ return Encode(false);
}
const QMetaObject *theirType = wrapperObject->metaObject();
- return QV4::Encode(QQmlMetaObject::canConvert(theirType, myQmlType));
+ if (QQmlMetaObject::canConvert(theirType, myQmlType))
+ return Encode(true);
+ else if (type.isValueType())
+ return Encode::undefined();
+ else
+ return Encode(false);
+}
+
+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->object());
+
+ if (const QQmlTypeWrapper *varTypeWrapper = var.as<QQmlTypeWrapper>()) {
+ // Singleton or attachment
+ if (QObject *varObject = varTypeWrapper->object())
+ return instanceOfQObject(typeWrapper, varObject);
+ }
+
+ const QQmlType type = typeWrapper->d()->type();
+
+ // If the target type is an object type we want null.
+ if (!type.isValueType())
+ return Encode(false);
+
+ const auto canCastValueType = [&]() -> bool {
+ if (const QQmlValueTypeWrapper *valueWrapper = var.as<QQmlValueTypeWrapper>()) {
+ return QQmlMetaObject::canConvert(
+ valueWrapper->metaObject(), type.metaObjectForValueType());
+ }
+
+ switch (type.typeId().id()) {
+ case QMetaType::Void:
+ return var.isUndefined();
+ case QMetaType::QVariant:
+ return true; // Everything is a var
+ case QMetaType::Int:
+ return var.isInteger();
+ case QMetaType::Double:
+ return var.isDouble(); // Integers are also doubles
+ case QMetaType::QString:
+ return var.isString();
+ case QMetaType::Bool:
+ return var.isBoolean();
+ }
+
+ return false;
+ };
+
+ // We want "foo as valuetype" to return undefined if it doesn't match.
+ return canCastValueType() ? Encode(true) : Encode::undefined();
}
ReturnedValue QQmlTypeWrapper::virtualResolveLookupGetter(const Object *object, ExecutionEngine *engine, Lookup *lookup)
@@ -440,7 +590,7 @@ ReturnedValue QQmlTypeWrapper::virtualResolveLookupGetter(const Object *object,
const QQmlTypeWrapper *This = static_cast<const QQmlTypeWrapper *>(object);
ScopedString name(scope, id.asStringOrSymbol());
- QQmlContextData *qmlContext = engine->callingQmlContext();
+ QQmlRefPointer<QQmlContextData> qmlContext = engine->callingQmlContext();
Scoped<QQmlTypeWrapper> w(scope, static_cast<const QQmlTypeWrapper *>(This));
QQmlType type = w->d()->type();
@@ -451,19 +601,24 @@ ReturnedValue QQmlTypeWrapper::virtualResolveLookupGetter(const Object *object,
QQmlEnginePrivate *e = QQmlEnginePrivate::get(engine->qmlEngine());
if (type.isQObjectSingleton() || type.isCompositeSingleton()) {
if (QObject *qobjectSingleton = e->singletonInstance<QObject*>(type)) {
- const bool includeEnums = w->d()->mode == Heap::QQmlTypeWrapper::IncludeEnums;
+ const bool includeEnums
+ = w->d()->typeNameMode() == Heap::QQmlTypeWrapper::IncludeEnums;
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
@@ -481,7 +636,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;
@@ -496,9 +651,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();
}
@@ -514,6 +669,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]() {
@@ -526,6 +705,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();
@@ -544,7 +733,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)
@@ -562,12 +786,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 7dc3f55310..fa859dd118 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
@@ -55,7 +19,8 @@
#include <QtCore/qpointer.h>
#include <private/qv4value_p.h>
-#include <private/qv4object_p.h>
+#include <private/qv4functionobject_p.h>
+#include <private/qv4qmetaobjectwrapper_p.h>
QT_BEGIN_NAMESPACE
@@ -68,24 +33,65 @@ namespace QV4 {
namespace Heap {
-struct QQmlTypeWrapper : Object {
- enum TypeNameMode {
- IncludeEnums,
- ExcludeEnums
+struct QQmlTypeWrapper : FunctionObject {
+
+ enum TypeNameMode : quint8 {
+ ExcludeEnums = 0x0,
+ IncludeEnums = 0x1,
+ TypeNameModeMask = 0x1,
+ };
+
+ enum Kind : quint8 {
+ Type = 0x0,
+ Namespace = 0x2,
+ KindMask = 0x2
};
- 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;
- QQmlQPointer<QObject> object;
+
+ const QMetaObject *metaObject() const { return type().metaObject(); }
+ QMetaType metaType() const { return type().typeId(); }
QQmlType type() const;
+ TypeNameMode typeNameMode() const { return TypeNameMode(flags & TypeNameModeMask); }
+ Kind kind() const { return Kind(flags & KindMask); }
+
+ const QQmlPropertyData *ensureConstructorsCache(
+ const QMetaObject *metaObject, QMetaType metaType)
+ {
+ Q_ASSERT(kind() == Type);
+ if (!t.constructors && metaObject) {
+ t.constructors = QMetaObjectWrapper::createConstructors(metaObject, metaType);
+ warnIfUncreatable();
+ }
+ return t.constructors;
+ }
+ void warnIfUncreatable() const;
+
+ QQmlTypeNameCache::Result queryNamespace(
+ const QV4::String *name, QQmlEnginePrivate *enginePrivate) const;
+
+ QV4QPointer<QObject> object;
+
+ union {
+ struct {
+ const QQmlTypePrivate *typePrivate;
+ const QQmlPropertyData *constructors;
+ } t;
+ struct {
+ QQmlTypeNameCache *typeNamespace;
+ const QQmlImportRef *importNamespace;
+ } n;
+ };
- const QQmlTypePrivate *typePrivate;
- QQmlTypeNameCache *typeNamespace;
- const QQmlImportRef *importNamespace;
+ quint8 flags;
};
+using QQmlTypeConstructor = QQmlTypeWrapper;
+
struct QQmlScopedEnumWrapper : Object {
void init() { Object::init(); }
void destroy();
@@ -96,16 +102,21 @@ struct QQmlScopedEnumWrapper : Object {
}
-struct Q_QML_EXPORT QQmlTypeWrapper : Object
+struct Q_QML_EXPORT QQmlTypeWrapper : FunctionObject
{
- V4_OBJECT2(QQmlTypeWrapper, Object)
+ V4_OBJECT2(QQmlTypeWrapper, FunctionObject)
+ V4_PROTOTYPE(typeWrapperPrototype)
V4_NEEDS_DESTROY
bool isSingleton() const;
+ const QMetaObject *metaObject() const;
+ QObject *object() const;
QObject *singletonObject() const;
QVariant toVariant() const;
+ static void initProto(ExecutionEngine *v4);
+
static ReturnedValue create(ExecutionEngine *, QObject *, const QQmlType &,
Heap::QQmlTypeWrapper::TypeNameMode = Heap::QQmlTypeWrapper::IncludeEnums);
static ReturnedValue create(ExecutionEngine *, QObject *, const QQmlRefPointer<QQmlTypeNameCache> &, const QQmlImportRef *,
@@ -113,8 +124,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);
@@ -124,6 +138,25 @@ protected:
static PropertyAttributes virtualGetOwnProperty(const Managed *m, PropertyKey id, Property *p);
static bool virtualIsEqualTo(Managed *that, Managed *o);
static ReturnedValue virtualInstanceOf(const Object *typeObject, const Value &var);
+
+private:
+ static ReturnedValue method_hasInstance(
+ const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
+ static ReturnedValue method_toString(
+ const FunctionObject *b, const Value *thisObject, const Value *, int);
+};
+
+struct QQmlTypeConstructor : QQmlTypeWrapper
+{
+ V4_OBJECT2(QQmlTypeConstructor, QQmlTypeWrapper)
+
+ static ReturnedValue virtualCallAsConstructor(
+ const FunctionObject *f, const Value *argv, int argc, const Value *)
+ {
+ Q_ASSERT(f->as<QQmlTypeWrapper>());
+ return QMetaObjectWrapper::construct(
+ static_cast<const QQmlTypeWrapper *>(f)->d(), argv, argc);
+ }
};
struct Q_QML_EXPORT QQmlScopedEnumWrapper : Object
diff --git a/src/qml/qml/qqmlvaluetype.cpp b/src/qml/qml/qqmlvaluetype.cpp
index d83fc4bb48..4088d6e6c4 100644
--- a/src/qml/qml/qqmlvaluetype.cpp
+++ b/src/qml/qml/qqmlvaluetype.cpp
@@ -1,295 +1,117 @@
-/****************************************************************************
-**
-** 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"
#include <QtCore/qmutex.h>
#include <private/qqmlglobal_p.h>
#include <QtCore/qdebug.h>
+#include <private/qqmlengine_p.h>
#include <private/qmetaobjectbuilder_p.h>
-#if QT_CONFIG(qml_itemmodel)
-#include <private/qqmlmodelindexvaluetype_p.h>
-#endif
-#include <private/qmetatype_p.h>
QT_BEGIN_NAMESPACE
-namespace {
-
-struct QQmlValueTypeFactoryImpl
-{
- QQmlValueTypeFactoryImpl();
- ~QQmlValueTypeFactoryImpl();
-
- bool isValueType(int idx);
-
- const QMetaObject *metaObjectForMetaType(int);
- QQmlValueType *valueType(int);
-
- QQmlValueType *valueTypes[QVariant::UserType];
- QHash<int, QQmlValueType *> userTypes;
- QMutex mutex;
-
- QQmlValueType invalidValueType;
-};
-
-QQmlValueTypeFactoryImpl::QQmlValueTypeFactoryImpl()
-{
- std::fill_n(valueTypes, int(QVariant::UserType), &invalidValueType);
-
-#if QT_CONFIG(qml_itemmodel)
- // See types wrapped in qqmlmodelindexvaluetype_p.h
- qRegisterMetaType<QItemSelectionRange>();
-#endif
-}
-
-QQmlValueTypeFactoryImpl::~QQmlValueTypeFactoryImpl()
-{
- for (QQmlValueType *type : valueTypes) {
- if (type != &invalidValueType)
- delete type;
- }
- qDeleteAll(userTypes);
-}
-
-bool isInternalType(int idx)
-{
- // Qt internal types
- switch (idx) {
- case QMetaType::UnknownType:
- case QMetaType::QStringList:
- case QMetaType::QObjectStar:
- case QMetaType::VoidStar:
- case QMetaType::Nullptr:
- case QMetaType::QVariant:
- case QMetaType::QLocale:
- case QMetaType::QImage: // scarce type, keep as QVariant
- case QMetaType::QPixmap: // scarce type, keep as QVariant
- return true;
- default:
- return false;
- }
-}
-
-bool QQmlValueTypeFactoryImpl::isValueType(int idx)
+QQmlValueType::~QQmlValueType()
{
- if (idx < 0 || isInternalType(idx))
- return false;
-
- return valueType(idx) != nullptr;
+ ::free(m_dynamicMetaObject);
}
-const QMetaObject *QQmlValueTypeFactoryImpl::metaObjectForMetaType(int t)
+QQmlGadgetPtrWrapper *QQmlGadgetPtrWrapper::instance(QQmlEngine *engine, QMetaType type)
{
- switch (t) {
- case QVariant::Point:
- return &QQmlPointValueType::staticMetaObject;
- case QVariant::PointF:
- return &QQmlPointFValueType::staticMetaObject;
- case QVariant::Size:
- return &QQmlSizeValueType::staticMetaObject;
- case QVariant::SizeF:
- return &QQmlSizeFValueType::staticMetaObject;
- case QVariant::Rect:
- return &QQmlRectValueType::staticMetaObject;
- case QVariant::RectF:
- return &QQmlRectFValueType::staticMetaObject;
-#if QT_CONFIG(easingcurve)
- case QVariant::EasingCurve:
- return &QQmlEasingValueType::staticMetaObject;
-#endif
-#if QT_CONFIG(qml_itemmodel)
- case QVariant::ModelIndex:
- return &QQmlModelIndexValueType::staticMetaObject;
- case QVariant::PersistentModelIndex:
- return &QQmlPersistentModelIndexValueType::staticMetaObject;
-#endif
- default:
-#if QT_CONFIG(qml_itemmodel)
- if (t == qMetaTypeId<QItemSelectionRange>())
- return &QQmlItemSelectionRangeValueType::staticMetaObject;
-#endif
-
- if (const QMetaObject *mo = QQml_valueTypeProvider()->metaObjectForMetaType(t))
- return mo;
- break;
- }
-
- QMetaType metaType(t);
- if (metaType.flags() & QMetaType::IsGadget)
- return metaType.metaObject();
- return nullptr;
+ return engine ? QQmlEnginePrivate::get(engine)->valueTypeInstance(type) : nullptr;
}
-QQmlValueType *QQmlValueTypeFactoryImpl::valueType(int idx)
+QQmlGadgetPtrWrapper::QQmlGadgetPtrWrapper(QQmlValueType *valueType, QObject *parent)
+ : QObject(parent), m_gadgetPtr(valueType->create())
{
- if (idx >= (int)QVariant::UserType) {
- // Protect the hash with a mutex
- mutex.lock();
-
- QHash<int, QQmlValueType *>::iterator it = userTypes.find(idx);
- if (it == userTypes.end()) {
- QQmlValueType *vt = nullptr;
- if (const QMetaObject *mo = metaObjectForMetaType(idx))
- vt = new QQmlValueType(idx, mo);
- it = userTypes.insert(idx, vt);
- }
-
- mutex.unlock();
- return *it;
- }
-
- QQmlValueType *rv = valueTypes[idx];
- if (rv == &invalidValueType) {
- // No need for mutex protection - the most we can lose is a valueType instance
-
- // TODO: Investigate the performance/memory characteristics of
- // removing the preallocated array
- if (isInternalType(idx))
- rv = valueTypes[idx] = nullptr;
- else if (const QMetaObject *mo = metaObjectForMetaType(idx))
- rv = valueTypes[idx] = new QQmlValueType(idx, mo);
- else
- rv = valueTypes[idx] = nullptr;
- }
-
- return rv;
+ QObjectPrivate *d = QObjectPrivate::get(this);
+ Q_ASSERT(!d->metaObject);
+ d->metaObject = valueType;
}
-}
-
-Q_GLOBAL_STATIC(QQmlValueTypeFactoryImpl, factoryImpl);
-
-bool QQmlValueTypeFactory::isValueType(int idx)
+QQmlGadgetPtrWrapper::~QQmlGadgetPtrWrapper()
{
- return factoryImpl()->isValueType(idx);
+ QObjectPrivate *d = QObjectPrivate::get(this);
+ static_cast<const QQmlValueType *>(d->metaObject)->destroy(m_gadgetPtr);
+ d->metaObject = nullptr;
}
-QQmlValueType *QQmlValueTypeFactory::valueType(int idx)
+void QQmlGadgetPtrWrapper::read(QObject *obj, int idx)
{
- return factoryImpl()->valueType(idx);
+ Q_ASSERT(m_gadgetPtr);
+ void *a[] = { m_gadgetPtr, nullptr };
+ QMetaObject::metacall(obj, QMetaObject::ReadProperty, idx, a);
}
-const QMetaObject *QQmlValueTypeFactory::metaObjectForMetaType(int type)
+void QQmlGadgetPtrWrapper::write(
+ QObject *obj, int idx, QQmlPropertyData::WriteFlags flags, int internalIndex) const
{
- return factoryImpl()->metaObjectForMetaType(type);
+ Q_ASSERT(m_gadgetPtr);
+ int status = -1;
+ void *a[] = { m_gadgetPtr, nullptr, &status, &flags, &internalIndex };
+ QMetaObject::metacall(obj, QMetaObject::WriteProperty, idx, a);
}
-void QQmlValueTypeFactory::registerValueTypes(const char *uri, int versionMajor, int versionMinor)
+QVariant QQmlGadgetPtrWrapper::value() const
{
-#if QT_CONFIG(easingcurve)
- qmlRegisterValueTypeEnums<QQmlEasingValueType>(uri, versionMajor, versionMinor, "Easing");
-#endif
-}
+ Q_ASSERT(m_gadgetPtr);
-QQmlValueType::QQmlValueType() :
- _metaObject(nullptr),
- gadgetPtr(nullptr),
- metaType(QMetaType::UnknownType)
-{
+ const QMetaType m = metaType();
+ return m == QMetaType::fromType<QVariant>()
+ ? *static_cast<const QVariant *>(m_gadgetPtr)
+ : QVariant(m, m_gadgetPtr);
}
-QQmlValueType::QQmlValueType(int typeId, const QMetaObject *gadgetMetaObject)
- : gadgetPtr(QMetaType::create(typeId))
- , metaType(typeId)
+void QQmlGadgetPtrWrapper::setValue(const QVariant &value)
{
- QObjectPrivate *op = QObjectPrivate::get(this);
- Q_ASSERT(!op->metaObject);
- op->metaObject = this;
+ Q_ASSERT(m_gadgetPtr);
- QMetaObjectBuilder builder(gadgetMetaObject);
- _metaObject = builder.toMetaObject();
-
- *static_cast<QMetaObject*>(this) = *_metaObject;
-}
-
-QQmlValueType::~QQmlValueType()
-{
- QObjectPrivate *op = QObjectPrivate::get(this);
- Q_ASSERT(op->metaObject == nullptr || op->metaObject == this);
- op->metaObject = nullptr;
- ::free(const_cast<QMetaObject *>(_metaObject));
- metaType.destroy(gadgetPtr);
+ 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());
+ }
}
-void QQmlValueType::read(QObject *obj, int idx)
+int QQmlGadgetPtrWrapper::metaCall(QMetaObject::Call type, int id, void **argv)
{
- void *a[] = { gadgetPtr, nullptr };
- QMetaObject::metacall(obj, QMetaObject::ReadProperty, idx, a);
+ Q_ASSERT(m_gadgetPtr);
+ const QMetaObject *metaObject = valueType()->staticMetaObject();
+ QQmlMetaObject::resolveGadgetMethodOrPropertyIndex(type, &metaObject, &id);
+ metaObject->d.static_metacall(static_cast<QObject *>(m_gadgetPtr), type, id, argv);
+ return id;
}
-void QQmlValueType::write(QObject *obj, int idx, QQmlPropertyData::WriteFlags flags)
+const QQmlValueType *QQmlGadgetPtrWrapper::valueType() const
{
- Q_ASSERT(gadgetPtr);
- int status = -1;
- void *a[] = { gadgetPtr, nullptr, &status, &flags };
- QMetaObject::metacall(obj, QMetaObject::WriteProperty, idx, a);
+ const QObjectPrivate *d = QObjectPrivate::get(this);
+ return static_cast<const QQmlValueType *>(d->metaObject);
}
-QVariant QQmlValueType::value()
+QMetaObject *QQmlValueType::toDynamicMetaObject(QObject *)
{
- Q_ASSERT(gadgetPtr);
- return QVariant(metaType.id(), gadgetPtr);
-}
+ if (!m_dynamicMetaObject) {
+ QMetaObjectBuilder builder(m_staticMetaObject);
-void QQmlValueType::setValue(const QVariant &value)
-{
- Q_ASSERT(metaType.id() == value.userType());
- metaType.destruct(gadgetPtr);
- metaType.construct(gadgetPtr, value.constData());
-}
+ // 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.
-QAbstractDynamicMetaObject *QQmlValueType::toDynamicMetaObject(QObject *)
-{
- return this;
+ m_dynamicMetaObject = builder.toMetaObject();
+ }
+ return m_dynamicMetaObject;
}
void QQmlValueType::objectDestroyed(QObject *)
{
}
-int QQmlValueType::metaCall(QObject *, QMetaObject::Call type, int _id, void **argv)
+int QQmlValueType::metaCall(QObject *object, QMetaObject::Call type, int _id, void **argv)
{
- const QMetaObject *mo = _metaObject;
- QQmlMetaObject::resolveGadgetMethodOrPropertyIndex(type, &mo, &_id);
- mo->d.static_metacall(reinterpret_cast<QObject*>(gadgetPtr), type, _id, argv);
- return _id;
+ return static_cast<QQmlGadgetPtrWrapper *>(object)->metaCall(type, _id, argv);
}
QString QQmlPointFValueType::toString() const
@@ -318,6 +140,11 @@ void QQmlPointFValueType::setY(qreal y)
}
+QString QQmlPointValueType::toString() const
+{
+ return QString::asprintf("QPoint(%d, %d)", v.x(), v.y());
+}
+
int QQmlPointValueType::x() const
{
return v.x();
@@ -365,6 +192,11 @@ void QQmlSizeFValueType::setHeight(qreal h)
}
+QString QQmlSizeValueType::toString() const
+{
+ return QString::asprintf("QSize(%d, %d)", v.width(), v.height());
+}
+
int QQmlSizeValueType::width() const
{
return v.width();
@@ -450,6 +282,12 @@ qreal QQmlRectFValueType::bottom() const
return v.bottom();
}
+
+QString QQmlRectValueType::toString() const
+{
+ return QString::asprintf("QRect(%d, %d, %d, %d)", v.x(), v.y(), v.width(), v.height());
+}
+
int QQmlRectValueType::x() const
{
return v.x();
@@ -511,9 +349,9 @@ int QQmlRectValueType::bottom() const
}
#if QT_CONFIG(easingcurve)
-QQmlEasingValueType::Type QQmlEasingValueType::type() const
+QQmlEasingEnums::Type QQmlEasingValueType::type() const
{
- return (QQmlEasingValueType::Type)v.type();
+ return (QQmlEasingEnums::Type)v.type();
}
qreal QQmlEasingValueType::amplitude() const
@@ -531,7 +369,7 @@ qreal QQmlEasingValueType::period() const
return v.period();
}
-void QQmlEasingValueType::setType(QQmlEasingValueType::Type type)
+void QQmlEasingValueType::setType(QQmlEasingEnums::Type type)
{
v.setType((QEasingCurve::Type)type);
}
@@ -556,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) {
diff --git a/src/qml/qml/qqmlvaluetype_p.h b/src/qml/qml/qqmlvaluetype_p.h
index 0601237c4b..dd23547c04 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,10 +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>
@@ -65,96 +30,172 @@
QT_BEGIN_NAMESPACE
-class Q_QML_PRIVATE_EXPORT QQmlValueType : public QObject, public QAbstractDynamicMetaObject
+class Q_QML_EXPORT QQmlValueType : public QDynamicMetaObjectData
{
public:
- QQmlValueType();
- QQmlValueType(int userType, const QMetaObject *metaObject);
- ~QQmlValueType() override;
- void read(QObject *, int);
- void write(QObject *, int, QQmlPropertyData::WriteFlags flags);
- QVariant value();
- void setValue(const QVariant &);
+ QQmlValueType() = default;
+ QQmlValueType(QMetaType type, const QMetaObject *staticMetaObject)
+ : m_metaType(type), m_staticMetaObject(staticMetaObject)
+ {}
+ ~QQmlValueType();
+
+ void *create() const { return m_metaType.create(); }
+ void destroy(void *gadgetPtr) const { m_metaType.destroy(gadgetPtr); }
+
+ void construct(void *gadgetPtr, const void *copy) const { m_metaType.construct(gadgetPtr, copy); }
+ void destruct(void *gadgetPtr) const { m_metaType.destruct(gadgetPtr); }
+
+ 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;
// ----
private:
- const QMetaObject *_metaObject;
- void *gadgetPtr;
-
-public:
- QMetaType metaType;
+ QMetaType m_metaType;
+ const QMetaObject *m_staticMetaObject = nullptr;
+ QMetaObject *m_dynamicMetaObject = nullptr;
};
-class Q_QML_PRIVATE_EXPORT QQmlValueTypeFactory
+class Q_QML_EXPORT QQmlGadgetPtrWrapper : public QObject
{
+ Q_OBJECT
public:
- static bool isValueType(int idx);
- static QQmlValueType *valueType(int idx);
- static const QMetaObject *metaObjectForMetaType(int type);
+ static QQmlGadgetPtrWrapper *instance(QQmlEngine *engine, QMetaType type);
+
+ QQmlGadgetPtrWrapper(QQmlValueType *valueType, QObject *parent = nullptr);
+ ~QQmlGadgetPtrWrapper();
+
+ void read(QObject *obj, int idx);
+ void write(QObject *obj, int idx, QQmlPropertyData::WriteFlags flags,
+ int internalIndex = QV4::ReferenceObject::AllProperties) const;
+ QVariant value() const;
+ void setValue(const QVariant &value);
+
+ QMetaType metaType() const { return valueType()->metaType(); }
+ int metaCall(QMetaObject::Call type, int id, void **argv);
+
+ 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);
+ }
- static void registerValueTypes(const char *uri, int versionMajor, int versionMinor);
+ void writeOnGadget(const QMetaProperty &property, QVariant &&value)
+ {
+ property.writeOnGadget(m_gadgetPtr, std::move(value));
+ }
+
+private:
+ const QQmlValueType *valueType() const;
+ void *m_gadgetPtr = nullptr;
};
-struct QQmlPointFValueType
+struct Q_QML_EXPORT QQmlPointFValueType
{
QPointF v;
Q_PROPERTY(qreal x READ x WRITE setX FINAL)
Q_PROPERTY(qreal y READ y WRITE setY FINAL)
Q_GADGET
+ QML_VALUE_TYPE(point)
+ QML_FOREIGN(QPointF)
+ QML_EXTENDED(QQmlPointFValueType)
+ QML_STRUCTURED_VALUE
+
public:
+ Q_INVOKABLE 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 QQmlPointValueType
+struct Q_QML_EXPORT QQmlPointValueType
{
QPoint v;
Q_PROPERTY(int x READ x WRITE setX FINAL)
Q_PROPERTY(int y READ y WRITE setY FINAL)
Q_GADGET
+ QML_ANONYMOUS
+ QML_FOREIGN(QPoint)
+ 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 QQmlSizeFValueType
+struct Q_QML_EXPORT QQmlSizeFValueType
{
QSizeF v;
Q_PROPERTY(qreal width READ width WRITE setWidth FINAL)
Q_PROPERTY(qreal height READ height WRITE setHeight FINAL)
Q_GADGET
+ QML_VALUE_TYPE(size)
+ QML_FOREIGN(QSizeF)
+ QML_EXTENDED(QQmlSizeFValueType)
+ QML_STRUCTURED_VALUE
+
public:
+ Q_INVOKABLE 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 QQmlSizeValueType
+struct Q_QML_EXPORT QQmlSizeValueType
{
QSize v;
Q_PROPERTY(int width READ width WRITE setWidth FINAL)
Q_PROPERTY(int height READ height WRITE setHeight FINAL)
Q_GADGET
+ QML_ANONYMOUS
+ QML_FOREIGN(QSize)
+ 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 QQmlRectFValueType
+struct Q_QML_EXPORT QQmlRectFValueType
{
QRectF v;
Q_PROPERTY(qreal x READ x WRITE setX FINAL)
@@ -166,7 +207,14 @@ struct QQmlRectFValueType
Q_PROPERTY(qreal top READ top DESIGNABLE false FINAL)
Q_PROPERTY(qreal bottom READ bottom DESIGNABLE false FINAL)
Q_GADGET
+ QML_VALUE_TYPE(rect)
+ QML_FOREIGN(QRectF)
+ QML_EXTENDED(QQmlRectFValueType)
+ QML_STRUCTURED_VALUE
+
public:
+ Q_INVOKABLE QQmlRectFValueType() = default;
+ Q_INVOKABLE QQmlRectFValueType(const QRect &rect) : v(rect) {}
Q_INVOKABLE QString toString() const;
qreal x() const;
qreal y() const;
@@ -182,9 +230,11 @@ public:
qreal right() const;
qreal top() const;
qreal bottom() const;
+
+ operator QRectF() const { return v; }
};
-struct QQmlRectValueType
+struct Q_QML_EXPORT QQmlRectValueType
{
QRect v;
Q_PROPERTY(int x READ x WRITE setX FINAL)
@@ -196,7 +246,15 @@ struct QQmlRectValueType
Q_PROPERTY(int top READ top DESIGNABLE false FINAL)
Q_PROPERTY(int bottom READ bottom DESIGNABLE false FINAL)
Q_GADGET
+ QML_ANONYMOUS
+ QML_FOREIGN(QRect)
+ 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;
void setX(int);
@@ -211,91 +269,85 @@ public:
int right() const;
int top() const;
int bottom() const;
+
+ operator QRect() const { return v; }
};
#if QT_CONFIG(easingcurve)
-struct QQmlEasingValueType
+namespace QQmlEasingEnums
+{
+Q_NAMESPACE_EXPORT(Q_QML_EXPORT)
+QML_NAMED_ELEMENT(Easing)
+
+enum Type {
+ Linear = QEasingCurve::Linear,
+ InQuad = QEasingCurve::InQuad, OutQuad = QEasingCurve::OutQuad,
+ InOutQuad = QEasingCurve::InOutQuad, OutInQuad = QEasingCurve::OutInQuad,
+ InCubic = QEasingCurve::InCubic, OutCubic = QEasingCurve::OutCubic,
+ InOutCubic = QEasingCurve::InOutCubic, OutInCubic = QEasingCurve::OutInCubic,
+ InQuart = QEasingCurve::InQuart, OutQuart = QEasingCurve::OutQuart,
+ InOutQuart = QEasingCurve::InOutQuart, OutInQuart = QEasingCurve::OutInQuart,
+ InQuint = QEasingCurve::InQuint, OutQuint = QEasingCurve::OutQuint,
+ InOutQuint = QEasingCurve::InOutQuint, OutInQuint = QEasingCurve::OutInQuint,
+ InSine = QEasingCurve::InSine, OutSine = QEasingCurve::OutSine,
+ InOutSine = QEasingCurve::InOutSine, OutInSine = QEasingCurve::OutInSine,
+ InExpo = QEasingCurve::InExpo, OutExpo = QEasingCurve::OutExpo,
+ InOutExpo = QEasingCurve::InOutExpo, OutInExpo = QEasingCurve::OutInExpo,
+ InCirc = QEasingCurve::InCirc, OutCirc = QEasingCurve::OutCirc,
+ InOutCirc = QEasingCurve::InOutCirc, OutInCirc = QEasingCurve::OutInCirc,
+ InElastic = QEasingCurve::InElastic, OutElastic = QEasingCurve::OutElastic,
+ InOutElastic = QEasingCurve::InOutElastic, OutInElastic = QEasingCurve::OutInElastic,
+ InBack = QEasingCurve::InBack, OutBack = QEasingCurve::OutBack,
+ InOutBack = QEasingCurve::InOutBack, OutInBack = QEasingCurve::OutInBack,
+ InBounce = QEasingCurve::InBounce, OutBounce = QEasingCurve::OutBounce,
+ InOutBounce = QEasingCurve::InOutBounce, OutInBounce = QEasingCurve::OutInBounce,
+ InCurve = QEasingCurve::InCurve, OutCurve = QEasingCurve::OutCurve,
+ SineCurve = QEasingCurve::SineCurve, CosineCurve = QEasingCurve::CosineCurve,
+ BezierSpline = QEasingCurve::BezierSpline,
+
+ Bezier = BezierSpline // Evil! Don't use this!
+};
+Q_ENUM_NS(Type)
+};
+
+struct Q_QML_EXPORT QQmlEasingValueType
{
QEasingCurve v;
Q_GADGET
- QML_NAMED_ELEMENT(Easing)
- QML_UNCREATABLE("Use the Type enum.")
+ QML_ANONYMOUS
+ QML_FOREIGN(QEasingCurve)
+ QML_EXTENDED(QQmlEasingValueType)
+ QML_STRUCTURED_VALUE
- Q_PROPERTY(QQmlEasingValueType::Type type READ type WRITE setType FINAL)
+ Q_PROPERTY(QQmlEasingEnums::Type type READ type WRITE setType FINAL)
Q_PROPERTY(qreal amplitude READ amplitude WRITE setAmplitude FINAL)
Q_PROPERTY(qreal overshoot READ overshoot WRITE setOvershoot FINAL)
Q_PROPERTY(qreal period READ period WRITE setPeriod FINAL)
Q_PROPERTY(QVariantList bezierCurve READ bezierCurve WRITE setBezierCurve FINAL)
+
public:
- enum Type {
- Linear = QEasingCurve::Linear,
- InQuad = QEasingCurve::InQuad, OutQuad = QEasingCurve::OutQuad,
- InOutQuad = QEasingCurve::InOutQuad, OutInQuad = QEasingCurve::OutInQuad,
- InCubic = QEasingCurve::InCubic, OutCubic = QEasingCurve::OutCubic,
- InOutCubic = QEasingCurve::InOutCubic, OutInCubic = QEasingCurve::OutInCubic,
- InQuart = QEasingCurve::InQuart, OutQuart = QEasingCurve::OutQuart,
- InOutQuart = QEasingCurve::InOutQuart, OutInQuart = QEasingCurve::OutInQuart,
- InQuint = QEasingCurve::InQuint, OutQuint = QEasingCurve::OutQuint,
- InOutQuint = QEasingCurve::InOutQuint, OutInQuint = QEasingCurve::OutInQuint,
- InSine = QEasingCurve::InSine, OutSine = QEasingCurve::OutSine,
- InOutSine = QEasingCurve::InOutSine, OutInSine = QEasingCurve::OutInSine,
- InExpo = QEasingCurve::InExpo, OutExpo = QEasingCurve::OutExpo,
- InOutExpo = QEasingCurve::InOutExpo, OutInExpo = QEasingCurve::OutInExpo,
- InCirc = QEasingCurve::InCirc, OutCirc = QEasingCurve::OutCirc,
- InOutCirc = QEasingCurve::InOutCirc, OutInCirc = QEasingCurve::OutInCirc,
- InElastic = QEasingCurve::InElastic, OutElastic = QEasingCurve::OutElastic,
- InOutElastic = QEasingCurve::InOutElastic, OutInElastic = QEasingCurve::OutInElastic,
- InBack = QEasingCurve::InBack, OutBack = QEasingCurve::OutBack,
- InOutBack = QEasingCurve::InOutBack, OutInBack = QEasingCurve::OutInBack,
- InBounce = QEasingCurve::InBounce, OutBounce = QEasingCurve::OutBounce,
- InOutBounce = QEasingCurve::InOutBounce, OutInBounce = QEasingCurve::OutInBounce,
- InCurve = QEasingCurve::InCurve, OutCurve = QEasingCurve::OutCurve,
- SineCurve = QEasingCurve::SineCurve, CosineCurve = QEasingCurve::CosineCurve,
- Bezier = QEasingCurve::BezierSpline
- };
- Q_ENUM(Type)
-
- Type type() const;
+ QQmlEasingEnums::Type type() const;
qreal amplitude() const;
qreal overshoot() const;
qreal period() const;
- void setType(Type);
+ void setType(QQmlEasingEnums::Type);
void setAmplitude(qreal);
void setOvershoot(qreal);
void setPeriod(qreal);
void setBezierCurve(const QVariantList &);
QVariantList bezierCurve() const;
+
+ operator QEasingCurve() const { return v; }
};
#endif
-template<typename T>
-int qmlRegisterValueTypeEnums(const char *uri, int versionMajor, int versionMinor, const char *qmlName)
+struct QQmlV4ExecutionEnginePtrForeign
{
- QByteArray name(T::staticMetaObject.className());
-
- QByteArray pointerName(name + '*');
-
- QQmlPrivate::RegisterType type = {
- 0,
-
- qRegisterNormalizedMetaType<T *>(pointerName.constData()), 0, 0, nullptr,
-
- QString(),
-
- uri, versionMajor, versionMinor, qmlName, &T::staticMetaObject,
-
- nullptr, nullptr,
-
- 0, 0, 0,
-
- nullptr, nullptr,
-
- nullptr,
- 0
- };
-
- return QQmlPrivate::qmlregister(QQmlPrivate::TypeRegistration, &type);
-}
+ Q_GADGET
+ QML_ANONYMOUS
+ 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 f23921497c..a85601e5b9 100644
--- a/src/qml/qml/qqmlvaluetypewrapper.cpp
+++ b/src/qml/qml/qqmlvaluetypewrapper.cpp
@@ -1,177 +1,129 @@
-/****************************************************************************
-**
-** 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"
-#include <private/qqmlvaluetype_p.h>
#include <private/qqmlbinding_p.h>
-#include <private/qqmlglobal_p.h>
#include <private/qqmlbuiltinfunctions_p.h>
+#include <private/qqmlvaluetype_p.h>
+#include <private/qv4alloca_p.h>
+#include <private/qv4arraybuffer_p.h>
+#include <private/qv4dateobject_p.h>
#include <private/qv4engine_p.h>
#include <private/qv4functionobject_p.h>
-#include <private/qv4variantobject_p.h>
-#include <private/qv4alloca_p.h>
-#include <private/qv4stackframe_p.h>
-#include <private/qv4objectiterator_p.h>
-#include <private/qv4qobjectwrapper_p.h>
#include <private/qv4identifiertable_p.h>
+#include <private/qv4jsonobject_p.h>
#include <private/qv4lookup_p.h>
+#include <private/qv4qobjectwrapper_p.h>
+#include <private/qv4stackframe_p.h>
+#include <private/qv4variantobject_p.h>
+
+#include <QtCore/qline.h>
+#include <QtCore/qsize.h>
+#include <QtCore/qdatetime.h>
#include <QtCore/qloggingcategory.h>
+#if QT_CONFIG(regularexpression)
+#include <private/qv4regexpobject_p.h>
+#endif
+
QT_BEGIN_NAMESPACE
-Q_DECLARE_LOGGING_CATEGORY(lcBindingRemoval)
+Q_DECLARE_LOGGING_CATEGORY(lcBuiltinsBindingRemoval)
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();
- }
- QQmlQPointer<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);
}
- if (m_propertyCache)
- m_propertyCache->release();
- 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.id(), 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);
-
- int variantReferenceType = variantReferenceValue.userType();
- if (variantReferenceType != typeId()) {
- // 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 (QQmlValueTypeFactory::isValueType(variantReferenceType)) {
- QQmlPropertyCache *cache = nullptr;
- if (const QMetaObject *mo = QQmlValueTypeFactory::metaObjectForMetaType(variantReferenceType))
- cache = QJSEnginePrivate::get(engine())->cache(mo);
- if (d()->gadgetPtr()) {
- d()->valueType()->metaType.destruct(d()->gadgetPtr());
- ::operator delete(d()->gadgetPtr());
- }
- d()->setGadgetPtr(nullptr);
- d()->setPropertyCache(cache);
- d()->setValueType(QQmlValueTypeFactory::valueType(variantReferenceType));
- if (!cache)
- 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,49 +135,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, int typeId)
+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()->setPropertyCache(QJSEnginePrivate::get(engine)->cache(metaObject));
- r->d()->setValueType(QQmlValueTypeFactory::valueType(typeId));
- r->d()->setGadgetPtr(nullptr);
+ if (!type.isValid()) {
+ return engine->throwTypeError(QLatin1String("Type %1 is not a value type")
+ .arg(QString::fromUtf8(type.name())));
+ }
+
+ // 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, int typeId)
+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()->setPropertyCache(QJSEnginePrivate::get(engine)->cache(metaObject));
- r->d()->setValueType(QQmlValueTypeFactory::valueType(typeId));
- r->d()->setGadgetPtr(nullptr);
- r->d()->setValue(value);
+ if (!type.isValid()) {
+ return engine->throwTypeError(QLatin1String("Type %1 is not a value type")
+ .arg(QString::fromUtf8(type.name())));
+ }
+
+ 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::destruct(typeId, data);
- QMetaType::construct(typeId, data, d()->gadgetPtr());
+ if (d()->isReference() && !readReferenceValue())
+ return false;
+ const QMetaType type = d()->metaType();
+ type.destruct(data);
+ type.construct(data, d()->gadgetPtr());
return true;
}
@@ -243,14 +249,191 @@ 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)
+{
+ if (isFunction) {
+ // calling a Q_INVOKABLE function of a value type
+ return QV4::QObjectMethod::create(engine, 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) \
+ case metatype: { \
+ cpptype v; \
+ void *args[] = { &v, nullptr }; \
+ doStaticReadCall(metaObject, valueTypeWrapper, index, args); \
+ return QV4::Encode(constructor(v)); \
+ }
+
+ 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::QString, QString, engine->newString);
+ 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);
+ }
+ 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
+}
+
PropertyAttributes QQmlValueTypeWrapper::virtualGetOwnProperty(const Managed *m, PropertyKey id, Property *p)
{
if (id.isString()) {
- Scope scope(m);
- ScopedString n(scope, id.asStringOrSymbol());
const QQmlValueTypeWrapper *r = static_cast<const QQmlValueTypeWrapper *>(m);
- QQmlPropertyData *result = r->d()->propertyCache()->property(n.getPointer(), nullptr, nullptr);
- return result ? 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);
@@ -267,24 +450,25 @@ 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()->propertyCache()) {
- const QMetaObject *mo = that->d()->propertyCache()->createMetaObject();
- const int propertyCount = mo->propertyCount();
- if (propertyIndex < propertyCount) {
- Scope scope(that->engine());
- ScopedString propName(scope, that->engine()->newString(QString::fromUtf8(mo->property(propertyIndex).name())));
- ++propertyIndex;
- if (attrs)
- *attrs = QV4::Attr_Data;
- if (pd)
- pd->value = that->QV4::Object::get(propName);
- return propName->toPropertyKey();
+ 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
+ const int propertyCount = mo->propertyCount();
+ if (propertyIndex < propertyCount) {
+ Scope scope(that->engine());
+ QMetaProperty p = mo->property(propertyIndex); // TODO: Implement and use QBasicMetaProperty
+ ScopedString propName(scope, that->engine()->newString(QString::fromUtf8(p.name())));
+ ++propertyIndex;
+ if (attrs)
+ *attrs = QV4::Attr_Data;
+ if (pd) {
+ QQmlPropertyData data;
+ data.load(p);
+ pd->value = getGadgetProperty(that->engine(), that->d(), data.propType(), data.coreIndex(), data.isFunction(), data.isEnum());
}
+ return propName->toPropertyKey();
}
return ObjectOwnPropertyKeyIterator::next(o, pd, attrs);
@@ -299,29 +483,75 @@ OwnPropertyKeyIterator *QQmlValueTypeWrapper::virtualOwnPropertyKeys(const Objec
bool QQmlValueTypeWrapper::isEqual(const QVariant& value) const
{
- if (const QQmlValueTypeReference *ref = as<const QQmlValueTypeReference>())
- if (!ref->readReferenceValue())
- return false;
- return (value == d()->toVariant());
+ if (d()->isReference() && !readReferenceValue())
+ return false;
+ int id1 = value.metaType().id();
+ QVariant v = d()->toVariant();
+ int id2 = v.metaType().id();
+ if (id1 != id2) {
+ // conversions for weak comparison
+ switch (id1) {
+ case QMetaType::QPoint:
+ if (id2 == QMetaType::QPointF)
+ return value.value<QPointF>() == v.value<QPointF>();
+ break;
+ case QMetaType::QPointF:
+ if (id2 == QMetaType::QPoint)
+ return value.value<QPointF>() == v.value<QPointF>();
+ break;
+ case QMetaType::QRect:
+ if (id2 == QMetaType::QRectF)
+ return value.value<QRectF>() == v.value<QRectF>();
+ break;
+ case QMetaType::QRectF:
+ if (id2 == QMetaType::QRect)
+ return value.value<QRectF>() == v.value<QRectF>();
+ break;
+ case QMetaType::QLine:
+ if (id2 == QMetaType::QLineF)
+ return value.value<QLineF>() == v.value<QLineF>();
+ break;
+ case QMetaType::QLineF:
+ if (id2 == QMetaType::QLine)
+ return value.value<QLineF>() == v.value<QLineF>();
+ break;
+ case QMetaType::QSize:
+ if (id2 == QMetaType::QSizeF)
+ return value.value<QSizeF>() == v.value<QSizeF>();
+ break;
+ case QMetaType::QSizeF:
+ if (id2 == QMetaType::QSize)
+ return value.value<QSizeF>() == v.value<QSizeF>();
+ break;
+ default:
+ break;
+ }
+ }
+ return (value == v);
}
int QQmlValueTypeWrapper::typeId() const
{
- return d()->valueType()->metaType.id();
+ return d()->metaType().id();
+}
+
+QMetaType QQmlValueTypeWrapper::type() const
+{
+ 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;
}
@@ -331,12 +561,30 @@ 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;
}
+QQmlPropertyData QQmlValueTypeWrapper::dataForPropertyKey(PropertyKey id) const
+{
+ if (!id.isStringOrSymbol())
+ return QQmlPropertyData {};
+ QByteArray name = id.asStringOrSymbol()->toQString().toUtf8();
+ const QMetaObject *mo = d()->metaObject();
+ QQmlPropertyData result;
+ QMetaMethod metaMethod = QMetaObjectPrivate::firstMethod(mo, name);
+ if (metaMethod.isValid()) {
+ result.load(metaMethod);
+ } else {
+ int propertyIndex = d()->metaObject()->indexOfProperty(name.constData());
+ if (propertyIndex >= 0)
+ result.load(mo->property(propertyIndex));
+ }
+ return result;
+}
+
ReturnedValue QQmlValueTypeWrapper::method_toString(const FunctionObject *b, const Value *thisObject, const Value *, int)
{
const Object *o = thisObject->as<Object>();
@@ -346,20 +594,14 @@ 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;
- // Prepare a buffer to pass to QMetaType::convert()
- QString convertResult;
- convertResult.~QString();
- if (QMetaType::convert(w->d()->gadgetPtr(), w->d()->valueType()->metaType.id(), &convertResult, QMetaType::QString)) {
- result = convertResult;
- } else {
- result += QString::fromUtf8(QMetaType::typeName(w->d()->valueType()->metaType.id()))
- + QLatin1Char('(');
- const QMetaObject *mo = w->d()->propertyCache()->metaObject();
+ if (!QMetaType::convert(w->d()->metaType(), w->d()->gadgetPtr(),
+ QMetaType(QMetaType::QString), &result)) {
+ 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) {
if (mo->property(i).isDesignable()) {
@@ -374,50 +616,6 @@ ReturnedValue QQmlValueTypeWrapper::method_toString(const FunctionObject *b, con
return Encode(b->engine()->newString(result));
}
-Q_ALWAYS_INLINE static ReturnedValue getGadgetProperty(ExecutionEngine *engine,
- Heap::QQmlValueTypeWrapper *valueTypeWrapper,
- QQmlPropertyData *property)
-{
- if (property->isFunction()) {
- // calling a Q_INVOKABLE function of a value type
- return QV4::QObjectMethod::create(engine->rootContext(), valueTypeWrapper, property->coreIndex());
- }
-
-#define VALUE_TYPE_LOAD(metatype, cpptype, constructor) \
- if (property->propType() == metatype) { \
- cpptype v; \
- void *args[] = { &v, nullptr }; \
- metaObject->d.static_metacall(reinterpret_cast<QObject*>(valueTypeWrapper->gadgetPtr()), \
- QMetaObject::ReadProperty, index, args); \
- return QV4::Encode(constructor(v)); \
- }
-
- const QMetaObject *metaObject = valueTypeWrapper->propertyCache()->metaObject();
-
- int index = property->coreIndex();
- QQmlMetaObject::resolveGadgetMethodOrPropertyIndex(QMetaObject::ReadProperty, &metaObject, &index);
-
- // These four types are the most common used by the value type wrappers
- VALUE_TYPE_LOAD(QMetaType::QReal, qreal, qreal);
- VALUE_TYPE_LOAD(QMetaType::Int || property->isEnum(), int, int);
- VALUE_TYPE_LOAD(QMetaType::Int, int, int);
- VALUE_TYPE_LOAD(QMetaType::QString, QString, engine->newString);
- VALUE_TYPE_LOAD(QMetaType::Bool, bool, bool);
-
- QVariant v;
- void *args[] = { nullptr, nullptr };
- if (property->propType() == QMetaType::QVariant) {
- args[0] = &v;
- } else {
- v = QVariant(property->propType(), static_cast<void *>(nullptr));
- args[0] = v.data();
- }
- metaObject->d.static_metacall(reinterpret_cast<QObject*>(valueTypeWrapper->gadgetPtr()), QMetaObject::ReadProperty,
- index, args);
- return engine->fromVariant(v);
-#undef VALUE_TYPE_LOAD
-}
-
ReturnedValue QQmlValueTypeWrapper::virtualResolveLookupGetter(const Object *object, ExecutionEngine *engine,
Lookup *lookup)
{
@@ -432,19 +630,20 @@ 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->d()->propertyCache()->property(name.getPointer(), nullptr, nullptr);
- if (!result)
+ QQmlPropertyData result = r->dataForPropertyKey(id);
+ if (!result.isValid())
return QV4::Object::virtualResolveLookupGetter(object, engine, lookup);
- lookup->qgadgetLookup.ic = r->internalClass();
- lookup->qgadgetLookup.propertyCache = r->d()->propertyCache();
- lookup->qgadgetLookup.propertyCache->addref();
- lookup->qgadgetLookup.propertyData = result;
+ 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();
+ lookup->qgadgetLookup.coreIndex = result.coreIndex();
+ lookup->qgadgetLookup.isFunction = result.isFunction();
+ lookup->qgadgetLookup.isEnum = result.isEnum();
lookup->getter = QQmlValueTypeWrapper::lookupGetter;
return lookup->getter(lookup, engine, *object);
}
@@ -452,8 +651,7 @@ ReturnedValue QQmlValueTypeWrapper::virtualResolveLookupGetter(const Object *obj
ReturnedValue QQmlValueTypeWrapper::lookupGetter(Lookup *lookup, ExecutionEngine *engine, const Value &object)
{
const auto revertLookup = [lookup, engine, &object]() {
- lookup->qgadgetLookup.propertyCache->release();
- lookup->qgadgetLookup.propertyCache = nullptr;
+ lookup->qgadgetLookup.metaObject = quintptr(0);
lookup->getter = Lookup::getterGeneric;
return Lookup::getterGeneric(lookup, engine, object);
};
@@ -466,17 +664,22 @@ ReturnedValue QQmlValueTypeWrapper::lookupGetter(Lookup *lookup, ExecutionEngine
Heap::QQmlValueTypeWrapper *valueTypeWrapper =
const_cast<Heap::QQmlValueTypeWrapper*>(static_cast<const Heap::QQmlValueTypeWrapper *>(o));
- if (valueTypeWrapper->propertyCache() != lookup->qgadgetLookup.propertyCache)
+ 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();
- QQmlPropertyData *property = lookup->qgadgetLookup.propertyData;
- return getGadgetProperty(engine, valueTypeWrapper, property);
+ 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,
@@ -494,23 +697,19 @@ ReturnedValue QQmlValueTypeWrapper::virtualGet(const Managed *m, PropertyKey id,
const QQmlValueTypeWrapper *r = static_cast<const QQmlValueTypeWrapper *>(m);
QV4::ExecutionEngine *v4 = r->engine();
- Scope scope(v4);
- 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->d()->propertyCache()->property(name.getPointer(), nullptr, nullptr);
- if (!result)
+ QQmlPropertyData result = r->dataForPropertyKey(id);
+ if (!result.isValid())
return Object::virtualGet(m, id, receiver, hasProperty);
if (hasProperty)
*hasProperty = true;
- return getGadgetProperty(v4, r->d(), result);
+ return getGadgetProperty(v4, r->d(), result.propType(), result.coreIndex(), result.isFunction(), result.isEnum());
}
bool QQmlValueTypeWrapper::virtualPut(Managed *m, PropertyKey id, const Value &value, Value *receiver)
@@ -525,30 +724,30 @@ 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());
-
- int writeBackPropertyType = -1;
-
- 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.userType();
}
- ScopedString name(scope, id.asStringOrSymbol());
-
- const QMetaObject *metaObject = r->d()->propertyCache()->metaObject();
- const QQmlPropertyData *pd = r->d()->propertyCache()->property(name.getPointer(), nullptr, nullptr);
- if (!pd)
+ const QMetaObject *metaObject = r->d()->metaObject();
+ const QQmlPropertyData pd = r->dataForPropertyKey(id);
+ if (!pd.isValid())
return false;
- if (reference) {
+ if (heapObject) {
+ QObject *referenceObject = nullptr;
QV4::ScopedFunctionObject f(scope, value);
- const QQmlQPointer<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()) {
@@ -559,7 +758,18 @@ bool QQmlValueTypeWrapper::virtualPut(Managed *m, PropertyKey id, const Value &v
return false;
}
- QQmlContextData *context = v4->callingQmlContext();
+ 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;
cacheData.setWritable(true);
@@ -568,64 +778,57 @@ bool QQmlValueTypeWrapper::virtualPut(Managed *m, PropertyKey id, const Value &v
QV4::Scoped<QQmlBindingFunction> bindingFunction(scope, (const Value &)f);
- QV4::ScopedFunctionObject f(scope, bindingFunction->bindingFunction());
+ QV4::Scoped<JavaScriptFunctionObject> f(scope, bindingFunction->bindingFunction());
QV4::ScopedContext ctx(scope, f->scope());
QQmlBinding *newBinding = QQmlBinding::create(&cacheData, f->function(), referenceObject, context, ctx);
newBinding->setSourceLocation(bindingFunction->currentLocation());
if (f->isBoundFunction())
newBinding->setBoundFunction(static_cast<QV4::BoundFunction *>(f.getPointer()));
newBinding->setSourceLocation(bindingFunction->currentLocation());
- newBinding->setTarget(referenceObject, cacheData, pd);
+ newBinding->setTarget(referenceObject, cacheData, &pd);
QQmlPropertyPrivate::setBinding(newBinding);
return true;
- } else {
- if (Q_UNLIKELY(lcBindingRemoval().isInfoEnabled())) {
- if (auto binding = QQmlPropertyPrivate::binding(referenceObject, QQmlPropertyIndex(referencePropertyIndex, pd->coreIndex()))) {
- Q_ASSERT(!binding->isValueTypeProxy());
+ } else if (referenceObject) {
+ if (Q_UNLIKELY(lcBuiltinsBindingRemoval().isInfoEnabled())) {
+ if (auto binding = QQmlPropertyPrivate::binding(referenceObject, QQmlPropertyIndex(referencePropertyIndex, pd.coreIndex()))) {
+ Q_ASSERT(binding->kind() == QQmlAbstractBinding::QmlBinding);
const auto qmlBinding = static_cast<const QQmlBinding*>(binding);
const auto stackFrame = v4->currentStackFrame;
- qCInfo(lcBindingRemoval,
+ qCInfo(lcBuiltinsBindingRemoval,
"Overwriting binding on %s::%s which was initially bound at %s by setting \"%s\" at %s:%d",
referenceObject->metaObject()->className(), referenceObject->metaObject()->property(referencePropertyIndex).name(),
qPrintable(qmlBinding->expressionIdentifier()),
- metaObject->property(pd->coreIndex()).name(),
+ metaObject->property(pd.coreIndex()).name(),
qPrintable(stackFrame->source()), stackFrame->lineNumber());
}
}
- QQmlPropertyPrivate::removeBinding(referenceObject, QQmlPropertyIndex(referencePropertyIndex, pd->coreIndex()));
+ QQmlPropertyPrivate::removeBinding(referenceObject, QQmlPropertyIndex(referencePropertyIndex, pd.coreIndex()));
}
}
- QMetaProperty property = metaObject->property(pd->coreIndex());
+ 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.type() == QMetaType::Double)
+ 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::QVariant) {
- QVariant variantReferenceValue = r->d()->toVariant();
+ property.writeOnGadget(gadget, std::move(v));
- int flags = 0;
- int status = -1;
- void *a[] = { &variantReferenceValue, nullptr, &status, &flags };
- QMetaObject::metacall(reference->d()->object, QMetaObject::WriteProperty, reference->d()->property, a);
-
- } 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 60079aa623..97709dfb4c 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,7 @@
#include <QtCore/qglobal.h>
#include <private/qtqmlglobal_p.h>
-#include <private/qv4value_p.h>
-#include <private/qv4object_p.h>
-#include <private/qqmlpropertycache_p.h>
+#include <private/qv4referenceobject_p.h>
QT_BEGIN_NAMESPACE
@@ -66,80 +28,126 @@ namespace QV4 {
namespace Heap {
-struct QQmlValueTypeWrapper : Object {
- void init() { Object::init(); }
- void destroy();
+#define QQmlValueTypeWrapperMembers(class, Member)
- QQmlPropertyCache *propertyCache() const { return m_propertyCache; }
- void setPropertyCache(QQmlPropertyCache *c) {
- if (c)
- c->addref();
- if (m_propertyCache)
- m_propertyCache->release();
- m_propertyCache = c;
- }
+DECLARE_HEAP_OBJECT(QQmlValueTypeWrapper, ReferenceObject) {
+ DECLARE_MARKOBJECTS(QQmlValueTypeWrapper);
- void setValueType(QQmlValueType *valueType)
+ void init(
+ const void *data, QMetaType metaType, const QMetaObject *metaObject,
+ Object *object, int property, Flags flags)
{
- Q_ASSERT(valueType != nullptr);
- m_valueType = valueType;
+ ReferenceObject::init(object, property, flags);
+ setMetaType(metaType);
+ setMetaObject(metaObject);
+ if (data)
+ setData(data);
}
- QQmlValueType *valueType() const
- {
- Q_ASSERT(m_valueType != nullptr);
- return m_valueType;
- }
+ QQmlValueTypeWrapper *detached() const;
- void setGadgetPtr(void *gadgetPtr) const
+ void destroy();
+
+ QMetaType metaType() const
{
- m_gadgetPtr = gadgetPtr;
+ Q_ASSERT(m_metaType != nullptr);
+ return QMetaType(m_metaType);
}
- void *gadgetPtr() 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_gadgetPtr;
+ 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;
- QQmlPropertyCache *m_propertyCache;
+ 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, int typeId);
- static ReturnedValue create(ExecutionEngine *engine, const QVariant &, const QMetaObject *metaObject, int typeId);
+ 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 018769948d..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>
@@ -76,8 +21,6 @@
QT_BEGIN_NAMESPACE
-using namespace QQmlVMETypes;
-
bool QQmlVME::s_enableComponentComplete = true;
void QQmlVME::enableComponentComplete()
@@ -109,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];
@@ -138,7 +81,7 @@ bool QQmlVMEGuard::isOK() const
return false;
for (int ii = 0; ii < m_contextCount; ++ii)
- if (m_contexts[ii].isNull() || !m_contexts[ii]->engine)
+ if (m_contexts[ii].isNull() || !m_contexts[ii]->engine())
return false;
return true;
diff --git a/src/qml/qml/qqmlvme_p.h b/src/qml/qml/qqmlvme_p.h
index 13c5524d96..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,66 +15,40 @@
// We mean it.
//
-#include "qqmlerror.h"
-#include <private/qbitfield_p.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>
#include <private/qqmlengine_p.h>
#include <private/qfinitestack_p.h>
+#include <atomic>
+
QT_BEGIN_NAMESPACE
class QObject;
-class QJSValue;
-class QQmlScriptData;
-class QQmlContextData;
-
-namespace QQmlVMETypes {
- struct List
- {
- List() : type(0) {}
- List(int t) : type(t) {}
-
- int type;
- QQmlListProperty<void> qListProperty;
- };
- struct State {
- enum Flag { Deferred = 0x00000001 };
-
- State() : flags(0), context(nullptr), instructionStream(nullptr) {}
- quint32 flags;
- QQmlContextData *context;
- const char *instructionStream;
- QBitField bindingSkipList;
- };
-}
-Q_DECLARE_TYPEINFO(QQmlVMETypes::List, Q_PRIMITIVE_TYPE | Q_MOVABLE_TYPE);
-template<>
-class QTypeInfo<QQmlVMETypes::State> : public QTypeInfoMerger<QQmlVMETypes::State, QBitField> {}; //Q_DECLARE_TYPEINFO
class QQmlInstantiationInterrupt {
public:
inline QQmlInstantiationInterrupt();
- inline QQmlInstantiationInterrupt(volatile bool *runWhile, int nsecs=0);
- inline QQmlInstantiationInterrupt(int 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;
- int nsecs;
- volatile bool *runWhile;
+ QDeadlineTimer deadline;
+ std::atomic<bool> *runWhile = nullptr;
};
-class Q_QML_PRIVATE_EXPORT QQmlVME
+class Q_QML_EXPORT QQmlVME
{
public:
static void enableComponentComplete();
@@ -141,43 +79,37 @@ public:
private:
int m_objectCount;
- QPointer<QObject> *m_objects;
+ QQmlGuard<QObject> *m_objects;
int m_contextCount;
QQmlGuardedContextData *m_contexts;
};
QQmlInstantiationInterrupt::QQmlInstantiationInterrupt()
- : mode(None), nsecs(0), runWhile(nullptr)
-{
-}
-
-QQmlInstantiationInterrupt::QQmlInstantiationInterrupt(volatile bool *runWhile, int nsecs)
- : mode(Flag), nsecs(nsecs), runWhile(runWhile)
+ : mode(None)
{
}
-QQmlInstantiationInterrupt::QQmlInstantiationInterrupt(int nsecs)
- : mode(Time), nsecs(nsecs), runWhile(nullptr)
+QQmlInstantiationInterrupt::QQmlInstantiationInterrupt(std::atomic<bool> *runWhile, QDeadlineTimer deadline)
+ : mode(Flag), deadline(deadline), runWhile(runWhile)
{
}
-void QQmlInstantiationInterrupt::reset()
+QQmlInstantiationInterrupt::QQmlInstantiationInterrupt(QDeadlineTimer deadline)
+ : mode(Time), deadline(deadline)
{
- if (mode == Time || nsecs)
- timer.start();
}
bool QQmlInstantiationInterrupt::shouldInterrupt() const
{
- if (mode == None) {
- return false;
- } else if (mode == Time) {
- return timer.nsecsElapsed() > nsecs;
- } else if (mode == Flag) {
- return !*runWhile || (nsecs && timer.nsecsElapsed() > nsecs);
- } else {
+ switch (mode) {
+ case None:
return false;
+ case Time:
+ return deadline.hasExpired();
+ case Flag:
+ return !runWhile->load(std::memory_order_acquire) || deadline.hasExpired();
}
+ Q_UNREACHABLE_RETURN(false);
}
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlvmemetaobject.cpp b/src/qml/qml/qqmlvmemetaobject.cpp
index 9b5490b6e5..dffddd2e0d 100644
--- a/src/qml/qml/qqmlvmemetaobject.cpp
+++ b/src/qml/qml/qqmlvmemetaobject.cpp
@@ -1,53 +1,12 @@
-/****************************************************************************
-**
-** 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>
#include <private/qqmlglobal_p.h>
@@ -57,63 +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
-static void list_append(QQmlListProperty<QObject> *prop, QObject *o)
+QQmlVMEResolvedList::QQmlVMEResolvedList(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 = 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;
+ }
+
+ 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);
+ }
+}
+
+void QQmlVMEResolvedList::append(QObject *o) const
{
- QList<QObject *> *list = static_cast<QList<QObject *> *>(prop->data);
- list->append(o);
- static_cast<QQmlVMEMetaObject *>(prop->dummy1)->activate(prop->object, reinterpret_cast<quintptr>(prop->dummy2), nullptr);
+ 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;
+ }
+
+ 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));
}
-static int list_count(QQmlListProperty<QObject> *prop)
+QObject *QQmlVMEResolvedList::at(qsizetype i) const
{
- QList<QObject *> *list = static_cast<QList<QObject *> *>(prop->data);
- return list->count();
+ QV4::Scope scope(m_list->internalClass->engine);
+ QV4::Scoped<QV4::QObjectWrapper> result(scope, m_list->arrayData->get(i));
+ return result ? result->object() : nullptr;
}
-static QObject *list_at(QQmlListProperty<QObject> *prop, int index)
+void QQmlVMEResolvedList::replace(qsizetype i, QObject *o) const
{
- QList<QObject *> *list = static_cast<QList<QObject *> *>(prop->data);
- return list->at(index);
+ 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));
}
-static void list_clear(QQmlListProperty<QObject> *prop)
+QQmlVMEResolvedList::~QQmlVMEResolvedList() = default;
+
+void QQmlVMEResolvedList::activateSignal() const
{
- QList<QObject *> *list = static_cast<QList<QObject *> *>(prop->data);
- list->clear();
- static_cast<QQmlVMEMetaObject *>(prop->dummy1)->activate(prop->object, reinterpret_cast<quintptr>(prop->dummy2), nullptr);
+ m_metaObject->activate(m_metaObject->object, int(m_id + m_metaObject->methodOffset()), nullptr);
}
-QQmlVMEVariantQObjectPtr::QQmlVMEVariantQObjectPtr()
- : QQmlGuard<QObject>(nullptr), m_target(nullptr), m_index(-1)
+void QQmlVMEMetaObject::list_append(QQmlListProperty<QObject> *prop, QObject *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 QQmlVMEResolvedList(prop).size();
+}
+
+static QObject *list_at(QQmlListProperty<QObject> *prop, qsizetype index)
{
+ return QQmlVMEResolvedList(prop).at(index);
}
-QQmlVMEVariantQObjectPtr::~QQmlVMEVariantQObjectPtr()
+void QQmlVMEMetaObject::list_clear(QQmlListProperty<QObject> *prop)
{
+ const QQmlVMEResolvedList resolved(prop);
+ resolved.clear();
+ resolved.activateSignal();
}
-void QQmlVMEVariantQObjectPtr::objectDestroyed(QObject *)
+void QQmlVMEMetaObject::list_clear_nosignal(QQmlListProperty<QObject> *prop)
{
- if (!m_target || QQmlData::wasDeleted(m_target->object))
+ QQmlVMEResolvedList(prop).clear();
+}
+
+static void list_replace(QQmlListProperty<QObject> *prop, qsizetype index, QObject *o)
+{
+ const QQmlVMEResolvedList resolved(prop);
+ resolved.replace(index, o);
+ resolved.activateSignal();
+}
+
+static void list_removeLast(QQmlListProperty<QObject> *prop)
+{
+ const QQmlVMEResolvedList resolved(prop);
+ resolved.removeLast();
+ resolved.activateSignal();
+}
+
+QQmlVMEVariantQObjectPtr::QQmlVMEVariantQObjectPtr()
+ : QQmlGuard<QObject>(QQmlVMEVariantQObjectPtr::objectDestroyedImpl, nullptr), m_target(nullptr), m_index(-1)
+{
+}
+
+void QQmlVMEVariantQObjectPtr::objectDestroyedImpl(QQmlGuardImpl *guard)
+{
+ 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);
}
}
@@ -130,7 +188,12 @@ public:
QQmlVMEMetaObjectEndpoint();
void tryConnect();
- QFlagPointer<QQmlVMEMetaObject> metaObject;
+ enum Tag {
+ NoTag,
+ EndPointIsConnected
+ };
+
+ QTaggedPointer<QQmlVMEMetaObject, Tag> metaObject;
};
QQmlVMEMetaObjectEndpoint::QQmlVMEMetaObjectEndpoint()
@@ -149,29 +212,26 @@ void QQmlVMEMetaObjectEndpoint::tryConnect()
Q_ASSERT(metaObject->compiledObject);
int aliasId = this - metaObject->aliasEndpoints;
- if (metaObject.flag()) {
+ if (metaObject.tag() == EndPointIsConnected) {
// This is actually notify
int sigIdx = metaObject->methodOffset() + aliasId + metaObject->compiledObject->nProperties;
metaObject->activate(metaObject->object, sigIdx, nullptr);
} else {
const QV4::CompiledData::Alias *aliasData = &metaObject->compiledObject->aliasTable()[aliasId];
if (!aliasData->isObjectAlias()) {
- QQmlContextData *ctxt = metaObject->ctxt;
- QObject *target = ctxt->idValues[aliasData->targetObjectId].data();
+ QQmlRefPointer<QQmlContextData> ctxt = metaObject->ctxt;
+ 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);
- if (pd && valueTypeIndex != -1 && !QQmlValueTypeFactory::valueType(pd->propType())) {
+ 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());
+ const QQmlPropertyCache::ConstPtr newPropertyCache
+ = QQmlMetaType::propertyCacheForType(pd->propType());
void *argv[1] = { &target };
QMetaObject::metacall(target, QMetaObject::ReadProperty, coreIndex, argv);
Q_ASSERT(newPropertyCache);
@@ -180,20 +240,18 @@ void QQmlVMEMetaObjectEndpoint::tryConnect()
if (!pd)
return;
- if (pd->notifyIndex() != -1)
- connect(target, pd->notifyIndex(), ctxt->engine);
+ if (pd->notifyIndex() != -1 && ctxt->engine())
+ connect(target, pd->notifyIndex(), ctxt->engine());
}
- metaObject.setFlag();
+ metaObject.setTag(EndPointIsConnected);
}
}
-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);
@@ -216,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;
@@ -231,21 +298,31 @@ 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)
-{
- 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();
- int type = QQmlData::get(object)->propertyCache->property(id)->propType();
-
- if (type != QVariant::Invalid) {
- if (valueIndex != -1) {
- QQmlValueType *valueType = QQmlValueTypeFactory::valueType(type);
+bool QQmlInterceptorMetaObject::doIntercept(QMetaObject::Call c, int id, void **a)
+{
+ 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);
//
@@ -279,57 +356,65 @@ bool QQmlInterceptorMetaObject::intercept(QMetaObject::Call c, int id, void **a)
// (7) Issue the interceptor call with the new component value.
//
- QMetaProperty valueProp = valueType->metaObject()->property(valueIndex);
- QVariant newValue(type, a[0]);
+ QMetaProperty valueProp = valueType->property(valueIndex);
+ 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);
+ QVariant newComponentValue = valueType->readOnGadget(valueProp);
- // 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);
-
- 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(type, 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),
@@ -345,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());
}
@@ -401,57 +492,20 @@ void QQmlVMEMetaObject::writeProperty(int id, double v)
void QQmlVMEMetaObject::writeProperty(int id, const QString& v)
{
QV4::MemberData *md = propertyAndMethodStorageAsMemberData();
- if (md)
- md->set(engine, id, engine->newString(v));
-}
-
-void QQmlVMEMetaObject::writeProperty(int id, const QUrl& v)
-{
- QV4::MemberData *md = propertyAndMethodStorageAsMemberData();
- if (md)
- md->set(engine, id, engine->newVariantObject(QVariant::fromValue(v)));
-}
-
-void QQmlVMEMetaObject::writeProperty(int id, const QDate& v)
-{
- QV4::MemberData *md = propertyAndMethodStorageAsMemberData();
- if (md)
- md->set(engine, id, engine->newVariantObject(QVariant::fromValue(v)));
-}
-
-void QQmlVMEMetaObject::writeProperty(int id, const QDateTime& v)
-{
- QV4::MemberData *md = propertyAndMethodStorageAsMemberData();
- if (md)
- md->set(engine, id, engine->newVariantObject(QVariant::fromValue(v)));
-}
-
-void QQmlVMEMetaObject::writeProperty(int id, const QPointF& v)
-{
- QV4::MemberData *md = propertyAndMethodStorageAsMemberData();
- if (md)
- md->set(engine, id, engine->newVariantObject(QVariant::fromValue(v)));
-}
-
-void QQmlVMEMetaObject::writeProperty(int id, const QSizeF& v)
-{
- QV4::MemberData *md = propertyAndMethodStorageAsMemberData();
- if (md)
- md->set(engine, id, engine->newVariantObject(QVariant::fromValue(v)));
-}
-
-void QQmlVMEMetaObject::writeProperty(int id, const QRectF& v)
-{
- QV4::MemberData *md = propertyAndMethodStorageAsMemberData();
- if (md)
- md->set(engine, id, engine->newVariantObject(QVariant::fromValue(v)));
+ if (md) {
+ QV4::Scope scope(engine);
+ QV4::Scoped<QV4::MemberData>(scope, md)->set(engine, id, engine->newString(v));
+ }
}
void QQmlVMEMetaObject::writeProperty(int id, QObject* v)
{
QV4::MemberData *md = propertyAndMethodStorageAsMemberData();
- if (md)
- md->set(engine, id, QV4::Value::fromReturnedValue(QV4::QObjectWrapper::wrap(engine, v)));
+ if (md) {
+ QV4::Scope scope(engine);
+ QV4::Scoped<QV4::MemberData>(scope, md)->set(engine, id, QV4::Value::fromReturnedValue(
+ QV4::QObjectWrapper::wrap(engine, v)));
+ }
QQmlVMEVariantQObjectPtr *guard = getQObjectGuardForProperty(id);
if (v && !guard) {
@@ -523,7 +577,7 @@ QUrl QQmlVMEMetaObject::readPropertyAsUrl(int id) const
QV4::Scope scope(engine);
QV4::ScopedValue sv(scope, *(md->data() + id));
const QV4::VariantObject *v = sv->as<QV4::VariantObject>();
- if (!v || v->d()->data().type() != QVariant::Url)
+ if (!v || v->d()->data().userType() != QMetaType::QUrl)
return QUrl();
return v->d()->data().value<QUrl>();
}
@@ -537,12 +591,26 @@ QDate QQmlVMEMetaObject::readPropertyAsDate(int id) const
QV4::Scope scope(engine);
QV4::ScopedValue sv(scope, *(md->data() + id));
const QV4::VariantObject *v = sv->as<QV4::VariantObject>();
- if (!v || v->d()->data().type() != QVariant::Date)
+ if (!v || v->d()->data().userType() != QMetaType::QDate)
return QDate();
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)
@@ -551,11 +619,27 @@ QDateTime QQmlVMEMetaObject::readPropertyAsDateTime(int id)
QV4::Scope scope(engine);
QV4::ScopedValue sv(scope, *(md->data() + id));
const QV4::VariantObject *v = sv->as<QV4::VariantObject>();
- if (!v || v->d()->data().type() != QVariant::DateTime)
+ if (!v || v->d()->data().userType() != QMetaType::QDateTime)
return QDateTime();
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();
@@ -565,7 +649,7 @@ QSizeF QQmlVMEMetaObject::readPropertyAsSizeF(int id) const
QV4::Scope scope(engine);
QV4::ScopedValue sv(scope, *(md->data() + id));
const QV4::VariantObject *v = sv->as<QV4::VariantObject>();
- if (!v || v->d()->data().type() != QVariant::SizeF)
+ if (!v || v->d()->data().userType() != QMetaType::QSizeF)
return QSizeF();
return v->d()->data().value<QSizeF>();
}
@@ -579,7 +663,7 @@ QPointF QQmlVMEMetaObject::readPropertyAsPointF(int id) const
QV4::Scope scope(engine);
QV4::ScopedValue sv(scope, *(md->data() + id));
const QV4::VariantObject *v = sv->as<QV4::VariantObject>();
- if (!v || v->d()->data().type() != QVariant::PointF)
+ if (!v || v->d()->data().userType() != QMetaType::QPointF)
return QPointF();
return v->d()->data().value<QPointF>();
}
@@ -598,20 +682,19 @@ QObject* QQmlVMEMetaObject::readPropertyAsQObject(int id) const
return wrapper->object();
}
-QList<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<QList<QObject *> >()) {
- QVariant variant(QVariant::fromValue(QList<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<QList<QObject *> *>(v->d()->data().data());
}
QRectF QQmlVMEMetaObject::readPropertyAsRectF(int id) const
@@ -623,14 +706,11 @@ QRectF QQmlVMEMetaObject::readPropertyAsRectF(int id) const
QV4::Scope scope(engine);
QV4::ScopedValue sv(scope, *(md->data() + id));
const QV4::VariantObject *v = sv->as<QV4::VariantObject>();
- if (!v || v->d()->data().type() != QVariant::RectF)
+ if (!v || v->d()->data().userType() != QMetaType::QRectF)
return QRectF();
return v->d()->data().value<QRectF>();
}
-#if defined(Q_OS_WINRT) && defined(_M_ARM)
-#pragma optimize("", off)
-#endif
int QQmlVMEMetaObject::metaCall(QObject *o, QMetaObject::Call c, int _id, void **a)
{
Q_ASSERT(o == object);
@@ -646,171 +726,301 @@ int QQmlVMEMetaObject::metaCall(QObject *o, QMetaObject::Call c, int _id, void *
const int signalCount = compiledObject ? int(compiledObject->nSignals) : 0;
const int methodCount = compiledObject ? int(compiledObject->nFunctions) : 0;
- if (c == QMetaObject::ReadProperty || c == QMetaObject::WriteProperty || c == QMetaObject::ResetProperty) {
+ if (c == QMetaObject::ReadProperty || c == QMetaObject::WriteProperty || c == QMetaObject::ResetProperty || c == QMetaObject::BindableProperty) {
if (id >= propOffset()) {
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 == nullptr || ctxt->engine == nullptr) ? nullptr : QQmlEnginePrivate::get(ctxt->engine);
-
- const int fallbackMetaType = QQmlPropertyCacheCreatorBase::metaTypeForPropertyType(t);
+ QQmlEnginePrivate *ep = (ctxt.isNull() || ctxt->engine() == nullptr)
+ ? nullptr
+ : QQmlEnginePrivate::get(ctxt->engine());
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::Variant:
- *reinterpret_cast<QVariant *>(a[0]) = readPropertyAsVariant(id);
- break;
- case QV4::CompiledData::BuiltinType::Font:
- case QV4::CompiledData::BuiltinType::Time:
- case QV4::CompiledData::BuiltinType::Color:
- case QV4::CompiledData::BuiltinType::Vector2D:
- case QV4::CompiledData::BuiltinType::Vector3D:
- case QV4::CompiledData::BuiltinType::Vector4D:
- case QV4::CompiledData::BuiltinType::Matrix4x4:
- case QV4::CompiledData::BuiltinType::Quaternion:
- Q_ASSERT(fallbackMetaType != QMetaType::UnknownType);
- if (QV4::MemberData *md = propertyAndMethodStorageAsMemberData()) {
- QVariant propertyAsVariant;
- if (const QV4::VariantObject *v = (md->data() + id)->as<QV4::VariantObject>())
- propertyAsVariant = v->d()->data();
- QQml_valueTypeProvider()->readValueType(propertyAsVariant, a[0], fallbackMetaType);
- }
- break;
- case QV4::CompiledData::BuiltinType::Var:
- if (ep) {
- *reinterpret_cast<QVariant *>(a[0]) = readPropertyAsVariant(id);
+ 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
+ // 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 = static_cast<QQmlVMEMetaObject *>(
+ QObjectPrivate::get(object)->metaObject);
+ quintptr inheritanceDepth = 0u;
+ while (mo && mo != this) {
+ mo = mo->parentVMEMetaObject();
+ ++inheritanceDepth;
+ }
+ 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) << idBits))) {
+ qmlWarning(object) << "Too many properties in object "
+ "for list property";
+ return -1;
+ }
+ quintptr encodedIndex = (inheritanceDepth << idBits) + id;
+
+ 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 {
- // if the context was disposed, we just return an invalid variant from read.
- *reinterpret_cast<QVariant *>(a[0]) = QVariant();
+ qmlWarning(object) << "Cannot find member data";
}
- break;
- case QV4::CompiledData::BuiltinType::InvalidBuiltin:
- if (property.isList) {
- QList<QObject *> *list = readPropertyAsList(id);
- QQmlListProperty<QObject> *p = static_cast<QQmlListProperty<QObject> *>(a[0]);
- *p = QQmlListProperty<QObject>(object, list,
- list_append, list_count, list_at,
- list_clear);
- p->dummy1 = this;
- p->dummy2 = reinterpret_cast<void *>(quintptr(methodOffset() + id));
- } else {
- *reinterpret_cast<QObject **>(a[0]) = readPropertyAsQObject(id);
+ } 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::Variant:
- writeProperty(id, *reinterpret_cast<QVariant *>(a[0]));
- break;
- case QV4::CompiledData::BuiltinType::Font:
- case QV4::CompiledData::BuiltinType::Time:
- case QV4::CompiledData::BuiltinType::Color:
- case QV4::CompiledData::BuiltinType::Vector2D:
- case QV4::CompiledData::BuiltinType::Vector3D:
- case QV4::CompiledData::BuiltinType::Vector4D:
- case QV4::CompiledData::BuiltinType::Matrix4x4:
- case QV4::CompiledData::BuiltinType::Quaternion:
- Q_ASSERT(fallbackMetaType != QMetaType::UnknownType);
- if (QV4::MemberData *md = propertyAndMethodStorageAsMemberData()) {
- const QV4::VariantObject *v = (md->data() + id)->as<QV4::VariantObject>();
- if (!v) {
- md->set(engine, id, engine->newVariantObject(QVariant()));
- v = (md->data() + id)->as<QV4::VariantObject>();
- QQml_valueTypeProvider()->initValueType(fallbackMetaType, v->d()->data());
+
+ 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)
@@ -825,18 +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) return -1;
+ if (ctxt.isNull())
+ return -1;
- while (aliasData->aliasToLocalAlias)
+ while (aliasData->isAliasToLocalAlias())
aliasData = &compiledObject->aliasTable()[aliasData->localAliasIndex];
- QQmlContext *context = ctxt->asQQmlContext();
- QQmlContextPrivate *ctxtPriv = QQmlContextPrivate::get(context);
-
- QObject *target = ctxtPriv->data->idValues[aliasData->targetObjectId].data();
+ QObject *target = ctxt->idValue(aliasData->targetObjectId());
if (!target)
return -1;
@@ -855,39 +1065,50 @@ 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)
return -1;
const QQmlPropertyData *pd = targetDData->propertyCache->property(coreIndex);
// Value type property or deep alias
- QQmlValueType *valueType = QQmlValueTypeFactory::valueType(pd->propType());
+ 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, nullptr);
+ 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);
}
@@ -910,7 +1131,7 @@ int QQmlVMEMetaObject::metaCall(QObject *o, QMetaObject::Call c, int _id, void *
id -= plainSignals;
if (id < methodCount) {
- QQmlEngine *engine = ctxt->engine;
+ QQmlEngine *engine = ctxt->engine();
if (!engine)
return -1; // We can't run the method
@@ -920,17 +1141,17 @@ int QQmlVMEMetaObject::metaCall(QObject *o, QMetaObject::Call c, int _id, void *
QV4::Scope scope(v4);
- QV4::ScopedFunctionObject function(scope, method(id));
+ QV4::Scoped<QV4::JavaScriptFunctionObject> function(scope, method(id));
if (!function) {
// The function was not compiled. There are some exceptional cases which the
// expression rewriter does not rewrite properly (e.g., \r-terminated lines
// 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.
}
@@ -938,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(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 int 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]) {
- QMetaType::destruct(returnType, a[0]);
- QMetaType::construct(returnType, 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::QVariant)
- *(QVariant *)a[0] = scope.engine->toVariant(result, 0);
- else
- scope.engine->metaTypeFromJS(result, returnType, a[0]);
- }
}
ep->dereferenceScarceResources(); // "release" scarce resources if top-level expression evaluation is complete.
@@ -981,13 +1187,10 @@ int QQmlVMEMetaObject::metaCall(QObject *o, QMetaObject::Call c, int _id, void *
else
return object->qt_metacall(c, _id, a);
}
-#if defined(Q_OS_WINRT) && defined(_M_ARM)
-#pragma optimize("", on)
-#endif
QV4::ReturnedValue QQmlVMEMetaObject::method(int index) const
{
- if (!ctxt || !ctxt->isValid() || !compiledObject) {
+ if (ctxt.isNull() || !ctxt->isValid() || !compiledObject) {
qWarning("QQmlVMEMetaObject: Internal error - attempted to evaluate a function in an invalid context");
return QV4::Encode::undefined();
}
@@ -1001,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)
@@ -1019,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)
@@ -1045,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();
@@ -1054,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;
@@ -1105,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();
}
@@ -1170,12 +1394,12 @@ 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)
{
- if (engine != markStack->engine)
+ if (engine != markStack->engine())
return;
propertyAndMethodStorage.markOnce(markStack);
@@ -1192,14 +1416,14 @@ bool QQmlVMEMetaObject::aliasTarget(int index, QObject **target, int *coreIndex,
*coreIndex = -1;
*valueTypeIndex = -1;
- if (!ctxt)
+ if (ctxt.isNull())
return false;
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->idValues[aliasData->targetObjectId].data();
+ *target = ctxt->idValue(aliasData->targetObjectId());
if (!*target)
return false;
@@ -1227,7 +1451,7 @@ void QQmlVMEMetaObject::connectAlias(int aliasId)
}
endpoint->metaObject = this;
- endpoint->connect(&ctxt->idValues[aliasData->targetObjectId].bindings);
+ 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 5025987586..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>
+
+QT_BEGIN_NAMESPACE
+
+class QQmlVMEMetaObject;
+class QQmlVMEResolvedList
+{
+ Q_DISABLE_COPY_MOVE(QQmlVMEResolvedList)
-#include <private/qobject_p.h>
+public:
+ QQmlVMEResolvedList(QQmlListProperty<QObject> *prop);
+ ~QQmlVMEResolvedList();
-#include "qqmlguard_p.h"
-#include "qqmlcontext_p.h"
+ QQmlVMEMetaObject *metaObject() const { return m_metaObject; }
+ QV4::Heap::Object *list() const { return m_list; }
+ quintptr id() const { return m_id; }
-#include <private/qflagpointer_p.h>
+ void append(QObject *o) const;
+ void replace(qsizetype i, QObject *o) const;
+ QObject *at(qsizetype i) const;
-#include <private/qv4object_p.h>
-#include <private/qv4value_p.h>
-#include <private/qqmlpropertyvalueinterceptor_p.h>
+ qsizetype size() const { return m_list->arrayData->length(); }
-QT_BEGIN_NAMESPACE
+ 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,10 +173,13 @@ 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 QQmlRefPointer<QV4::ExecutableCompilationUnit> &qmlCompilationUnit, int qmlObjectId);
+ QQmlVMEMetaObject(QV4::ExecutionEngine *engine, QObject *obj,
+ const QQmlPropertyCache::ConstPtr &cache,
+ const QQmlRefPointer<QV4::ExecutableCompilationUnit> &qmlCompilationUnit,
+ int qmlObjectId);
~QQmlVMEMetaObject() override;
bool aliasTarget(int index, QObject **target, int *coreIndex, int *valueTypeIndex) const;
@@ -160,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;
@@ -185,21 +225,34 @@ 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;
- QList<QObject *> *readPropertyAsList(int id) const;
+ void initPropertyAsList(int id) const;
void writeProperty(int id, int v);
void writeProperty(int id, bool v);
void writeProperty(int id, double v);
void writeProperty(int id, const QString& v);
- void writeProperty(int id, const QPointF& v);
- void writeProperty(int id, const QSizeF& v);
- void writeProperty(int id, const QUrl& v);
- void writeProperty(int id, const QDate& v);
- void writeProperty(int id, const QDateTime& v);
- void writeProperty(int id, const QRectF& v);
+
+ template<typename VariantCompatible>
+ void writeProperty(int id, const VariantCompatible &v)
+ {
+ QV4::MemberData *md = propertyAndMethodStorageAsMemberData();
+ if (md) {
+ QV4::Scope scope(engine);
+ QV4::Scoped<QV4::MemberData>(scope, md)->set(
+ engine, id, engine->newVariantObject(
+ QMetaType::fromType<VariantCompatible>(), &v));
+ }
+ }
+
void writeProperty(int id, QObject *v);
void ensureQObjectWrapper();
diff --git a/src/qml/qml/qqmlxmlhttprequest.cpp b/src/qml/qml/qqmlxmlhttprequest.cpp
index 4db0562c0e..b4800584a3 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>
@@ -54,8 +17,11 @@
#include <QtCore/qobject.h>
#include <QtQml/qjsvalue.h>
#include <QtQml/qjsengine.h>
+#include <QtQml/qqmlfile.h>
#include <QtNetwork/qnetworkreply.h>
-#include <QtCore/qtextcodec.h>
+
+#include <QtCore/qpointer.h>
+#include <QtCore/qstringconverter.h>
#include <QtCore/qxmlstream.h>
#include <QtCore/qstack.h>
#include <QtCore/qdebug.h>
@@ -77,6 +43,8 @@ using namespace QV4;
QT_BEGIN_NAMESPACE
DEFINE_BOOL_CONFIG_OPTION(xhrDump, QML_XHR_DUMP);
+DEFINE_BOOL_CONFIG_OPTION(xhrFileWrite, QML_XHR_ALLOW_FILE_WRITE);
+DEFINE_BOOL_CONFIG_OPTION(xhrFileRead, QML_XHR_ALLOW_FILE_READ);
struct QQmlXMLHttpRequestData {
QQmlXMLHttpRequestData();
@@ -150,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;
}
@@ -164,8 +133,8 @@ public:
NodeImpl *root;
- void addref() { QQmlRefCount::addref(); }
- void release() { QQmlRefCount::release(); }
+ void addref() { Base1::addref(); }
+ void release() { Base1::release(); }
};
namespace Heap {
@@ -537,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();
@@ -559,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));
@@ -699,7 +668,7 @@ ReturnedValue CharacterData::method_length(const FunctionObject *b, const Value
if (!r)
RETURN_UNDEFINED();
- return Encode(r->d()->d->data.length());
+ return Encode(int(r->d()->d->data.size()));
}
ReturnedValue CharacterData::prototype(ExecutionEngine *v4)
@@ -725,7 +694,7 @@ ReturnedValue Text::method_isElementContentWhitespace(const FunctionObject *b, c
if (!r)
RETURN_UNDEFINED();
- return Encode(QStringRef(&r->d()->d->data).trimmed().isEmpty());
+ return Encode(QStringView(r->d()->d->data).trimmed().isEmpty());
}
ReturnedValue Text::method_wholeText(const FunctionObject *b, const Value *thisObject, const Value *, int)
@@ -892,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));
@@ -906,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;
@@ -935,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));
@@ -946,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);
}
@@ -1003,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();
@@ -1017,7 +990,8 @@ public:
QString replyStatusText() const;
ReturnedValue open(Object *thisObject, const QString &, const QUrl &, LoadType);
- ReturnedValue send(Object *thisObject, QQmlContextData *context, const QByteArray &);
+ ReturnedValue send(Object *thisObject, const QQmlRefPointer<QQmlContextData> &context,
+ const QByteArray &);
ReturnedValue abort(Object *thisObject);
void addHeader(const QString &, const QString &);
@@ -1027,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*);
@@ -1058,14 +1038,14 @@ private:
bool m_gotXml;
QByteArray m_mime;
QByteArray m_charset;
- QTextCodec *m_textCodec;
-#if QT_CONFIG(textcodec)
- QTextCodec* findTextCodec() const;
-#endif
+ QByteArray m_overrideMime;
+ QByteArray m_overrideCharset;
+
+ QStringDecoder findTextDecoder() const;
void readEncoding();
PersistentValue m_thisObject;
- QQmlContextDataRef m_qmlContext;
+ QQmlRefPointer<QQmlContextData> m_qmlContext;
bool m_wasConstructedWithQmlContext = true;
void dispatchCallbackNow(Object *thisObj);
@@ -1088,11 +1068,9 @@ private:
QQmlXMLHttpRequest::QQmlXMLHttpRequest(QNetworkAccessManager *manager, QV4::ExecutionEngine *v4)
: m_state(Unsent), m_errorFlag(false), m_sendFlag(false)
- , m_redirectCount(0), m_gotXml(false), m_textCodec(nullptr), m_network(nullptr), m_nam(manager)
- , m_responseType()
- , m_parsedDocument()
+ , m_redirectCount(0), m_gotXml(false), m_network(nullptr), m_nam(manager)
{
- m_wasConstructedWithQmlContext = v4->callingQmlContext() != nullptr;
+ m_wasConstructedWithQmlContext = !v4->callingQmlContext().isNull();
}
QQmlXMLHttpRequest::~QQmlXMLHttpRequest()
@@ -1169,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);
@@ -1194,7 +1172,30 @@ void QQmlXMLHttpRequest::fillHeadersList()
void QQmlXMLHttpRequest::requestFromUrl(const QUrl &url)
{
+ m_url = url;
QNetworkRequest request = m_request;
+
+ if (QQmlFile::isLocalFile(url)) {
+ if (m_method == QLatin1String("PUT"))
+ {
+ if (!xhrFileWrite()) {
+ qWarning("XMLHttpRequest: Using PUT on a local file is disabled by default.\n"
+ "Set QML_XHR_ALLOW_FILE_WRITE to 1 to enable this feature.");
+ return;
+ }
+ } else if (m_method == QLatin1String("GET")) {
+ if (!xhrFileRead()) {
+ qWarning("XMLHttpRequest: Using GET on a local file is disabled by default.\n"
+ "Set QML_XHR_ALLOW_FILE_READ to 1 to enable this feature.");
+ return;
+ }
+ } else {
+ qWarning("XMLHttpRequest: Unsupported method used on a local file");
+ return;
+ }
+ }
+
+ request.setAttribute(QNetworkRequest::RedirectPolicyAttribute, QNetworkRequest::ManualRedirectPolicy);
request.setUrl(url);
if(m_method == QLatin1String("POST") ||
m_method == QLatin1String("PUT")) {
@@ -1211,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;
}
@@ -1266,14 +1267,15 @@ void QQmlXMLHttpRequest::requestFromUrl(const QUrl &url)
} else {
QObject::connect(m_network, SIGNAL(readyRead()),
this, SLOT(readyRead()));
- QObject::connect(m_network, SIGNAL(error(QNetworkReply::NetworkError)),
+ QObject::connect(m_network, SIGNAL(errorOccurred(QNetworkReply::NetworkError)),
this, SLOT(error(QNetworkReply::NetworkError)));
QObject::connect(m_network, SIGNAL(finished()),
this, SLOT(finished()));
}
}
-ReturnedValue QQmlXMLHttpRequest::send(Object *thisObject, QQmlContextData *context, const QByteArray &data)
+ReturnedValue QQmlXMLHttpRequest::send(
+ Object *thisObject, const QQmlRefPointer<QQmlContextData> &context, const QByteArray &data)
{
m_errorFlag = false;
m_sendFlag = true;
@@ -1319,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();
}
@@ -1389,13 +1391,17 @@ void QQmlXMLHttpRequest::finished()
QVariant redirect = m_network->attribute(QNetworkRequest::RedirectionTargetAttribute);
if (redirect.isValid()) {
QUrl url = m_network->url().resolved(redirect.toUrl());
- if (url.scheme() != QLatin1String("file")) {
+ if (!QQmlFile::isLocalFile(url)) {
// See http://www.ietf.org/rfc/rfc2616.txt, section 10.3.4 "303 See Other":
// Result of 303 redirection should be a new "GET" request.
const QVariant code = m_network->attribute(QNetworkRequest::HttpStatusCodeAttribute);
if (code.isValid() && code.toInt() == 303 && m_method != QLatin1String("GET"))
m_method = QStringLiteral("GET");
destroyNetwork();
+
+ // Discard redirect response body
+ m_responseEntityBody = QByteArray();
+
requestFromUrl(url);
return;
}
@@ -1434,13 +1440,13 @@ void QQmlXMLHttpRequest::finished()
dispatchCallbackSafely();
m_thisObject.clear();
- m_qmlContext.setContextData(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) {
@@ -1451,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;
}
@@ -1467,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;
@@ -1484,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"));
@@ -1504,43 +1530,38 @@ QV4::ReturnedValue QQmlXMLHttpRequest::xmlResponseBody(QV4::ExecutionEngine* eng
return m_parsedDocument.value();
}
-#if QT_CONFIG(textcodec)
-QTextCodec* QQmlXMLHttpRequest::findTextCodec() const
+QStringDecoder QQmlXMLHttpRequest::findTextDecoder() const
{
- QTextCodec *codec = nullptr;
+ QStringDecoder decoder;
- if (!m_charset.isEmpty())
- codec = QTextCodec::codecForName(m_charset);
+ if (!charset().isEmpty())
+ decoder = QStringDecoder(charset());
- if (!codec && m_gotXml) {
+ if (!decoder.isValid() && m_gotXml) {
QXmlStreamReader reader(m_responseEntityBody);
reader.readNext();
- codec = QTextCodec::codecForName(reader.documentEncoding().toString().toUtf8());
+ decoder = QStringDecoder(reader.documentEncoding().toString().toUtf8());
}
- if (!codec && m_mime == "text/html")
- codec = QTextCodec::codecForHtml(m_responseEntityBody, nullptr);
+ if (!decoder.isValid() && mimeType() == "text/html")
+ decoder = QStringDecoder::decoderForHtml(m_responseEntityBody);
+
+ if (!decoder.isValid()) {
+ auto encoding = QStringConverter::encodingForData(m_responseEntityBody);
+ if (encoding)
+ decoder = QStringDecoder(*encoding);
+ }
- if (!codec)
- codec = QTextCodec::codecForUtfText(m_responseEntityBody, nullptr);
+ if (!decoder.isValid())
+ decoder = QStringDecoder(QStringDecoder::Utf8);
- if (!codec)
- codec = QTextCodec::codecForName("UTF-8");
- return codec;
+ return decoder;
}
-#endif
-
QString QQmlXMLHttpRequest::responseBody()
{
-#if QT_CONFIG(textcodec)
- if (!m_textCodec)
- m_textCodec = findTextCodec();
- if (m_textCodec)
- return m_textCodec->toUnicode(m_responseEntityBody);
-#endif
-
- return QString::fromUtf8(m_responseEntityBody);
+ QStringDecoder toUtf16 = findTextDecoder();
+ return toUtf16(m_responseEntityBody);
}
const QByteArray &QQmlXMLHttpRequest::rawResponseBody() const
@@ -1565,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);
@@ -1587,12 +1608,13 @@ void QQmlXMLHttpRequest::dispatchCallbackNow(Object *thisObj, bool done, bool er
void QQmlXMLHttpRequest::dispatchCallbackSafely()
{
- if (m_wasConstructedWithQmlContext && !m_qmlContext.contextData())
+ if (m_wasConstructedWithQmlContext && m_qmlContext.isNull()) {
// if the calling context object is no longer valid, then it has been
// deleted explicitly (e.g., by a Loader deleting the itemContext when
// the source is changed). We do nothing in this case, as the evaluation
// cannot succeed.
return;
+ }
dispatchCallbackNow(m_thisObject.as<Object>());
}
@@ -1626,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);
};
@@ -1638,6 +1660,7 @@ struct QQmlXMLHttpRequestWrapper : public Object
V4_NEEDS_DESTROY
};
+// https://xhr.spec.whatwg.org/
struct QQmlXMLHttpRequestCtor : public FunctionObject
{
V4_OBJECT2(QQmlXMLHttpRequestCtor, FunctionObject)
@@ -1647,7 +1670,7 @@ struct QQmlXMLHttpRequestCtor : public FunctionObject
Scope scope(f->engine());
const QQmlXMLHttpRequestCtor *ctor = static_cast<const QQmlXMLHttpRequestCtor *>(f);
- QQmlXMLHttpRequest *r = new QQmlXMLHttpRequest(scope.engine->qmlEngine()->networkAccessManager(), scope.engine);
+ QQmlXMLHttpRequest *r = new QQmlXMLHttpRequest(scope.engine->networkAccessManager(scope.engine), scope.engine);
Scoped<QQmlXMLHttpRequestWrapper> w(scope, scope.engine->memoryManager->allocate<QQmlXMLHttpRequestWrapper>(r));
ScopedObject proto(scope, ctor->d()->proto);
w->setPrototypeUnchecked(proto);
@@ -1666,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);
@@ -1675,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);
};
}
@@ -1683,15 +1708,16 @@ DEFINE_OBJECT_VTABLE(QQmlXMLHttpRequestWrapper);
void Heap::QQmlXMLHttpRequestCtor::init(ExecutionEngine *engine)
{
- Heap::FunctionObject::init(engine->rootContext(), QStringLiteral("XMLHttpRequest"));
+ Heap::FunctionObject::init(engine, QStringLiteral("XMLHttpRequest"));
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());
@@ -1714,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);
@@ -1722,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);
@@ -1763,8 +1791,7 @@ ReturnedValue QQmlXMLHttpRequestCtor::method_open(const FunctionObject *b, const
QUrl url = QUrl(argv[1].toQStringNoThrow());
if (url.isRelative()) {
- QQmlContextData *qmlContextData = scope.engine->callingQmlContext();
- if (qmlContextData)
+ if (QQmlRefPointer<QQmlContextData> qmlContextData = scope.engine->callingQmlContext())
url = qmlContextData->resolvedUrl(url);
else
url = scope.engine->resolvedUrl(url.url());
@@ -1829,7 +1856,6 @@ ReturnedValue QQmlXMLHttpRequestCtor::method_setRequestHeader(const FunctionObje
nameUpper == QLatin1String("TRAILER") ||
nameUpper == QLatin1String("TRANSFER-ENCODING") ||
nameUpper == QLatin1String("UPGRADE") ||
- nameUpper == QLatin1String("USER-AGENT") ||
nameUpper == QLatin1String("VIA") ||
nameUpper.startsWith(QLatin1String("PROXY-")) ||
nameUpper.startsWith(QLatin1String("SEC-")))
@@ -2049,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/qqmlbuiltinfunctions_p.h b/src/qml/qml/v8/qqmlbuiltinfunctions_p.h
deleted file mode 100644
index d87b83ba10..0000000000
--- a/src/qml/qml/v8/qqmlbuiltinfunctions_p.h
+++ /dev/null
@@ -1,200 +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 QQMLBUILTINFUNCTIONS_P_H
-#define QQMLBUILTINFUNCTIONS_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/qqmlglobal_p.h>
-#include <private/qv4functionobject_p.h>
-#include <private/qjsengine_p.h>
-
-QT_BEGIN_NAMESPACE
-
-class QQmlEngine;
-
-namespace QV4 {
-
-namespace Heap {
-
-struct QtObject : Object {
- void init(QQmlEngine *qmlEngine);
- QObject *platform;
- QObject *application;
-
- enum { Finished = -1 };
- int enumeratorIterator;
- int keyIterator;
-
- bool isComplete() const
- { return enumeratorIterator == Finished; }
-};
-
-struct ConsoleObject : Object {
- void init();
-};
-
-#define QQmlBindingFunctionMembers(class, Member) \
- Member(class, Pointer, FunctionObject *, bindingFunction)
-DECLARE_HEAP_OBJECT(QQmlBindingFunction, FunctionObject) {
- DECLARE_MARKOBJECTS(QQmlBindingFunction)
- void init(const QV4::FunctionObject *bindingFunction);
-};
-
-}
-
-struct QtObject : Object
-{
- V4_OBJECT2(QtObject, Object)
-
- static ReturnedValue virtualGet(const Managed *m, PropertyKey id, const Value *receiver, bool *hasProperty);
- static OwnPropertyKeyIterator *virtualOwnPropertyKeys(const Object *m, Value *target);
-
- static ReturnedValue method_isQtObject(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
- static ReturnedValue method_rgba(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
- static ReturnedValue method_hsla(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
- static ReturnedValue method_hsva(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
- static ReturnedValue method_colorEqual(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
- static ReturnedValue method_font(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
- static ReturnedValue method_rect(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
- static ReturnedValue method_point(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
- static ReturnedValue method_size(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
- static ReturnedValue method_vector2d(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
- static ReturnedValue method_vector3d(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
- static ReturnedValue method_vector4d(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
- static ReturnedValue method_quaternion(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
- static ReturnedValue method_matrix4x4(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
- static ReturnedValue method_lighter(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
- static ReturnedValue method_darker(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
- static ReturnedValue method_tint(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
- static ReturnedValue method_formatDate(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
- static ReturnedValue method_formatTime(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
- static ReturnedValue method_formatDateTime(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
- static ReturnedValue method_openUrlExternally(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
- static ReturnedValue method_fontFamilies(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
- static ReturnedValue method_md5(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
- static ReturnedValue method_btoa(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
- static ReturnedValue method_atob(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
- static ReturnedValue method_quit(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
- static ReturnedValue method_exit(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
- static ReturnedValue method_resolvedUrl(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
- static ReturnedValue method_createQmlObject(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
- static ReturnedValue method_createComponent(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
-#if QT_CONFIG(qml_locale)
- static ReturnedValue method_locale(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
-#endif
- static ReturnedValue method_binding(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
-
- static ReturnedValue method_get_platform(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
- static ReturnedValue method_get_application(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
- static ReturnedValue method_get_inputMethod(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
- static ReturnedValue method_get_styleHints(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
-
- static ReturnedValue method_callLater(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
-
-private:
- void addAll();
- ReturnedValue findAndAdd(const QString *name, bool &foundProperty) const;
-};
-
-struct ConsoleObject : Object
-{
- V4_OBJECT2(ConsoleObject, Object)
-
- static ReturnedValue method_error(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
- static ReturnedValue method_log(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
- static ReturnedValue method_info(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
- static ReturnedValue method_profile(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
- static ReturnedValue method_profileEnd(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
- static ReturnedValue method_time(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
- static ReturnedValue method_timeEnd(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
- static ReturnedValue method_count(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
- static ReturnedValue method_trace(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
- static ReturnedValue method_warn(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
- static ReturnedValue method_assert(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
- static ReturnedValue method_exception(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
-
-};
-
-struct Q_QML_PRIVATE_EXPORT GlobalExtensions {
- static void init(Object *globalObject, QJSEngine::Extensions extensions);
-
-#if QT_CONFIG(translation)
- 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);
- static ReturnedValue method_qsTrNoOp(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
- static ReturnedValue method_qsTrId(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
- static ReturnedValue method_qsTrIdNoOp(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
-#endif
- static ReturnedValue method_gc(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
-
- // on String:prototype
- static ReturnedValue method_string_arg(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
-
-};
-
-struct QQmlBindingFunction : public QV4::FunctionObject
-{
- V4_OBJECT2(QQmlBindingFunction, FunctionObject)
-
- Heap::FunctionObject *bindingFunction() const { return d()->bindingFunction; }
- QQmlSourceLocation currentLocation() const; // from caller stack trace
-};
-
-inline bool FunctionObject::isBinding() const
-{
- return d()->vtable() == QQmlBindingFunction::staticVTable();
-}
-
-}
-
-QT_END_NAMESPACE
-
-#endif // QQMLBUILTINFUNCTIONS_P_H
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
diff --git a/src/qml/qml/v8/v8.pri b/src/qml/qml/v8/v8.pri
deleted file mode 100644
index fbcc47de0c..0000000000
--- a/src/qml/qml/v8/v8.pri
+++ /dev/null
@@ -1,9 +0,0 @@
-HEADERS += \
- $$PWD/qv4domerrors_p.h \
- $$PWD/qv4sqlerrors_p.h \
- $$PWD/qqmlbuiltinfunctions_p.h
-
-SOURCES += \
- $$PWD/qv4domerrors.cpp \
- $$PWD/qv4sqlerrors.cpp \
- $$PWD/qqmlbuiltinfunctions.cpp