aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml
diff options
context:
space:
mode:
authorQt Forward Merge Bot <qt_forward_merge_bot@qt-project.org>2019-12-12 01:00:07 +0100
committerUlf Hermann <ulf.hermann@qt.io>2019-12-12 10:06:06 +0100
commit1196b1ef6c5d2cb05ceba5d6f178dc7e2432ed61 (patch)
tree2a99ee28d15d8ee51fc28096e5559bfc2d453e3f /src/qml
parentfb54af6638dcbeae8ad21249fe234ef4d82c005b (diff)
parentca206bceaff3667469986402e6143bf4c666b228 (diff)
Merge remote-tracking branch 'origin/5.15' into dev
Conflicts: src/qml/types/qqmlbind.cpp Change-Id: Ib992d1a7ac6c1a96d39819be6f23955dc31b44b2
Diffstat (limited to 'src/qml')
-rw-r--r--src/qml/common/qv4compileddata_p.h10
-rw-r--r--src/qml/compiler/qv4codegen.cpp38
-rw-r--r--src/qml/doc/images/listmodel-nested.pngbin7493 -> 0 bytes
-rw-r--r--src/qml/doc/images/listmodel.pngbin3407 -> 0 bytes
-rw-r--r--src/qml/doc/images/objectmodel.pngbin347 -> 0 bytes
-rw-r--r--src/qml/doc/qtqml.qdocconf12
-rw-r--r--src/qml/doc/snippets/qml/workerscript/script.mjs4
-rw-r--r--src/qml/doc/snippets/qml/workerscript/workerscript.qml74
-rw-r--r--src/qml/doc/src/cppintegration/data.qdoc5
-rw-r--r--src/qml/doc/src/qmldiskcache.qdoc76
-rw-r--r--src/qml/doc/src/qmlfunctions.qdoc1
-rw-r--r--src/qml/doc/src/qtqml.qdoc2
-rw-r--r--src/qml/jsruntime/qv4enginebase_p.h2
-rw-r--r--src/qml/jsruntime/qv4executablecompilationunit.cpp6
-rw-r--r--src/qml/jsruntime/qv4runtime.cpp9
-rw-r--r--src/qml/jsruntime/qv4typedarray.cpp154
-rw-r--r--src/qml/jsruntime/qv4typedarray_p.h1
-rw-r--r--src/qml/jsruntime/qv4vme_moth.cpp35
-rw-r--r--src/qml/parser/qqmljs.g82
-rw-r--r--src/qml/parser/qqmljsast_p.h4
-rw-r--r--src/qml/parser/qqmljslexer.cpp9
-rw-r--r--src/qml/qml.pro1
-rw-r--r--src/qml/qml/qqmlcomponent.cpp2
-rw-r--r--src/qml/qml/qqmldata_p.h2
-rw-r--r--src/qml/qml/qqmlengine.cpp12
-rw-r--r--src/qml/qml/qqmlextensionplugin.cpp2
-rw-r--r--src/qml/qml/qqmlinfo.cpp3
-rw-r--r--src/qml/qml/qqmllocale.cpp28
-rw-r--r--src/qml/qml/qqmllocale_p.h13
-rw-r--r--src/qml/qml/qqmlmetatype.cpp19
-rw-r--r--src/qml/qml/qqmlmetatypedata_p.h4
-rw-r--r--src/qml/qml/qqmlproperty.cpp4
-rw-r--r--src/qml/qml/qqmlproperty_p.h4
-rw-r--r--src/qml/qml/qqmltype.cpp36
-rw-r--r--src/qml/qml/qqmltype_p.h1
-rw-r--r--src/qml/qml/qqmltype_p_p.h12
-rw-r--r--src/qml/qml/qqmltypeloader.cpp5
-rw-r--r--src/qml/qml/qqmltypeloaderqmldircontent.cpp1
-rw-r--r--src/qml/qml/qqmlvmemetaobject.cpp132
-rw-r--r--src/qml/qml/qqmlvmemetaobject_p.h18
-rw-r--r--src/qml/qml/qqmlxmlhttprequest.cpp4
-rw-r--r--src/qml/qmldirparser/qqmldirparser.cpp33
-rw-r--r--src/qml/qmldirparser/qqmldirparser_p.h9
43 files changed, 611 insertions, 258 deletions
diff --git a/src/qml/common/qv4compileddata_p.h b/src/qml/common/qv4compileddata_p.h
index 7abf530996..5e30db8a89 100644
--- a/src/qml/common/qv4compileddata_p.h
+++ b/src/qml/common/qv4compileddata_p.h
@@ -76,7 +76,7 @@ QT_BEGIN_NAMESPACE
// Also change the comment behind the number to describe the latest change. This has the added
// benefit that if another patch changes the version too, it will result in a merge conflict, and
// not get removed silently.
-#define QV4_DATA_STRUCTURE_VERSION 0x26// support required properties
+#define QV4_DATA_STRUCTURE_VERSION 0x27 // resolved merge
class QIODevice;
class QQmlTypeNameCache;
@@ -304,13 +304,15 @@ struct Function
quint16_le nLineNumbers;
size_t lineNumberOffset() const { return localsOffset + nLocals * sizeof(quint32); }
quint32_le nestedFunctionIndex; // for functions that only return a single closure, used in signal handlers
+
+ quint32_le nRegisters;
+ Location location;
+ quint32_le nLabelInfos;
+
quint16_le sizeOfLocalTemporalDeadZone;
quint16_le firstTemporalDeadZoneRegister;
quint16_le sizeOfRegisterTemporalDeadZone;
- quint16_le nRegisters;
- Location location;
- quint32_le nLabelInfos;
size_t labelInfosOffset() const { return lineNumberOffset() + nLineNumbers * sizeof(CodeOffsetToLine); }
// Keep all unaligned data at the end
diff --git a/src/qml/compiler/qv4codegen.cpp b/src/qml/compiler/qv4codegen.cpp
index c43ea64e2e..d61456f38d 100644
--- a/src/qml/compiler/qv4codegen.cpp
+++ b/src/qml/compiler/qv4codegen.cpp
@@ -1371,6 +1371,40 @@ bool Codegen::visit(BinaryExpression *ast)
setExprResult(Reference::fromAccumulator(this));
}
return false;
+ } else if (ast->op == QSOperator::Coalesce) {
+
+ Reference left = expression(ast->left);
+ if (hasError())
+ return false;
+
+ BytecodeGenerator::Label iftrue = bytecodeGenerator->newLabel();
+ BytecodeGenerator::Label iffalse = bytecodeGenerator->newLabel();
+
+ Instruction::CmpNeNull cmp;
+
+ left = left.storeOnStack();
+ left.loadInAccumulator();
+ bytecodeGenerator->addInstruction(cmp);
+
+ bytecodeGenerator->jumpTrue().link(iftrue);
+ bytecodeGenerator->jumpFalse().link(iffalse);
+
+ blockTailCalls.unblock();
+
+ iftrue.link();
+
+ left.loadInAccumulator();
+
+ BytecodeGenerator::Jump jump_endif = bytecodeGenerator->jump();
+
+ iffalse.link();
+
+ Reference right = expression(ast->right);
+ right.loadInAccumulator();
+ jump_endif.link();
+ setExprResult(Reference::fromAccumulator(this));
+
+ return false;
} else if (ast->op == QSOperator::Assign) {
if (AST::Pattern *p = ast->left->patternCast()) {
RegisterScope scope(this);
@@ -1497,7 +1531,9 @@ bool Codegen::visit(BinaryExpression *ast)
break;
}
-
+ case QSOperator::As:
+ setExprResult(left);
+ break;
} // switch
return false;
diff --git a/src/qml/doc/images/listmodel-nested.png b/src/qml/doc/images/listmodel-nested.png
deleted file mode 100644
index ee7ffba67a..0000000000
--- a/src/qml/doc/images/listmodel-nested.png
+++ /dev/null
Binary files differ
diff --git a/src/qml/doc/images/listmodel.png b/src/qml/doc/images/listmodel.png
deleted file mode 100644
index 7ab1771f15..0000000000
--- a/src/qml/doc/images/listmodel.png
+++ /dev/null
Binary files differ
diff --git a/src/qml/doc/images/objectmodel.png b/src/qml/doc/images/objectmodel.png
deleted file mode 100644
index 5e6d1325b2..0000000000
--- a/src/qml/doc/images/objectmodel.png
+++ /dev/null
Binary files differ
diff --git a/src/qml/doc/qtqml.qdocconf b/src/qml/doc/qtqml.qdocconf
index 74d0a3b27c..07ab974289 100644
--- a/src/qml/doc/qtqml.qdocconf
+++ b/src/qml/doc/qtqml.qdocconf
@@ -34,20 +34,14 @@ qhp.QtQml.subprojects.qmltypes.sortPages = true
tagfile = ../../../doc/qtqml/qtqml.tags
-depends += qtcore qtgui qtquick qtdoc qtlinguist qmake qtscript qtwidgets qtxmlpatterns qtquickcontrols
+depends += qtcore qtqmlmodels qtqmlworkerscript qtgui qtquick qtdoc qtlinguist qmake qtscript qtwidgets qtxmlpatterns qtquickcontrols
headerdirs += .. \
- ../../imports/models \
- ../../qmlmodels \
- ../../qml \
- ../../qmlworkerscript
+ ../../qml
sourcedirs += .. \
- ../../imports/models \
../../imports/statemachine \
- ../../qmlmodels \
- ../../qml \
- ../../qmlworkerscript
+ ../../qml
exampledirs += ../../../examples/qml \
../ \
diff --git a/src/qml/doc/snippets/qml/workerscript/script.mjs b/src/qml/doc/snippets/qml/workerscript/script.mjs
deleted file mode 100644
index f55dee3507..0000000000
--- a/src/qml/doc/snippets/qml/workerscript/script.mjs
+++ /dev/null
@@ -1,4 +0,0 @@
-WorkerScript.onMessage = function(message) {
- // ... long-running operations and calculations are done here
- WorkerScript.sendMessage({ 'reply': 'Mouse is at ' + message.x + ',' + message.y })
-}
diff --git a/src/qml/doc/snippets/qml/workerscript/workerscript.qml b/src/qml/doc/snippets/qml/workerscript/workerscript.qml
deleted file mode 100644
index cc637d34cf..0000000000
--- a/src/qml/doc/snippets/qml/workerscript/workerscript.qml
+++ /dev/null
@@ -1,74 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-//![0]
-import QtQuick 2.0
-
-Rectangle {
- width: 300; height: 300
-
- Text {
- id: myText
- text: 'Click anywhere'
- }
-
- WorkerScript {
- id: myWorker
- source: "script.mjs"
-
- onMessage: myText.text = messageObject.reply
- }
-
- MouseArea {
- anchors.fill: parent
- onClicked: myWorker.sendMessage({ 'x': mouse.x, 'y': mouse.y })
- }
-}
-//![0]
diff --git a/src/qml/doc/src/cppintegration/data.qdoc b/src/qml/doc/src/cppintegration/data.qdoc
index 171b2b6a11..6bf7dbfb8f 100644
--- a/src/qml/doc/src/cppintegration/data.qdoc
+++ b/src/qml/doc/src/cppintegration/data.qdoc
@@ -308,6 +308,11 @@ In both the Q_PROPERTY and return from Q_INVOKABLE cases, the elements
of a std::vector are copied. This copying may be an expensive operation,
so std::vector should be used judiciously.
+You can also create a list-like data structure by constructing a QJSValue using
+QJSEngine::newArray(). Such a JavaScript array does not need any conversion
+when passing it between QML and C++. See \l{QJSValue#Working With Arrays} for
+details on how to manipulate JavaScript arrays from C++.
+
Other sequence types are not supported transparently, and instead an
instance of any other sequence type will be passed between QML and C++ as an
opaque QVariantList.
diff --git a/src/qml/doc/src/qmldiskcache.qdoc b/src/qml/doc/src/qmldiskcache.qdoc
new file mode 100644
index 0000000000..a32adf37c8
--- /dev/null
+++ b/src/qml/doc/src/qmldiskcache.qdoc
@@ -0,0 +1,76 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+\page qmldiskcache.html
+\title The QML Disk Cache
+\brief QML caches compiled documents on disk to improve load time.
+
+When your application loads a QML or JavaScript file for the first time,
+the QML engine compiles the file into a byte code representation on the
+fly and runs it. The compiling process can be time consuming, and subsequent
+loads of the same document yield the same result. To optimize this step, the
+QML engine can cache the result. It stores the byte code in a cache file and
+later loads the cache file instead of re-compiling when the same file is
+requested again. Usually the files are stored in a subdirectory \c{qmlcache}
+of the system's cache directory, as denoted by QStandardPaths::CacheLocation.
+Checks are in place to make sure that the cache files are only loaded if all
+of the following conditions are met:
+\list
+ \li The Qt version has not changed
+ \li The source code in the original file has not changed
+ \li The QML debugger is not running
+\endlist
+
+The disk caching behavior can be fine tuned using the following environment
+variables:
+
+\table
+ \header
+ \li Environment Variable
+ \li Description
+ \row
+ \li \c{QML_DISABLE_DISK_CACHE}
+ \li Disables the disk cache and forces re-compilation from source for
+ all QML and JavaScript files.
+ \row
+ \li \c{QML_FORCE_DISK_CACHE}
+ \li Enables the disk cache even when debugging QML. You cannot use the
+ JavaScript debugger this way. It may fail to stop at breakpoints,
+ for example. You can still use the QML inspector to explore the
+ object hierarchy, though. \c{QML_FORCE_DISK_CACHE} overrides
+ \c{QML_DISABLE_DISK_CACHE}.
+ \row
+ \li \c{QML_DISK_CACHE_PATH}
+ \li Specifies a custom location where the cache files shall be stored
+ instead of using the default location.
+
+You can also specify \c{CONFIG += qtquickcompiler} in your \c{.pro} file
+to perform the compilation ahead of time and integrate the resulting byte code
+directly into your executable. For more information, see \l{Qt Quick Compiler}.
+
+*/
diff --git a/src/qml/doc/src/qmlfunctions.qdoc b/src/qml/doc/src/qmlfunctions.qdoc
index b2d322465d..67c0f6bb25 100644
--- a/src/qml/doc/src/qmlfunctions.qdoc
+++ b/src/qml/doc/src/qmlfunctions.qdoc
@@ -275,6 +275,7 @@
/*!
\fn int qmlRegisterAnonymousType(const char *uri, int versionMajor)
+ \relates QQmlEngine
This template function registers the C++ type in the QML system as an anonymous type. The
resulting QML type does not have a name. Therefore, instances of this type cannot be created from
diff --git a/src/qml/doc/src/qtqml.qdoc b/src/qml/doc/src/qtqml.qdoc
index 68d2b66950..205cbc147d 100644
--- a/src/qml/doc/src/qtqml.qdoc
+++ b/src/qml/doc/src/qtqml.qdoc
@@ -155,6 +155,8 @@ Further information for writing QML applications:
- essential information for application development with QML and Qt Quick
\li \l{Qt Quick} - a module which provides a set of QML types and C++ classes
for building user interfaces and applications with QML
+\li \l{The QML Disk Cache}
+ - how to fine tune if and where the QML engine caches compilation results.
\endlist
\section2 Reference
diff --git a/src/qml/jsruntime/qv4enginebase_p.h b/src/qml/jsruntime/qv4enginebase_p.h
index 788897bdad..5e62c5bd50 100644
--- a/src/qml/jsruntime/qv4enginebase_p.h
+++ b/src/qml/jsruntime/qv4enginebase_p.h
@@ -86,7 +86,6 @@ struct Q_QML_EXPORT EngineBase {
quint8 isExecutingInRegExpJIT = false;
quint8 padding[3];
MemoryManager *memoryManager = nullptr;
- Runtime runtime;
qint32 callDepth = 0;
Value *jsStackLimit = nullptr;
@@ -146,7 +145,6 @@ Q_STATIC_ASSERT(offsetof(EngineBase, currentStackFrame) == 0);
Q_STATIC_ASSERT(offsetof(EngineBase, jsStackTop) == offsetof(EngineBase, currentStackFrame) + QT_POINTER_SIZE);
Q_STATIC_ASSERT(offsetof(EngineBase, hasException) == offsetof(EngineBase, jsStackTop) + QT_POINTER_SIZE);
Q_STATIC_ASSERT(offsetof(EngineBase, memoryManager) == offsetof(EngineBase, hasException) + 8);
-Q_STATIC_ASSERT(offsetof(EngineBase, runtime) == offsetof(EngineBase, memoryManager) + QT_POINTER_SIZE);
Q_STATIC_ASSERT(offsetof(EngineBase, isInterrupted) + sizeof(EngineBase::isInterrupted) <= offsetof(EngineBase, hasException) + 4);
}
diff --git a/src/qml/jsruntime/qv4executablecompilationunit.cpp b/src/qml/jsruntime/qv4executablecompilationunit.cpp
index 7c6368d60a..b1e2879bba 100644
--- a/src/qml/jsruntime/qv4executablecompilationunit.cpp
+++ b/src/qml/jsruntime/qv4executablecompilationunit.cpp
@@ -94,11 +94,15 @@ ExecutableCompilationUnit::~ExecutableCompilationUnit()
QString ExecutableCompilationUnit::localCacheFilePath(const QUrl &url)
{
+ static const QByteArray envCachePath = qgetenv("QML_DISK_CACHE_PATH");
+
const QString localSourcePath = QQmlFile::urlToLocalFileOrQrc(url);
const QString cacheFileSuffix = QFileInfo(localSourcePath + QLatin1Char('c')).completeSuffix();
QCryptographicHash fileNameHash(QCryptographicHash::Sha1);
fileNameHash.addData(localSourcePath.toUtf8());
- QString directory = QStandardPaths::writableLocation(QStandardPaths::CacheLocation) + QLatin1String("/qmlcache/");
+ QString directory = envCachePath.isEmpty()
+ ? QStandardPaths::writableLocation(QStandardPaths::CacheLocation) + QLatin1String("/qmlcache/")
+ : QString::fromLocal8Bit(envCachePath) + QLatin1String("/");
QDir::root().mkpath(directory);
return directory + QString::fromUtf8(fileNameHash.result().toHex()) + QLatin1Char('.') + cacheFileSuffix;
}
diff --git a/src/qml/jsruntime/qv4runtime.cpp b/src/qml/jsruntime/qv4runtime.cpp
index 21a0017728..e47a7a0b46 100644
--- a/src/qml/jsruntime/qv4runtime.cpp
+++ b/src/qml/jsruntime/qv4runtime.cpp
@@ -408,6 +408,15 @@ QV4::ReturnedValue Runtime::In::call(ExecutionEngine *engine, const Value &left,
double RuntimeHelpers::stringToNumber(const QString &string)
{
+ // The actual maximum valid length is certainly shorter, but due to the sheer number of
+ // different number formatting variants, we rather err on the side of caution here.
+ // For example, you can have up to 772 valid decimal digits left of the dot, as stated in the
+ // libdoubleconversion sources. The same maximum value would be represented by roughly 3.5 times
+ // as many binary digits.
+ const int excessiveLength = 16 * 1024;
+ if (string.length() > excessiveLength)
+ return qQNaN();
+
const QStringRef s = QStringRef(&string).trimmed();
if (s.startsWith(QLatin1Char('0'))) {
int base = -1;
diff --git a/src/qml/jsruntime/qv4typedarray.cpp b/src/qml/jsruntime/qv4typedarray.cpp
index 893fe06e8e..9c50ac2b95 100644
--- a/src/qml/jsruntime/qv4typedarray.cpp
+++ b/src/qml/jsruntime/qv4typedarray.cpp
@@ -1641,6 +1641,158 @@ ReturnedValue IntrinsicTypedArrayCtor::method_of(const FunctionObject *f, const
return newObj->asReturnedValue();
}
+ReturnedValue IntrinsicTypedArrayCtor::method_from(const FunctionObject *f, const Value *thisObject, const Value *argv, int argc)
+{
+ Scope scope(f);
+ ScopedObject itemsObject(scope, argv[0]);
+ bool usingIterator = false;
+
+ ScopedFunctionObject mapfn(scope, Value::undefinedValue());
+ Value *mapArguments = nullptr;
+ if (argc > 1) {
+ mapfn = ScopedFunctionObject(scope, argv[1]);
+ if (!mapfn)
+ return scope.engine->throwTypeError(QString::fromLatin1("%1 is not a function").arg(argv[1].toQStringNoThrow()));
+ mapArguments = scope.alloc(2);
+ }
+
+ // Iterator validity check goes after map function validity has been checked.
+ if (itemsObject) {
+ // If the object claims to support iterators, then let's try use them.
+ ScopedValue it(scope, itemsObject->get(scope.engine->symbol_iterator()));
+ CHECK_EXCEPTION();
+ if (!it->isNullOrUndefined()) {
+ ScopedFunctionObject itfunc(scope, it);
+ if (!itfunc)
+ return scope.engine->throwTypeError();
+ usingIterator = true;
+ }
+ }
+
+ ScopedValue thisArg(scope);
+ if (argc > 2)
+ thisArg = argv[2];
+
+ const FunctionObject *C = thisObject->as<FunctionObject>();
+
+ if (usingIterator) {
+ // Item iteration supported, so let's go ahead and try use that.
+ CHECK_EXCEPTION();
+
+ qint64 iterableLength = 0;
+ Value *nextValue = scope.alloc(1);
+ ScopedValue done(scope);
+
+ ScopedObject lengthIterator(scope, Runtime::GetIterator::call(scope.engine, itemsObject, true));
+ CHECK_EXCEPTION(); // symbol_iterator threw; whoops.
+ if (!lengthIterator) {
+ return scope.engine->throwTypeError(); // symbol_iterator wasn't an object.
+ }
+
+ forever {
+ // Here we calculate the length of the iterable range.
+ if (iterableLength > (static_cast<qint64>(1) << 53) - 1) {
+ ScopedValue falsey(scope, Encode(false));
+ ScopedValue error(scope, scope.engine->throwTypeError());
+ return Runtime::IteratorClose::call(scope.engine, lengthIterator, falsey);
+ }
+ // Retrieve the next value. If the iteration ends, we're done here.
+ done = Value::fromReturnedValue(Runtime::IteratorNext::call(scope.engine, lengthIterator, nextValue));
+ if (scope.engine->hasException)
+ return Runtime::IteratorClose::call(scope.engine, lengthIterator, Value::fromBoolean(false));
+ if (done->toBoolean()) {
+ break;
+ }
+ iterableLength++;
+ }
+
+ // Constructor validity check goes after we have calculated the length, because that calculation can throw
+ // errors that are not type errors and at least the tests expect those rather than type errors.
+ if (!C || !C->isConstructor())
+ return scope.engine->throwTypeError();
+
+ ScopedObject iterator(scope, Runtime::GetIterator::call(scope.engine, itemsObject, true));
+ CHECK_EXCEPTION(); // symbol_iterator can throw.
+ if (!iterator) {
+ return scope.engine->throwTypeError(); // symbol_iterator wasn't an object.
+ }
+
+ ScopedObject a(scope, Value::undefinedValue());
+ ScopedValue ctorArgument(scope, Value::fromReturnedValue(QV4::Encode(int(iterableLength))));
+ a = C->callAsConstructor(ctorArgument, 1);
+ CHECK_EXCEPTION();
+
+ // We check exceptions above, and only after doing so, check the array's validity after construction.
+ if (!::validateTypedArray(a) || (a->getLength() < iterableLength))
+ return scope.engine->throwTypeError();
+
+
+ // The loop below traverses the iterator, and puts elements into the created array.
+ ScopedValue mappedValue(scope, Value::undefinedValue());
+ for (qint64 k = 0; k < iterableLength; ++k) {
+ done = Value::fromReturnedValue(Runtime::IteratorNext::call(scope.engine, iterator, nextValue));
+ if (scope.engine->hasException)
+ return Runtime::IteratorClose::call(scope.engine, iterator, Value::fromBoolean(false));
+
+ if (mapfn) {
+ mapArguments[0] = *nextValue;
+ mapArguments[1] = Value::fromDouble(k);
+ mappedValue = mapfn->call(thisArg, mapArguments, 2);
+ if (scope.engine->hasException)
+ return Runtime::IteratorClose::call(scope.engine, iterator, Value::fromBoolean(false));
+ } else {
+ mappedValue = *nextValue;
+ }
+
+ a->put(k, mappedValue);
+ if (scope.engine->hasException)
+ return Runtime::IteratorClose::call(scope.engine, iterator, Value::fromBoolean(false));
+ }
+ return a.asReturnedValue();
+ } else {
+ // Array-like fallback. We request elements by index, and put them into the created array.
+ ScopedObject arrayLike(scope, argv[0].toObject(scope.engine));
+ if (!arrayLike)
+ return scope.engine->throwTypeError(QString::fromLatin1("Cannot convert %1 to object").arg(argv[0].toQStringNoThrow()));
+
+ int len = arrayLike->getLength();
+ CHECK_EXCEPTION();
+
+ // Getting the length may throw, and must do so before we check the constructor validity.
+ if (!C || !C->isConstructor())
+ return scope.engine->throwTypeError();
+
+ ScopedObject a(scope, Value::undefinedValue());
+ ScopedValue ctorArgument(scope, Value::fromReturnedValue(QV4::Encode(len)));
+ a = C->callAsConstructor(ctorArgument, 1);
+ CHECK_EXCEPTION();
+
+ // We check exceptions above, and only after doing so, check the array's validity after construction.
+ if (!::validateTypedArray(a) || (a->getLength() < len))
+ return scope.engine->throwTypeError();
+
+ ScopedValue mappedValue(scope, Value::undefinedValue());
+ ScopedValue kValue(scope);
+ for (int k = 0; k < len; ++k) {
+ kValue = arrayLike->get(k);
+ CHECK_EXCEPTION();
+
+ if (mapfn) {
+ mapArguments[0] = kValue;
+ mapArguments[1] = Value::fromDouble(k);
+ mappedValue = mapfn->call(thisArg, mapArguments, 2);
+ CHECK_EXCEPTION();
+ } else {
+ mappedValue = kValue;
+ }
+
+ a->put(k, mappedValue);
+ CHECK_EXCEPTION();
+ }
+ return a.asReturnedValue();
+ }
+}
+
void IntrinsicTypedArrayPrototype::init(ExecutionEngine *engine, IntrinsicTypedArrayCtor *ctor)
{
Scope scope(engine);
@@ -1650,6 +1802,8 @@ void IntrinsicTypedArrayPrototype::init(ExecutionEngine *engine, IntrinsicTypedA
ctor->defineReadonlyConfigurableProperty(engine->id_name(), s);
s = scope.engine->newString(QStringLiteral("of"));
ctor->defineDefaultProperty(s, IntrinsicTypedArrayCtor::method_of);
+ s = scope.engine->newString(QStringLiteral("from"));
+ ctor->defineDefaultProperty(s, IntrinsicTypedArrayCtor::method_from, 1);
ctor->addSymbolSpecies();
defineAccessorProperty(QStringLiteral("buffer"), method_get_buffer, nullptr);
diff --git a/src/qml/jsruntime/qv4typedarray_p.h b/src/qml/jsruntime/qv4typedarray_p.h
index 64792f23a2..65656e3389 100644
--- a/src/qml/jsruntime/qv4typedarray_p.h
+++ b/src/qml/jsruntime/qv4typedarray_p.h
@@ -181,6 +181,7 @@ struct IntrinsicTypedArrayCtor: FunctionObject
static constexpr VTable::Call virtualCall = nullptr;
static ReturnedValue method_of(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
+ static ReturnedValue method_from(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
};
struct TypedArrayCtor: FunctionObject
diff --git a/src/qml/jsruntime/qv4vme_moth.cpp b/src/qml/jsruntime/qv4vme_moth.cpp
index ad5a6ebc8c..e143523165 100644
--- a/src/qml/jsruntime/qv4vme_moth.cpp
+++ b/src/qml/jsruntime/qv4vme_moth.cpp
@@ -341,7 +341,17 @@ static struct InstrCount {
}
#endif
-#define STACK_VALUE(temp) stack[temp]
+static inline QV4::Value &stackValue(QV4::Value *stack, size_t slot, const CppStackFrame *frame)
+{
+ Q_ASSERT(slot < CallData::HeaderSize() / sizeof(QV4::StaticValue)
+ + frame->jsFrame->argc()
+ + frame->v4Function->compiledFunction->nRegisters);
+ Q_UNUSED(frame);
+
+ return stack[slot];
+}
+
+#define STACK_VALUE(temp) stackValue(stack, temp, frame)
// qv4scopedvalue_p.h also defines a CHECK_EXCEPTION macro
#ifdef CHECK_EXCEPTION
@@ -521,14 +531,14 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine,
MOTH_END_INSTR(LoadImport)
MOTH_BEGIN_INSTR(LoadLocal)
- auto cc = static_cast<Heap::CallContext *>(stack[CallData::Context].m());
+ auto cc = static_cast<Heap::CallContext *>(STACK_VALUE(CallData::Context).m());
Q_ASSERT(cc->type != QV4::Heap::CallContext::Type_GlobalContext);
acc = cc->locals[index].asReturnedValue();
MOTH_END_INSTR(LoadLocal)
MOTH_BEGIN_INSTR(StoreLocal)
CHECK_EXCEPTION;
- auto cc = static_cast<Heap::CallContext *>(stack[CallData::Context].m());
+ auto cc = static_cast<Heap::CallContext *>(STACK_VALUE(CallData::Context).m());
Q_ASSERT(cc->type != QV4::Heap::CallContext::Type_GlobalContext);
QV4::WriteBarrier::write(engine, cc, cc->locals.values[index].data_ptr(), acc);
MOTH_END_INSTR(StoreLocal)
@@ -714,7 +724,7 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine,
MOTH_BEGIN_INSTR(CallProperty)
STORE_IP();
- acc = Runtime::CallProperty::call(engine, stack[base], name, stack + argv, argc);
+ acc = Runtime::CallProperty::call(engine, STACK_VALUE(base), name, stack + argv, argc);
CHECK_EXCEPTION;
MOTH_END_INSTR(CallProperty)
@@ -722,21 +732,21 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine,
STORE_IP();
Lookup *l = function->executableCompilationUnit()->runtimeLookups + lookupIndex;
- if (stack[base].isNullOrUndefined()) {
+ if (STACK_VALUE(base).isNullOrUndefined()) {
QString message = QStringLiteral("Cannot call method '%1' of %2")
.arg(engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[l->nameIndex]->toQString())
- .arg(stack[base].toQStringNoThrow());
+ .arg(STACK_VALUE(base).toQStringNoThrow());
acc = engine->throwTypeError(message);
goto handleUnwind;
}
// ok to have the value on the stack here
- Value f = Value::fromReturnedValue(l->getter(l, engine, stack[base]));
+ Value f = Value::fromReturnedValue(l->getter(l, engine, STACK_VALUE(base)));
if (Q_UNLIKELY(!f.isFunctionObject())) {
QString message = QStringLiteral("Property '%1' of object %2 is not a function")
.arg(engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[l->nameIndex]->toQString())
- .arg(stack[base].toQStringNoThrow());
+ .arg(STACK_VALUE(base).toQStringNoThrow());
acc = engine->throwTypeError(message);
goto handleUnwind;
}
@@ -747,7 +757,7 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine,
MOTH_BEGIN_INSTR(CallElement)
STORE_IP();
- acc = Runtime::CallElement::call(engine, stack[base], STACK_VALUE(index), stack + argv, argc);
+ acc = Runtime::CallElement::call(engine, STACK_VALUE(base), STACK_VALUE(index), stack + argv, argc);
CHECK_EXCEPTION;
MOTH_END_INSTR(CallElement)
@@ -864,7 +874,7 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine,
MOTH_BEGIN_INSTR(PushWithContext)
STORE_IP();
STORE_ACC();
- acc = Runtime::PushWithContext::call(engine, stack[CallData::Accumulator]);
+ acc = Runtime::PushWithContext::call(engine, STACK_VALUE(CallData::Accumulator));
CHECK_EXCEPTION;
MOTH_END_INSTR(PushWithContext)
@@ -971,12 +981,13 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine,
MOTH_BEGIN_INSTR(ConvertThisToObject)
STORE_ACC();
- stack[CallData::This] = Runtime::ConvertThisToObject::call(engine, stack[CallData::This]);
+ stack[CallData::This] = Runtime::ConvertThisToObject::call(
+ engine, STACK_VALUE(CallData::This));
CHECK_EXCEPTION;
MOTH_END_INSTR(ConvertThisToObject)
MOTH_BEGIN_INSTR(LoadSuperConstructor)
- acc = Runtime::LoadSuperConstructor::call(engine, stack[CallData::Function]);
+ acc = Runtime::LoadSuperConstructor::call(engine, STACK_VALUE(CallData::Function));
CHECK_EXCEPTION;
MOTH_END_INSTR(LoadSuperConstructor)
diff --git a/src/qml/parser/qqmljs.g b/src/qml/parser/qqmljs.g
index e28899883f..6fbb9df164 100644
--- a/src/qml/parser/qqmljs.g
+++ b/src/qml/parser/qqmljs.g
@@ -80,6 +80,7 @@
%token T_COMMENT "comment"
%token T_COMPATIBILITY_SEMICOLON
%token T_ARROW "=>"
+%token T_QUESTION_QUESTION "??"
%token T_ENUM "enum"
%token T_ELLIPSIS "..."
%token T_YIELD "yield"
@@ -125,6 +126,7 @@
%nonassoc T_IDENTIFIER T_COLON T_SIGNAL T_PROPERTY T_READONLY T_ON T_SET T_GET T_OF T_STATIC T_FROM T_AS T_REQUIRED
%nonassoc REDUCE_HERE
%right T_THEN T_ELSE
+%right T_WITHOUTAS T_AS
%start TopLevel
@@ -1011,15 +1013,27 @@ UiObjectMember: UiQualifiedId T_ON UiQualifiedId UiObjectInitializer;
./
-UiObjectLiteral: T_LBRACE ExpressionStatementLookahead UiPropertyDefinitionList T_RBRACE;
-/. case $rule_number: Q_FALLTHROUGH(); ./
-UiObjectLiteral: T_LBRACE ExpressionStatementLookahead UiPropertyDefinitionList T_COMMA T_RBRACE;
+UiObjectLiteral: T_LBRACE ExpressionStatementLookahead UiPropertyDefinitionList T_RBRACE Semicolon;
/.
case $rule_number: {
AST::ObjectPattern *l = new (pool) AST::ObjectPattern(sym(3).PatternPropertyList->finish());
l->lbraceToken = loc(1);
l->rbraceToken = loc(4);
AST::ExpressionStatement *node = new (pool) AST::ExpressionStatement(l);
+ node->semicolonToken = loc(5);
+ sym(1).Node = node;
+ } break;
+./
+
+
+UiObjectLiteral: T_LBRACE ExpressionStatementLookahead UiPropertyDefinitionList T_COMMA T_RBRACE Semicolon;
+/.
+ case $rule_number: {
+ AST::ObjectPattern *l = new (pool) AST::ObjectPattern(sym(3).PatternPropertyList->finish());
+ l->lbraceToken = loc(1);
+ l->rbraceToken = loc(5);
+ AST::ExpressionStatement *node = new (pool) AST::ExpressionStatement(l);
+ node->semicolonToken = loc(6);
sym(1).Node = node;
} break;
./
@@ -2500,6 +2514,20 @@ RelationalExpression_In: RelationalExpression_In T_IN ShiftExpression;
} break;
./
+TypeAssertExpression_In: RelationalExpression_In T_AS Type;
+/. case $rule_number: Q_FALLTHROUGH(); ./
+TypeAssertExpression: RelationalExpression T_AS Type;
+/.
+ case $rule_number: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, QSOperator::As, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+ } break;
+./
+
+RelationalExpression_In: TypeAssertExpression_In;
+RelationalExpression: TypeAssertExpression;
+
EqualityExpression_In: RelationalExpression_In;
EqualityExpression: RelationalExpression;
@@ -2611,13 +2639,48 @@ LogicalORExpression_In: LogicalORExpression_In T_OR_OR LogicalANDExpression_In;
} break;
./
+CoalesceExpression: LogicalORExpression;
+CoalesceExpression_In: LogicalORExpression_In;
+
+CoalesceExpression: CoalesceExpression T_QUESTION_QUESTION LogicalORExpression;
+/. case $rule_number: Q_FALLTHROUGH(); ./
+CoalesceExpression_In: CoalesceExpression_In T_QUESTION_QUESTION LogicalORExpression_In;
+/.
+ case $rule_number: {
+
+ auto *lhs = sym(1).Expression;
+ auto *rhs = sym(3).Expression;
+
+ // Check if lhs or rhs contain || or &&
+
+ if (lhs->binaryExpressionCast() != nullptr) {
+ auto *binaryExpr = lhs->binaryExpressionCast();
+ if (binaryExpr->op == QSOperator::And || binaryExpr->op == QSOperator::Or) {
+ syntaxError(binaryExpr->operatorToken, "Left-hand side may not contain || or &&");
+ return false;
+ }
+ }
+
+ if (rhs->binaryExpressionCast() != nullptr) {
+ auto *binaryExpr = rhs->binaryExpressionCast();
+ if (binaryExpr->op == QSOperator::And || binaryExpr->op == QSOperator::Or) {
+ syntaxError(binaryExpr->operatorToken, "Right-hand side may not contain || or &&");
+ return false;
+ }
+ }
+
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(lhs, QSOperator::Coalesce, rhs);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+ } break;
+./
-ConditionalExpression: LogicalORExpression;
-ConditionalExpression_In: LogicalORExpression_In;
+ConditionalExpression: CoalesceExpression;
+ConditionalExpression_In: CoalesceExpression_In;
-ConditionalExpression: LogicalORExpression T_QUESTION AssignmentExpression_In T_COLON AssignmentExpression;
+ConditionalExpression: CoalesceExpression T_QUESTION AssignmentExpression_In T_COLON AssignmentExpression;
/. case $rule_number: Q_FALLTHROUGH(); ./
-ConditionalExpression_In: LogicalORExpression_In T_QUESTION AssignmentExpression_In T_COLON AssignmentExpression_In;
+ConditionalExpression_In: CoalesceExpression_In T_QUESTION AssignmentExpression_In T_COLON AssignmentExpression_In;
/.
case $rule_number: {
AST::ConditionalExpression *node = new (pool) AST::ConditionalExpression(sym(1).Expression, sym(3).Expression, sym(5).Expression);
@@ -4356,7 +4419,10 @@ ImportsList: ImportsList T_COMMA ImportSpecifier;
} break;
./
-ImportSpecifier: ImportedBinding;
+-- When enconutering an IdentifierReference it can resolve to both ImportedBinding and IdentifierName
+-- Using %right and %prec, we tell qlalr that it should not reduce immediately, but rather shift
+-- so that we have a chance of actually parsing the correct rule if there is an "as" identifier
+ImportSpecifier: ImportedBinding %prec T_WITHOUTAS;
/.
case $rule_number: {
auto importSpecifier = new (pool) AST::ImportSpecifier(stringRef(1));
diff --git a/src/qml/parser/qqmljsast_p.h b/src/qml/parser/qqmljsast_p.h
index e436c4673d..aa355fed85 100644
--- a/src/qml/parser/qqmljsast_p.h
+++ b/src/qml/parser/qqmljsast_p.h
@@ -104,6 +104,8 @@ enum Op {
URShift,
InplaceURightShift,
InplaceXor,
+ As,
+ Coalesce,
Invalid
};
@@ -1782,7 +1784,7 @@ public:
{ return expression->firstSourceLocation(); }
SourceLocation lastSourceLocation() const override
- { return expression->lastSourceLocation(); }
+ { return semicolonToken; }
// attributes
ExpressionNode *expression;
diff --git a/src/qml/parser/qqmljslexer.cpp b/src/qml/parser/qqmljslexer.cpp
index 443e1a7476..80d883e52f 100644
--- a/src/qml/parser/qqmljslexer.cpp
+++ b/src/qml/parser/qqmljslexer.cpp
@@ -580,7 +580,14 @@ again:
case ']': return T_RBRACKET;
case '[': return T_LBRACKET;
- case '?': return T_QUESTION;
+ case '?': {
+ if (_char == QLatin1Char('?')) {
+ scanChar();
+ return T_QUESTION_QUESTION;
+ }
+
+ return T_QUESTION;
+ }
case '>':
if (_char == QLatin1Char('>')) {
diff --git a/src/qml/qml.pro b/src/qml/qml.pro
index 3c889244f4..2cbe8ec564 100644
--- a/src/qml/qml.pro
+++ b/src/qml/qml.pro
@@ -63,7 +63,6 @@ qtConfig(qml-animation) {
include(types/types.pri)
include(../3rdparty/masm/masm-defs.pri)
include(../3rdparty/masm/masm.pri)
-include(../3rdparty/llvm/llvm.pri)
MODULE_PLUGIN_TYPES = \
qmltooling
diff --git a/src/qml/qml/qqmlcomponent.cpp b/src/qml/qml/qqmlcomponent.cpp
index 1d5f974d5c..279998b5de 100644
--- a/src/qml/qml/qqmlcomponent.cpp
+++ b/src/qml/qml/qqmlcomponent.cpp
@@ -376,7 +376,7 @@ bool QQmlComponentPrivate::setInitialProperty(QObject *component, const QString&
{
QQmlProperty prop = QQmlComponentPrivate::removePropertyFromRequired(component, name, requiredProperties());
QQmlPropertyPrivate *privProp = QQmlPropertyPrivate::get(prop);
- if (!prop.isValid() || !privProp->writeValueProperty(value, nullptr)) {
+ if (!prop.isValid() || !privProp->writeValueProperty(value, {})) {
QQmlError error{};
error.setUrl(url);
error.setDescription(QLatin1String("Could not set property %1").arg(name));
diff --git a/src/qml/qml/qqmldata_p.h b/src/qml/qml/qqmldata_p.h
index 299476f5c8..ee31cb38d9 100644
--- a/src/qml/qml/qqmldata_p.h
+++ b/src/qml/qml/qqmldata_p.h
@@ -335,7 +335,7 @@ bool QQmlData::wasDeleted(const QObject *object)
return true;
const QObjectPrivate *priv = QObjectPrivate::get(object);
- if (!priv || priv->wasDeleted)
+ if (!priv || priv->wasDeleted || priv->isDeletingChildren)
return true;
const QQmlData *ddata = QQmlData::get(object);
diff --git a/src/qml/qml/qqmlengine.cpp b/src/qml/qml/qqmlengine.cpp
index 0bdba313f3..51a5cc1db4 100644
--- a/src/qml/qml/qqmlengine.cpp
+++ b/src/qml/qml/qqmlengine.cpp
@@ -1595,6 +1595,9 @@ static QObject *resolveAttachedProperties(QQmlAttachedPropertiesFunc pf, QQmlDat
}
#if QT_DEPRECATED_SINCE(5, 14)
+QT_WARNING_PUSH
+QT_WARNING_DISABLE_DEPRECATED
+
QObject *qmlAttachedPropertiesObjectById(int id, const QObject *object, bool create)
{
QQmlData *data = QQmlData::get(object, create);
@@ -1605,7 +1608,9 @@ QObject *qmlAttachedPropertiesObjectById(int id, const QObject *object, bool cre
return nullptr;
QQmlEnginePrivate *engine = QQmlEnginePrivate::get(data->context);
- return resolveAttachedProperties(QQmlMetaType::attachedPropertiesFuncById(engine, id), data,
+
+ const QQmlType type = QQmlMetaType::qmlType(id, QQmlMetaType::TypeIdCategory::QmlType);
+ return resolveAttachedProperties(type.attachedPropertiesFunction(engine), data,
const_cast<QObject *>(object), create);
}
@@ -1622,6 +1627,8 @@ QObject *qmlAttachedPropertiesObject(int *idCache, const QObject *object,
return qmlAttachedPropertiesObjectById(*idCache, object, create);
}
+
+QT_WARNING_POP
#endif
QQmlAttachedPropertiesFunc qmlAttachedPropertiesFunction(QObject *object,
@@ -1650,6 +1657,8 @@ QObject *qmlAttachedPropertiesObject(QObject *object, QQmlAttachedPropertiesFunc
} // namespace QtQml
#if QT_DEPRECATED_SINCE(5, 1)
+QT_WARNING_PUSH
+QT_WARNING_DISABLE_DEPRECATED
// Also define symbols outside namespace to keep binary compatibility with Qt 5.0
@@ -1680,6 +1689,7 @@ Q_QML_EXPORT QObject *qmlAttachedPropertiesObject(int *idCache, const QObject *o
return QtQml::qmlAttachedPropertiesObject(idCache, object, attachedMetaObject, create);
}
+QT_WARNING_POP
#endif // QT_DEPRECATED_SINCE(5, 1)
class QQmlDataExtended {
diff --git a/src/qml/qml/qqmlextensionplugin.cpp b/src/qml/qml/qqmlextensionplugin.cpp
index 26364661a8..7a62c967e7 100644
--- a/src/qml/qml/qqmlextensionplugin.cpp
+++ b/src/qml/qml/qqmlextensionplugin.cpp
@@ -127,8 +127,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.
diff --git a/src/qml/qml/qqmlinfo.cpp b/src/qml/qml/qqmlinfo.cpp
index 2bfd2d5bb4..dd401bdb20 100644
--- a/src/qml/qml/qqmlinfo.cpp
+++ b/src/qml/qml/qqmlinfo.cpp
@@ -57,7 +57,6 @@ QT_BEGIN_NAMESPACE
/*!
\fn QQmlInfo QtQml::qmlDebug(const QObject *object)
- \relates QtQml
\since 5.9
Prints debug messages that include the file and line number for the
@@ -91,7 +90,6 @@ QT_BEGIN_NAMESPACE
/*!
\fn QQmlInfo QtQml::qmlInfo(const QObject *object)
- \relates QtQml
Prints informational messages that include the file and line number for the
specified QML \a object.
@@ -119,7 +117,6 @@ QT_BEGIN_NAMESPACE
/*!
\fn QQmlInfo QtQml::qmlWarning(const QObject *object)
- \relates QtQml
\since 5.9
Prints warning messages that include the file and line number for the
diff --git a/src/qml/qml/qqmllocale.cpp b/src/qml/qml/qqmllocale.cpp
index dca13ac8d4..139074c648 100644
--- a/src/qml/qml/qqmllocale.cpp
+++ b/src/qml/qml/qqmllocale.cpp
@@ -478,6 +478,23 @@ ReturnedValue QQmlLocaleData::method_get_firstDayOfWeek(const QV4::FunctionObjec
RETURN_RESULT(fdow);
}
+ReturnedValue QQmlLocaleData::method_get_numberOptions(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *, int) {
+ QV4::Scope scope(b);
+ const QLocale *locale = getThisLocale(scope, thisObject);
+ if (!locale)
+ return Encode::undefined();
+ int numberOptions = int(locale->numberOptions());
+ RETURN_RESULT(numberOptions);
+}
+
+ReturnedValue QQmlLocaleData::method_set_numberOptions(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc) {
+ QV4::Scope scope(b);
+ QLocale *locale = getThisLocale(scope, thisObject);
+ int const numberOptions = argc ? int(argv[0].toNumber()) : QLocale::DefaultNumberOptions;
+ locale->setNumberOptions(QLocale::NumberOptions {numberOptions});
+ return Encode::undefined();
+}
+
ReturnedValue QQmlLocaleData::method_get_measurementSystem(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *, int)
{
QV4::Scope scope(b);
@@ -701,6 +718,7 @@ QV4LocaleDataDeletable::QV4LocaleDataDeletable(QV4::ExecutionEngine *engine)
o->defineAccessorProperty(QStringLiteral("amText"), QQmlLocaleData::method_get_amText, nullptr);
o->defineAccessorProperty(QStringLiteral("measurementSystem"), QQmlLocaleData::method_get_measurementSystem, nullptr);
o->defineAccessorProperty(QStringLiteral("exponential"), QQmlLocaleData::method_get_exponential, nullptr);
+ o->defineAccessorProperty(QStringLiteral("numberOptions"), QQmlLocaleData::method_get_numberOptions, QQmlLocaleData::method_set_numberOptions);
prototype.set(engine, o);
}
@@ -873,6 +891,16 @@ ReturnedValue QQmlLocale::method_localeCompare(const QV4::FunctionObject *b, con
*/
/*!
+ \qmlproperty enumeration QtQml::Locale::NumberOption
+
+ 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.
diff --git a/src/qml/qml/qqmllocale_p.h b/src/qml/qml/qqmllocale_p.h
index 10e0dfcc38..1d6fdb12a7 100644
--- a/src/qml/qml/qqmllocale_p.h
+++ b/src/qml/qml/qqmllocale_p.h
@@ -131,6 +131,16 @@ public:
Saturday = Qt::Saturday
};
Q_ENUM(DayOfWeek)
+ enum NumberOptions {
+ DefaultNumberOptions = QLocale::DefaultNumberOptions,
+ OmitGroupSeparator = QLocale::OmitGroupSeparator,
+ RejectGroupSeparator = QLocale::RejectGroupSeparator,
+ OmitLeadingZeroInExponent = QLocale::OmitLeadingZeroInExponent,
+ RejectLeadingZeroInExponent = QLocale::RejectLeadingZeroInExponent,
+ IncludeTrailingZeroesAfterDot = QLocale::IncludeTrailingZeroesAfterDot,
+ RejectTrailingZeroesAfterDot = QLocale::RejectTrailingZeroesAfterDot
+ };
+ Q_ENUM(NumberOptions)
static QV4::ReturnedValue locale(QV4::ExecutionEngine *engine, const QString &localeName);
static QV4::ReturnedValue wrap(QV4::ExecutionEngine *engine, const QLocale &locale);
@@ -200,6 +210,9 @@ struct QQmlLocaleData : public QV4::Object
static QV4::ReturnedValue method_get_exponential(const QV4::FunctionObject *, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
static QV4::ReturnedValue method_get_amText(const QV4::FunctionObject *, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
static QV4::ReturnedValue method_get_pmText(const QV4::FunctionObject *, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
+
+ static QV4::ReturnedValue method_get_numberOptions(const QV4::FunctionObject *, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
+ static QV4::ReturnedValue method_set_numberOptions(const QV4::FunctionObject *, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
};
}
diff --git a/src/qml/qml/qqmlmetatype.cpp b/src/qml/qml/qqmlmetatype.cpp
index b8c17c9374..8f652f601a 100644
--- a/src/qml/qml/qqmlmetatype.cpp
+++ b/src/qml/qml/qqmlmetatype.cpp
@@ -329,7 +329,6 @@ QQmlType QQmlMetaType::registerInterface(const QQmlPrivate::RegisterInterface &t
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);
@@ -414,10 +413,10 @@ 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);
@@ -492,7 +491,7 @@ QQmlType QQmlMetaType::registerCompositeSingletonType(const QQmlPrivate::Registe
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);
}
@@ -513,7 +512,7 @@ QQmlType QQmlMetaType::registerCompositeType(const QQmlPrivate::RegisterComposit
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);
}
@@ -797,7 +796,7 @@ QQmlType QQmlMetaType::typeForUrl(const QString &urlString,
data->registerType(priv);
addTypeToData(priv, data);
- data->urlToType.insertMulti(url, priv);
+ data->urlToType.insert(url, priv);
return QQmlType(priv);
}
@@ -927,11 +926,11 @@ int QQmlMetaType::attachedPropertiesFuncId(QQmlEnginePrivate *engine, const QMet
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);
+ if (const QQmlTypePrivate *type = it.value()) {
+ if (const QQmlTypePrivate *base = type->attachedPropertiesBase(engine))
+ return base->index;
+ }
}
-
return -1;
}
diff --git a/src/qml/qml/qqmlmetatypedata_p.h b/src/qml/qml/qqmlmetatypedata_p.h
index f193e51f5a..e51d4ca1a4 100644
--- a/src/qml/qml/qqmlmetatypedata_p.h
+++ b/src/qml/qml/qqmlmetatypedata_p.h
@@ -71,7 +71,7 @@ struct QQmlMetaTypeData
QSet<QQmlType> undeletableTypes;
typedef QHash<int, QQmlTypePrivate *> Ids;
Ids idToType;
- typedef QHash<QHashedStringRef, QQmlTypePrivate *> Names;
+ typedef QMultiHash<QHashedStringRef, QQmlTypePrivate *> Names;
Names nameToType;
typedef QHash<QUrl, QQmlTypePrivate *> Files; //For file imported composite types only
Files urlToType;
@@ -79,7 +79,7 @@ struct QQmlMetaTypeData
// 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;
diff --git a/src/qml/qml/qqmlproperty.cpp b/src/qml/qml/qqmlproperty.cpp
index 27667de678..871bec1c17 100644
--- a/src/qml/qml/qqmlproperty.cpp
+++ b/src/qml/qml/qqmlproperty.cpp
@@ -785,7 +785,7 @@ static void removeOldBinding(QObject *object, QQmlPropertyIndex index, QQmlPrope
return;
if (!(flags & QQmlPropertyPrivate::DontEnable))
- oldBinding->setEnabled(false, nullptr);
+ oldBinding->setEnabled(false, {});
oldBinding->removeFromObject();
}
@@ -1451,7 +1451,7 @@ QQmlMetaObject QQmlPropertyPrivate::rawMetaObjectForType(QQmlEnginePrivate *engi
*/
bool QQmlProperty::write(const QVariant &value) const
{
- return QQmlPropertyPrivate::write(*this, value, nullptr);
+ return QQmlPropertyPrivate::write(*this, value, {});
}
/*!
diff --git a/src/qml/qml/qqmlproperty_p.h b/src/qml/qml/qqmlproperty_p.h
index 285c34d7fa..8abd83d7b4 100644
--- a/src/qml/qml/qqmlproperty_p.h
+++ b/src/qml/qml/qqmlproperty_p.h
@@ -107,9 +107,9 @@ public:
static bool writeValueProperty(QObject *,
const QQmlPropertyData &, const QQmlPropertyData &valueTypeData,
const QVariant &, QQmlContextData *,
- QQmlPropertyData::WriteFlags flags = nullptr);
+ QQmlPropertyData::WriteFlags flags = {});
static bool write(QObject *, const QQmlPropertyData &, const QVariant &,
- QQmlContextData *, QQmlPropertyData::WriteFlags flags = nullptr);
+ QQmlContextData *, QQmlPropertyData::WriteFlags flags = {});
static void findAliasTarget(QObject *, QQmlPropertyIndex, QObject **, QQmlPropertyIndex *);
enum BindingFlag {
diff --git a/src/qml/qml/qqmltype.cpp b/src/qml/qml/qqmltype.cpp
index 874bcd4bca..4a211ffa53 100644
--- a/src/qml/qml/qqmltype.cpp
+++ b/src/qml/qml/qqmltype.cpp
@@ -618,28 +618,16 @@ int QQmlType::metaObjectRevision() const
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->attachedPropertiesBase(engine))
+ return base->extraData.cd->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->attachedPropertiesBase(engine))
+ return base->extraData.cd->attachedPropertiesType;
+ return nullptr;
}
#if QT_DEPRECATED_SINCE(5, 14)
@@ -650,15 +638,9 @@ Qt 4.7 and QtQuick 1.0).
*/
int QQmlType::attachedPropertiesId(QQmlEnginePrivate *engine) const
{
- if (!d)
- 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);
+ if (const QQmlTypePrivate *base = d->attachedPropertiesBase(engine))
+ return base->index;
+ return -1;
}
#endif
diff --git a/src/qml/qml/qqmltype_p.h b/src/qml/qml/qqmltype_p.h
index ec27b38a73..af134b21f1 100644
--- a/src/qml/qml/qqmltype_p.h
+++ b/src/qml/qml/qqmltype_p.h
@@ -182,6 +182,7 @@ public:
};
private:
+ friend class QQmlTypePrivate;
friend uint qHash(const QQmlType &t, uint seed);
QQmlRefPointer<const QQmlTypePrivate> d;
};
diff --git a/src/qml/qml/qqmltype_p_p.h b/src/qml/qml/qqmltype_p_p.h
index 6a2d961de8..51f776178c 100644
--- a/src/qml/qml/qqmltype_p_p.h
+++ b/src/qml/qml/qqmltype_p_p.h
@@ -82,6 +82,18 @@ public:
}
}
+ 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.cd->attachedPropertiesType ? d : nullptr;
+
+ if (d->regType != QQmlType::CompositeType)
+ return nullptr;
+ }
+ return nullptr;
+ }
+
bool isComposite() const
{
return regType == QQmlType::CompositeType || regType == QQmlType::CompositeSingletonType;
diff --git a/src/qml/qml/qqmltypeloader.cpp b/src/qml/qml/qqmltypeloader.cpp
index b164f5873c..e0131c0a98 100644
--- a/src/qml/qml/qqmltypeloader.cpp
+++ b/src/qml/qml/qqmltypeloader.cpp
@@ -710,7 +710,7 @@ bool QQmlTypeLoader::Blob::isDebugging() const
bool QQmlTypeLoader::Blob::diskCacheEnabled() const
{
- return (!disableDiskCache() || forceDiskCache()) && !isDebugging();
+ return (!disableDiskCache() && !isDebugging()) || forceDiskCache();
}
bool QQmlTypeLoader::Blob::qmldirDataAvailable(const QQmlRefPointer<QQmlQmldirData> &data, QList<QQmlError> *errors)
@@ -1129,7 +1129,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);
}
/*!
diff --git a/src/qml/qml/qqmltypeloaderqmldircontent.cpp b/src/qml/qml/qqmltypeloaderqmldircontent.cpp
index 8e983db756..860971d296 100644
--- a/src/qml/qml/qqmltypeloaderqmldircontent.cpp
+++ b/src/qml/qml/qqmltypeloaderqmldircontent.cpp
@@ -74,6 +74,7 @@ QString QQmlTypeLoaderQmldirContent::typeNamespace() const
void QQmlTypeLoaderQmldirContent::setContent(const QString &location, const QString &content)
{
+ Q_ASSERT(!m_hasContent);
m_hasContent = true;
m_location = location;
m_parser.parse(content);
diff --git a/src/qml/qml/qqmlvmemetaobject.cpp b/src/qml/qml/qqmlvmemetaobject.cpp
index 9b5490b6e5..e0ca1ae6c5 100644
--- a/src/qml/qml/qqmlvmemetaobject.cpp
+++ b/src/qml/qml/qqmlvmemetaobject.cpp
@@ -62,30 +62,73 @@
QT_BEGIN_NAMESPACE
+class ResolvedList
+{
+ Q_DISABLE_COPY_MOVE(ResolvedList)
+
+public:
+ ResolvedList(QQmlListProperty<QObject> *prop) :
+ m_metaObject(static_cast<QQmlVMEMetaObject *>(QObjectPrivate::get(prop->object)->metaObject)),
+ m_id(quintptr(prop->data))
+ {
+ Q_ASSERT(m_metaObject);
+ Q_ASSERT(m_metaObject->object == prop->object);
+ Q_ASSERT(m_id <= quintptr(std::numeric_limits<int>::max() - m_metaObject->methodOffset()));
+
+ // readPropertyAsList() with all the checks transformed into Q_ASSERT
+ // and without allocation.
+ Q_ASSERT(!m_metaObject->propertyAndMethodStorage.isUndefined());
+ auto *md = static_cast<QV4::MemberData *>(m_metaObject->propertyAndMethodStorage.asManaged());
+ Q_ASSERT(md);
+ const auto *v = (md->data() + m_id)->as<QV4::VariantObject>();
+ Q_ASSERT(v);
+ Q_ASSERT(v->d());
+ QVariant &data = v->d()->data();
+ Q_ASSERT(data.userType() == qMetaTypeId<QList<QObject *>>());
+ m_list = static_cast<QList<QObject *> *>(data.data());
+ Q_ASSERT(m_list);
+ }
+
+ ~ResolvedList() = default;
+
+ QQmlVMEMetaObject *metaObject() const { return m_metaObject; }
+ QList<QObject *> *list() const { return m_list; }
+ quintptr id() const { return m_id; }
+
+ void activateSignal() const
+ {
+ m_metaObject->activate(m_metaObject->object, int(m_id + m_metaObject->methodOffset()),
+ nullptr);
+ }
+
+private:
+ QQmlVMEMetaObject *m_metaObject = nullptr;
+ QList<QObject *> *m_list = nullptr;
+ quintptr m_id = 0;
+};
+
static void list_append(QQmlListProperty<QObject> *prop, QObject *o)
{
- 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);
+ const ResolvedList resolved(prop);
+ resolved.list()->append(o);
+ resolved.activateSignal();
}
static int list_count(QQmlListProperty<QObject> *prop)
{
- QList<QObject *> *list = static_cast<QList<QObject *> *>(prop->data);
- return list->count();
+ return ResolvedList(prop).list()->count();
}
static QObject *list_at(QQmlListProperty<QObject> *prop, int index)
{
- QList<QObject *> *list = static_cast<QList<QObject *> *>(prop->data);
- return list->at(index);
+ return ResolvedList(prop).list()->at(index);
}
static void list_clear(QQmlListProperty<QObject> *prop)
{
- 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);
+ const ResolvedList resolved(prop);
+ resolved.list()->clear();
+ resolved.activateSignal();
}
QQmlVMEVariantQObjectPtr::QQmlVMEVariantQObjectPtr()
@@ -401,57 +444,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) {
@@ -720,13 +726,11 @@ int QQmlVMEMetaObject::metaCall(QObject *o, QMetaObject::Call c, int _id, void *
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));
+ readPropertyAsList(id); // Initializes if necessary
+ *static_cast<QQmlListProperty<QObject> *>(a[0])
+ = QQmlListProperty<QObject>(
+ object, reinterpret_cast<void *>(quintptr(id)),
+ list_append, list_count, list_at, list_clear);
} else {
*reinterpret_cast<QObject **>(a[0]) = readPropertyAsQObject(id);
}
@@ -877,7 +881,7 @@ int QQmlVMEMetaObject::metaCall(QObject *o, QMetaObject::Call c, int _id, void *
int rv = QMetaObject::metacall(valueType, c, valueTypePropertyIndex, a);
if (c == QMetaObject::WriteProperty)
- valueType->write(target, coreIndex, nullptr);
+ valueType->write(target, coreIndex, {});
return rv;
} else {
diff --git a/src/qml/qml/qqmlvmemetaobject_p.h b/src/qml/qml/qqmlvmemetaobject_p.h
index 5025987586..58332ff7a8 100644
--- a/src/qml/qml/qqmlvmemetaobject_p.h
+++ b/src/qml/qml/qqmlvmemetaobject_p.h
@@ -194,12 +194,18 @@ public:
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(
+ QVariant::fromValue(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..df4639bb1d 100644
--- a/src/qml/qml/qqmlxmlhttprequest.cpp
+++ b/src/qml/qml/qqmlxmlhttprequest.cpp
@@ -1396,6 +1396,10 @@ void QQmlXMLHttpRequest::finished()
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;
}
diff --git a/src/qml/qmldirparser/qqmldirparser.cpp b/src/qml/qmldirparser/qqmldirparser.cpp
index 6e925ba515..36b47a3302 100644
--- a/src/qml/qmldirparser/qqmldirparser.cpp
+++ b/src/qml/qmldirparser/qqmldirparser.cpp
@@ -73,6 +73,20 @@ static bool parseVersion(const QString &str, int *major, int *minor)
return false;
}
+void QQmlDirParser::clear()
+{
+ _errors.clear();
+ _typeNamespace.clear();
+ _components.clear();
+ _dependencies.clear();
+ _imports.clear();
+ _scripts.clear();
+ _plugins.clear();
+ _designerSupported = false;
+ _typeInfos.clear();
+ _className.clear();
+}
+
inline static void scanSpace(const QChar *&ch) {
while (ch->isSpace() && !ch->isNull() && *ch != QLatin1Char('\n'))
++ch;
@@ -93,13 +107,6 @@ inline static void scanWord(const QChar *&ch) {
*/
bool QQmlDirParser::parse(const QString &source)
{
- _errors.clear();
- _plugins.clear();
- _components.clear();
- _scripts.clear();
- _designerSupported = false;
- _className.clear();
-
quint16 lineNumber = 0;
bool firstLine = true;
@@ -198,7 +205,7 @@ bool QQmlDirParser::parse(const QString &source)
}
Component entry(sections[1], sections[2], -1, -1);
entry.internal = true;
- _components.insertMulti(entry.typeName, entry);
+ _components.insert(entry.typeName, entry);
} else if (sections[0] == QLatin1String("singleton")) {
if (sectionCount < 3 || sectionCount > 4) {
reportError(lineNumber, 0,
@@ -209,7 +216,7 @@ bool QQmlDirParser::parse(const QString &source)
// singleton TestSingletonType TestSingletonType.qml
Component entry(sections[1], sections[2], -1, -1);
entry.singleton = true;
- _components.insertMulti(entry.typeName, entry);
+ _components.insert(entry.typeName, entry);
} else {
// handle qmldir module listing case where singleton is defined in the following pattern:
// singleton TestSingletonType 2.0 TestSingletonType20.qml
@@ -218,7 +225,7 @@ bool QQmlDirParser::parse(const QString &source)
const QString &fileName = sections[3];
Component entry(sections[1], fileName, major, minor);
entry.singleton = true;
- _components.insertMulti(entry.typeName, entry);
+ _components.insert(entry.typeName, entry);
} else {
reportError(lineNumber, 0, QStringLiteral("invalid version %1, expected <major>.<minor>").arg(sections[2]));
}
@@ -264,7 +271,7 @@ bool QQmlDirParser::parse(const QString &source)
} else if (sectionCount == 2) {
// No version specified (should only be used for relative qmldir files)
const Component entry(sections[0], sections[1], -1, -1);
- _components.insertMulti(entry.typeName, entry);
+ _components.insert(entry.typeName, entry);
} else if (sectionCount == 3) {
int major, minor;
if (parseVersion(sections[1], &major, &minor)) {
@@ -276,7 +283,7 @@ bool QQmlDirParser::parse(const QString &source)
_scripts.append(entry);
} else {
const Component entry(sections[0], fileName, major, minor);
- _components.insertMulti(entry.typeName, entry);
+ _components.insert(entry.typeName, entry);
}
} else {
reportError(lineNumber, 0, QStringLiteral("invalid version %1, expected <major>.<minor>").arg(sections[1]));
@@ -343,7 +350,7 @@ QList<QQmlDirParser::Plugin> QQmlDirParser::plugins() const
return _plugins;
}
-QHash<QString, QQmlDirParser::Component> QQmlDirParser::components() const
+QMultiHash<QString, QQmlDirParser::Component> QQmlDirParser::components() const
{
return _components;
}
diff --git a/src/qml/qmldirparser/qqmldirparser_p.h b/src/qml/qmldirparser/qqmldirparser_p.h
index c9d77532c8..3696a1aa12 100644
--- a/src/qml/qmldirparser/qqmldirparser_p.h
+++ b/src/qml/qmldirparser/qqmldirparser_p.h
@@ -64,6 +64,7 @@ class QQmlEngine;
class Q_QMLCOMPILER_PRIVATE_EXPORT QQmlDirParser
{
public:
+ void clear();
bool parse(const QString &source);
bool hasError() const;
@@ -75,7 +76,7 @@ public:
static void checkNonRelative(const char *item, const QString &typeName, const QString &fileName)
{
- if (fileName.startsWith(QLatin1Char('/')) || fileName.contains(QLatin1Char(':'))) {
+ if (fileName.startsWith(QLatin1Char('/'))) {
qWarning() << item << typeName
<< "is specified with non-relative URL" << fileName << "in a qmldir file."
<< "URLs in qmldir files should be relative to the qmldir file's directory.";
@@ -131,7 +132,7 @@ public:
int minorVersion = 0;
};
- QHash<QString,Component> components() const;
+ QMultiHash<QString,Component> components() const;
QHash<QString,Component> dependencies() const;
QStringList imports() const;
QList<Script> scripts() const;
@@ -158,7 +159,7 @@ private:
private:
QList<QQmlJS::DiagnosticMessage> _errors;
QString _typeNamespace;
- QHash<QString,Component> _components; // multi hash
+ QMultiHash<QString,Component> _components;
QHash<QString,Component> _dependencies;
QStringList _imports;
QList<Script> _scripts;
@@ -168,7 +169,7 @@ private:
QString _className;
};
-using QQmlDirComponents = QHash<QString,QQmlDirParser::Component>;
+using QQmlDirComponents = QMultiHash<QString,QQmlDirParser::Component>;
using QQmlDirScripts = QList<QQmlDirParser::Script>;
using QQmlDirPlugins = QList<QQmlDirParser::Plugin>;