aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorSimon Hausmann <simon.hausmann@qt.io>2019-07-12 20:36:14 +0200
committerSimon Hausmann <simon.hausmann@qt.io>2019-07-12 20:36:48 +0200
commit880a143eb572de3e8a6734cc663ed4b6e309b99d (patch)
tree4d1ad149dff7d9708e5981ea7b0ec7f8aee24bbf /src
parentc433b78660923b6268653b437a2a04078de0f058 (diff)
parenta6057b46eebc71772d584ea5d318d130e2f40a19 (diff)
Merge remote-tracking branch 'origin/dev' into wip/qt6
Diffstat (limited to 'src')
-rw-r--r--src/imports/imports.pro4
-rw-r--r--src/imports/testlib/main.cpp1
-rw-r--r--src/particles/qquickparticlesystem_p.h1
-rw-r--r--src/plugins/qmltooling/qmldbg_preview/qqmlpreviewfileloader.cpp2
-rw-r--r--src/plugins/qmltooling/qmldbg_preview/qqmlpreviewhandler.cpp4
-rw-r--r--src/plugins/qmltooling/qmldbg_preview/qqmlpreviewhandler.h6
-rw-r--r--src/plugins/qmltooling/qmldbg_preview/qqmlpreviewservice.cpp4
-rw-r--r--src/plugins/qmltooling/qmldbg_preview/qqmlpreviewservice.h2
-rw-r--r--src/qml/common/common.pri34
-rw-r--r--src/qml/common/qqmljsfixedpoolarray_p.h140
-rw-r--r--src/qml/common/qqmljsmemorypool_p.h (renamed from src/qml/parser/qqmljsmemorypool_p.h)81
-rw-r--r--src/qml/common/qv4alloca_p.h (renamed from src/qml/compiler/qv4alloca_p.h)0
-rw-r--r--src/qml/common/qv4calldata_p.h (renamed from src/qml/compiler/qv4calldata_p.h)0
-rw-r--r--src/qml/common/qv4compileddata_p.h (renamed from src/qml/compiler/qv4compileddata_p.h)65
-rw-r--r--src/qml/common/qv4staticvalue_p.h (renamed from src/qml/compiler/qv4staticvalue_p.h)44
-rw-r--r--src/qml/common/qv4stringtoarrayindex_p.h (renamed from src/qml/compiler/qv4stringtoarrayindex_p.h)0
-rw-r--r--src/qml/compiler/compiler.pri8
-rw-r--r--src/qml/compiler/qqmlirbuilder.cpp312
-rw-r--r--src/qml/compiler/qqmlirbuilder_p.h87
-rw-r--r--src/qml/compiler/qv4bytecodegenerator.cpp4
-rw-r--r--src/qml/compiler/qv4bytecodegenerator_p.h5
-rw-r--r--src/qml/compiler/qv4codegen.cpp10
-rw-r--r--src/qml/compiler/qv4codegen_p.h271
-rw-r--r--src/qml/compiler/qv4compiler.cpp22
-rw-r--r--src/qml/compiler/qv4compiler_p.h9
-rw-r--r--src/qml/compiler/qv4compilercontext_p.h11
-rw-r--r--src/qml/compiler/qv4compilercontrolflow_p.h11
-rw-r--r--src/qml/compiler/qv4compilerglobal_p.h74
-rw-r--r--src/qml/compiler/qv4compilerscanfunctions.cpp33
-rw-r--r--src/qml/compiler/qv4compilerscanfunctions_p.h101
-rw-r--r--src/qml/compiler/qv4instr_moth_p.h2
-rw-r--r--src/qml/configure.json7
-rw-r--r--src/qml/doc/qtqml.qdocconf1
-rw-r--r--src/qml/doc/snippets/qml/events.qml8
-rw-r--r--src/qml/doc/snippets/qml/qtbinding/functions-qml/MyItem.qml2
-rw-r--r--src/qml/doc/snippets/qml/qtbinding/functions-qml/main.cpp10
-rw-r--r--src/qml/doc/snippets/qml/qtbinding/signals-qml/MyItem.qml2
-rw-r--r--src/qml/doc/snippets/qml/statemachine/guardcondition.qml2
-rw-r--r--src/qml/doc/src/cppintegration/interactqmlfromcpp.qdoc33
-rw-r--r--src/qml/jsruntime/qv4argumentsobject.cpp3
-rw-r--r--src/qml/jsruntime/qv4compilationunitmapper.cpp2
-rw-r--r--src/qml/jsruntime/qv4dateobject.cpp2
-rw-r--r--src/qml/jsruntime/qv4debugging_p.h1
-rw-r--r--src/qml/jsruntime/qv4engine.cpp2
-rw-r--r--src/qml/jsruntime/qv4engine_p.h1
-rw-r--r--src/qml/jsruntime/qv4errorobject.cpp2
-rw-r--r--src/qml/jsruntime/qv4executablecompilationunit.cpp4
-rw-r--r--src/qml/jsruntime/qv4executablecompilationunit_p.h6
-rw-r--r--src/qml/jsruntime/qv4function.cpp4
-rw-r--r--src/qml/jsruntime/qv4function_p.h5
-rw-r--r--src/qml/jsruntime/qv4functionobject.cpp2
-rw-r--r--src/qml/jsruntime/qv4global_p.h13
-rw-r--r--src/qml/jsruntime/qv4globalobject.cpp8
-rw-r--r--src/qml/jsruntime/qv4include.cpp1
-rw-r--r--src/qml/jsruntime/qv4math_p.h2
-rw-r--r--src/qml/jsruntime/qv4qobjectwrapper.cpp14
-rw-r--r--src/qml/jsruntime/qv4regexpobject.cpp2
-rw-r--r--src/qml/jsruntime/qv4runtime.cpp1
-rw-r--r--src/qml/jsruntime/qv4runtimeapi_p.h1
-rw-r--r--src/qml/jsruntime/qv4runtimecodegen.cpp3
-rw-r--r--src/qml/jsruntime/qv4runtimecodegen_p.h6
-rw-r--r--src/qml/jsruntime/qv4script.cpp2
-rw-r--r--src/qml/jsruntime/qv4sequenceobject.cpp25
-rw-r--r--src/qml/jsruntime/qv4stringobject.cpp2
-rw-r--r--src/qml/jsruntime/qv4vme_moth.cpp5
-rw-r--r--src/qml/jsruntime/qv4vme_moth_p.h1
-rw-r--r--src/qml/memory/qv4mm.cpp2
-rw-r--r--src/qml/parser/parser.pri2
-rw-r--r--src/qml/parser/qqmljs.g245
-rw-r--r--src/qml/parser/qqmljsast.cpp82
-rw-r--r--src/qml/parser/qqmljsast_p.h232
-rw-r--r--src/qml/parser/qqmljsastfwd_p.h3
-rw-r--r--src/qml/parser/qqmljsastvisitor_p.h9
-rw-r--r--src/qml/parser/qqmljsengine_p.h3
-rw-r--r--src/qml/parser/qqmljslexer.cpp2
-rw-r--r--src/qml/qml.pro29
-rw-r--r--src/qml/qml/qml.pri23
-rw-r--r--src/qml/qml/qqmlapplicationengine.cpp1
-rw-r--r--src/qml/qml/qqmlbinding.cpp1
-rw-r--r--src/qml/qml/qqmlbinding_p.h1
-rw-r--r--src/qml/qml/qqmlboundsignal.cpp1
-rw-r--r--src/qml/qml/qqmlcomponent.cpp12
-rw-r--r--src/qml/qml/qqmlcomponent_p.h1
-rw-r--r--src/qml/qml/qqmlcustomparser.cpp2
-rw-r--r--src/qml/qml/qqmlcustomparser_p.h2
-rw-r--r--src/qml/qml/qqmldatablob.cpp639
-rw-r--r--src/qml/qml/qqmldatablob_p.h257
-rw-r--r--src/qml/qml/qqmldelayedcallqueue.cpp1
-rw-r--r--src/qml/qml/qqmldirdata.cpp96
-rw-r--r--src/qml/qml/qqmldirdata_p.h86
-rw-r--r--src/qml/qml/qqmlengine.cpp21
-rw-r--r--src/qml/qml/qqmlengine_p.h1
-rw-r--r--src/qml/qml/qqmlexpression.cpp1
-rw-r--r--src/qml/qml/qqmlimport.cpp1
-rw-r--r--src/qml/qml/qqmlinfo.h1
-rw-r--r--src/qml/qml/qqmlirloader.cpp9
-rw-r--r--src/qml/qml/qqmlmetatype.cpp1
-rw-r--r--src/qml/qml/qqmlobjectcreator.cpp11
-rw-r--r--src/qml/qml/qqmlobjectcreator_p.h3
-rw-r--r--src/qml/qml/qqmlpropertycache.cpp7
-rw-r--r--src/qml/qml/qqmlpropertycache_p.h4
-rw-r--r--src/qml/qml/qqmlpropertycachecreator_p.h84
-rw-r--r--src/qml/qml/qqmlpropertyvalidator.cpp5
-rw-r--r--src/qml/qml/qqmlpropertyvalidator_p.h10
-rw-r--r--src/qml/qml/qqmlscriptblob.cpp263
-rw-r--r--src/qml/qml/qqmlscriptblob_p.h97
-rw-r--r--src/qml/qml/qqmlscriptdata.cpp170
-rw-r--r--src/qml/qml/qqmlscriptdata_p.h108
-rw-r--r--src/qml/qml/qqmltype.cpp1
-rw-r--r--src/qml/qml/qqmltypecompiler.cpp79
-rw-r--r--src/qml/qml/qqmltypecompiler_p.h18
-rw-r--r--src/qml/qml/qqmltypedata.cpp844
-rw-r--r--src/qml/qml/qqmltypedata_p.h163
-rw-r--r--src/qml/qml/qqmltypeloader.cpp2204
-rw-r--r--src/qml/qml/qqmltypeloader_p.h408
-rw-r--r--src/qml/qml/qqmltypeloadernetworkreplyproxy.cpp74
-rw-r--r--src/qml/qml/qqmltypeloadernetworkreplyproxy_p.h86
-rw-r--r--src/qml/qml/qqmltypeloaderqmldircontent.cpp115
-rw-r--r--src/qml/qml/qqmltypeloaderqmldircontent_p.h94
-rw-r--r--src/qml/qml/qqmltypeloaderthread.cpp198
-rw-r--r--src/qml/qml/qqmltypeloaderthread_p.h110
-rw-r--r--src/qml/qml/qqmltypewrapper.cpp1
-rw-r--r--src/qml/qml/qqmlvaluetype.cpp8
-rw-r--r--src/qml/qml/qqmlvmemetaobject.cpp28
-rw-r--r--src/qml/qml/v8/qqmlbuiltinfunctions.cpp1
-rw-r--r--src/qml/qmldirparser/qqmldirparser_p.h4
-rw-r--r--src/qml/qtqmlcompilerglobal.h58
-rw-r--r--src/qml/qtqmlcompilerglobal_p.h59
-rw-r--r--src/qml/types/types.pri13
-rw-r--r--src/qmlmodels/configure.json4
-rw-r--r--src/qmlmodels/qqmladaptormodel.cpp10
-rw-r--r--src/qmlmodels/qqmllistmodel.cpp1
-rw-r--r--src/qmltest/doc/qtqmltest.qdocconf1
-rw-r--r--src/quick/doc/qtquick.qdocconf1
-rw-r--r--src/quick/doc/snippets/qml/qml-extending-types/signals/Button.qml2
-rw-r--r--src/quick/doc/src/concepts/effects/sprites.qdoc2
-rw-r--r--src/quick/items/qquickitemsmodule.cpp2
-rw-r--r--src/quick/scenegraph/qsgopengldistancefieldglyphcache.cpp40
-rw-r--r--src/quick/scenegraph/qsgopengldistancefieldglyphcache_p.h9
-rw-r--r--src/quick/util/qquickpropertychanges.cpp1
140 files changed, 5174 insertions, 3527 deletions
diff --git a/src/imports/imports.pro b/src/imports/imports.pro
index 2ed839a6e0..a87b0a59f6 100644
--- a/src/imports/imports.pro
+++ b/src/imports/imports.pro
@@ -5,9 +5,9 @@ SUBDIRS += \
builtins \
qtqml \
models \
- labsmodels \
- folderlistmodel
+ labsmodels
+qtConfig(qml-itemmodel): SUBDIRS += folderlistmodel
qtConfig(qml-worker-script): SUBDIRS += workerscript
qtHaveModule(sql): SUBDIRS += localstorage
qtConfig(settings): SUBDIRS += settings
diff --git a/src/imports/testlib/main.cpp b/src/imports/testlib/main.cpp
index 7b931c25d2..fbaf3bc4e2 100644
--- a/src/imports/testlib/main.cpp
+++ b/src/imports/testlib/main.cpp
@@ -37,6 +37,7 @@
**
****************************************************************************/
+#include <private/qv4scopedvalue_p.h>
#include <QtQml/qqmlextensionplugin.h>
#include <QtQml/qqml.h>
#include <QtQml/qjsvalue.h>
diff --git a/src/particles/qquickparticlesystem_p.h b/src/particles/qquickparticlesystem_p.h
index 4a9fecb504..1e34086b0c 100644
--- a/src/particles/qquickparticlesystem_p.h
+++ b/src/particles/qquickparticlesystem_p.h
@@ -61,6 +61,7 @@
#include <QtQml/qqml.h>
#include <private/qv4util_p.h>
#include <private/qv4global_p.h>
+#include <private/qv4staticvalue_p.h>
#include "qtquickparticlesglobal_p.h"
QT_BEGIN_NAMESPACE
diff --git a/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewfileloader.cpp b/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewfileloader.cpp
index 9927089e5e..bb43f75c63 100644
--- a/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewfileloader.cpp
+++ b/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewfileloader.cpp
@@ -40,6 +40,8 @@
#include "qqmlpreviewfileloader.h"
#include "qqmlpreviewservice.h"
+#include <QtQml/qqmlfile.h>
+
#include <QtCore/qlibraryinfo.h>
#include <QtCore/qstandardpaths.h>
diff --git a/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewhandler.cpp b/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewhandler.cpp
index 5d2684b510..8bb3b95e48 100644
--- a/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewhandler.cpp
+++ b/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewhandler.cpp
@@ -93,7 +93,9 @@ QQmlPreviewHandler::QQmlPreviewHandler(QObject *parent) : QObject(parent)
QQmlPreviewHandler::~QQmlPreviewHandler()
{
+#if QT_CONFIG(translation)
removeTranslators();
+#endif
clear();
}
@@ -223,6 +225,7 @@ void QQmlPreviewHandler::doZoom()
m_lastPosition.initLastSavedWindowPosition(m_currentWindow);
}
+#if QT_CONFIG(translation)
void QQmlPreviewHandler::removeTranslators()
{
if (!m_qtTranslator.isNull()) {
@@ -255,6 +258,7 @@ void QQmlPreviewHandler::language(const QUrl &context, const QLocale &locale)
for (QQmlEngine *engine : qAsConst(m_engines))
engine->retranslate();
}
+#endif
void QQmlPreviewHandler::clear()
{
diff --git a/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewhandler.h b/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewhandler.h
index 47491b9d8f..f7f343a4ee 100644
--- a/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewhandler.h
+++ b/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewhandler.h
@@ -81,7 +81,9 @@ public:
void loadUrl(const QUrl &url);
void rerun();
void zoom(qreal newFactor);
+#if QT_CONFIG(translation)
void language(const QUrl &context, const QLocale &locale);
+#endif
void clear();
@@ -115,7 +117,9 @@ private:
void frameSwapped();
void fpsTimerHit();
+#if QT_CONFIG(translation)
void removeTranslators();
+#endif
QScopedPointer<QQuickItem> m_dummyItem;
QList<QQmlEngine *> m_engines;
@@ -145,8 +149,10 @@ private:
FrameTime m_rendering;
FrameTime m_synchronizing;
+#if QT_CONFIG(translation)
QScopedPointer<QTranslator> m_qtTranslator;
QScopedPointer<QTranslator> m_qmlTranslator;
+#endif
};
QT_END_NAMESPACE
diff --git a/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewservice.cpp b/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewservice.cpp
index 2e2224df47..2e6aaa5858 100644
--- a/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewservice.cpp
+++ b/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewservice.cpp
@@ -64,7 +64,9 @@ QQmlPreviewServiceImpl::QQmlPreviewServiceImpl(QObject *parent) :
connect(this, &QQmlPreviewServiceImpl::load, &m_handler, &QQmlPreviewHandler::loadUrl);
connect(this, &QQmlPreviewServiceImpl::rerun, &m_handler, &QQmlPreviewHandler::rerun);
connect(this, &QQmlPreviewServiceImpl::zoom, &m_handler, &QQmlPreviewHandler::zoom);
+#if QT_CONFIG(translation)
connect(this, &QQmlPreviewServiceImpl::language, &m_handler, &QQmlPreviewHandler::language);
+#endif
connect(&m_handler, &QQmlPreviewHandler::error, this, &QQmlPreviewServiceImpl::forwardError,
Qt::DirectConnection);
connect(&m_handler, &QQmlPreviewHandler::fps, this, &QQmlPreviewServiceImpl::forwardFps,
@@ -135,6 +137,7 @@ void QQmlPreviewServiceImpl::messageReceived(const QByteArray &data)
emit zoom(static_cast<qreal>(factor));
break;
}
+#if QT_CONFIG(translation)
case Language: {
QUrl context;
QString locale;
@@ -143,6 +146,7 @@ void QQmlPreviewServiceImpl::messageReceived(const QByteArray &data)
locale.isEmpty() ? QLocale() : QLocale(locale));
break;
}
+#endif
default:
forwardError(QString::fromLatin1("Invalid command: %1").arg(command));
break;
diff --git a/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewservice.h b/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewservice.h
index 7bdc87ec59..de50e6fc61 100644
--- a/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewservice.h
+++ b/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewservice.h
@@ -99,7 +99,9 @@ signals:
void rerun();
void clearCache();
void zoom(qreal factor);
+#if QT_CONFIG(translation)
void language(const QUrl &context, const QLocale &locale);
+#endif
private:
QScopedPointer<QQmlPreviewFileEngineHandler> m_fileEngine;
diff --git a/src/qml/common/common.pri b/src/qml/common/common.pri
index de95772120..bcc3ea0fa0 100644
--- a/src/qml/common/common.pri
+++ b/src/qml/common/common.pri
@@ -1,3 +1,35 @@
+!build_pass {
+ # Create a header containing a hash that describes this library. For a
+ # released version of Qt, we'll use the .tag file that is updated by git
+ # archive with the commit hash. For unreleased versions, we'll ask git
+ # describe. Note that it won't update unless qmake is run again, even if
+ # the commit change also changed something in this library.
+ tagFile = $$PWD/../../.tag
+ tag =
+ exists($$tagFile) {
+ tag = $$cat($$tagFile, singleline)
+ QMAKE_INTERNAL_INCLUDED_FILES += $$tagFile
+ }
+ !equals(tag, "$${LITERAL_DOLLAR}Format:%H$${LITERAL_DOLLAR}") {
+ QML_COMPILE_HASH = $$tag
+ } else:exists($$PWD/../../.git) {
+ commit = $$system(git rev-parse HEAD)
+ QML_COMPILE_HASH = $$commit
+ }
+ compile_hash_contents = \
+ "// Generated file, DO NOT EDIT" \
+ "$${LITERAL_HASH}define QML_COMPILE_HASH \"$$QML_COMPILE_HASH\"" \
+ "$${LITERAL_HASH}define QML_COMPILE_HASH_LENGTH $$str_size($$QML_COMPILE_HASH)"
+ write_file("$$OUT_PWD/qml_compile_hash_p.h", compile_hash_contents)|error()
+}
+
HEADERS += \
$$PWD/qqmlapiversion_p.h \
- $$PWD/qqmljsdiagnosticmessage_p.h
+ $$PWD/qqmljsdiagnosticmessage_p.h \
+ $$PWD/qqmljsfixedpoolarray_p.h \
+ $$PWD/qqmljsmemorypool_p.h \
+ $$PWD/qv4alloca_p.h \
+ $$PWD/qv4calldata_p.h \
+ $$PWD/qv4compileddata_p.h \
+ $$PWD/qv4staticvalue_p.h \
+ $$PWD/qv4stringtoarrayindex_p.h
diff --git a/src/qml/common/qqmljsfixedpoolarray_p.h b/src/qml/common/qqmljsfixedpoolarray_p.h
new file mode 100644
index 0000000000..b65b994d6c
--- /dev/null
+++ b/src/qml/common/qqmljsfixedpoolarray_p.h
@@ -0,0 +1,140 @@
+/****************************************************************************
+**
+** 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 QQMLJSFIXEDPOOLARRAY_P_H
+#define QQMLJSFIXEDPOOLARRAY_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 <private/qqmljsmemorypool_p.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace QQmlJS {
+
+template <typename T>
+class FixedPoolArray
+{
+ T *data;
+ int count = 0;
+
+public:
+ FixedPoolArray()
+ : data(nullptr)
+ {}
+
+ FixedPoolArray(MemoryPool *pool, int size)
+ { allocate(pool, size); }
+
+ void allocate(MemoryPool *pool, int size)
+ {
+ count = size;
+ data = reinterpret_cast<T*>(pool->allocate(count * sizeof(T)));
+ }
+
+ void allocate(MemoryPool *pool, const QVector<T> &vector)
+ {
+ count = vector.count();
+ data = reinterpret_cast<T*>(pool->allocate(count * sizeof(T)));
+
+ if (QTypeInfo<T>::isComplex) {
+ for (int i = 0; i < count; ++i)
+ new (data + i) T(vector.at(i));
+ } else {
+ memcpy(data, static_cast<const void*>(vector.constData()), count * sizeof(T));
+ }
+ }
+
+ template <typename Container>
+ void allocate(MemoryPool *pool, const Container &container)
+ {
+ count = container.count();
+ data = reinterpret_cast<T*>(pool->allocate(count * sizeof(T)));
+ typename Container::ConstIterator it = container.constBegin();
+ for (int i = 0; i < count; ++i)
+ new (data + i) T(*it++);
+ }
+
+ int size() const
+ { return count; }
+
+ const T &at(int index) const {
+ Q_ASSERT(index >= 0 && index < count);
+ return data[index];
+ }
+
+ T &at(int index) {
+ Q_ASSERT(index >= 0 && index < count);
+ return data[index];
+ }
+
+ T &operator[](int index) {
+ return at(index);
+ }
+
+
+ int indexOf(const T &value) const {
+ for (int i = 0; i < count; ++i)
+ if (data[i] == value)
+ return i;
+ return -1;
+ }
+
+ const T *begin() const { return data; }
+ const T *end() const { return data + count; }
+
+ T *begin() { return data; }
+ T *end() { return data + count; }
+};
+
+} // namespace QQmlJS
+
+QT_END_NAMESPACE
+
+#endif // QQMLJSFIXEDPOOLARRAY_P_H
diff --git a/src/qml/parser/qqmljsmemorypool_p.h b/src/qml/common/qqmljsmemorypool_p.h
index e7b1f46414..0cf7ea84e6 100644
--- a/src/qml/parser/qqmljsmemorypool_p.h
+++ b/src/qml/common/qqmljsmemorypool_p.h
@@ -51,8 +51,6 @@
// We mean it.
//
-#include "qqmljsglobal_p.h"
-
#include <QtCore/qglobal.h>
#include <QtCore/qshareddata.h>
#include <QtCore/qdebug.h>
@@ -65,7 +63,7 @@ namespace QQmlJS {
class Managed;
-class QML_PARSER_EXPORT MemoryPool : public QSharedData
+class MemoryPool : public QSharedData
{
MemoryPool(const MemoryPool &other);
void operator =(const MemoryPool &other);
@@ -162,7 +160,7 @@ private:
};
};
-class QML_PARSER_EXPORT Managed
+class Managed
{
Q_DISABLE_COPY(Managed)
public:
@@ -174,81 +172,6 @@ public:
void operator delete(void *, MemoryPool *) {}
};
-template <typename T>
-class FixedPoolArray
-{
- T *data;
- int count = 0;
-
-public:
- FixedPoolArray()
- : data(nullptr)
- {}
-
- FixedPoolArray(MemoryPool *pool, int size)
- { allocate(pool, size); }
-
- void allocate(MemoryPool *pool, int size)
- {
- count = size;
- data = reinterpret_cast<T*>(pool->allocate(count * sizeof(T)));
- }
-
- void allocate(MemoryPool *pool, const QVector<T> &vector)
- {
- count = vector.count();
- data = reinterpret_cast<T*>(pool->allocate(count * sizeof(T)));
-
- if (QTypeInfo<T>::isComplex) {
- for (int i = 0; i < count; ++i)
- new (data + i) T(vector.at(i));
- } else {
- memcpy(data, static_cast<const void*>(vector.constData()), count * sizeof(T));
- }
- }
-
- template <typename Container>
- void allocate(MemoryPool *pool, const Container &container)
- {
- count = container.count();
- data = reinterpret_cast<T*>(pool->allocate(count * sizeof(T)));
- typename Container::ConstIterator it = container.constBegin();
- for (int i = 0; i < count; ++i)
- new (data + i) T(*it++);
- }
-
- int size() const
- { return count; }
-
- const T &at(int index) const {
- Q_ASSERT(index >= 0 && index < count);
- return data[index];
- }
-
- T &at(int index) {
- Q_ASSERT(index >= 0 && index < count);
- return data[index];
- }
-
- T &operator[](int index) {
- return at(index);
- }
-
-
- int indexOf(const T &value) const {
- for (int i = 0; i < count; ++i)
- if (data[i] == value)
- return i;
- return -1;
- }
-
- const T *begin() const { return data; }
- const T *end() const { return data + count; }
-
- T *begin() { return data; }
- T *end() { return data + count; }
-};
-
} // namespace QQmlJS
QT_END_NAMESPACE
diff --git a/src/qml/compiler/qv4alloca_p.h b/src/qml/common/qv4alloca_p.h
index 65c3e4d65a..65c3e4d65a 100644
--- a/src/qml/compiler/qv4alloca_p.h
+++ b/src/qml/common/qv4alloca_p.h
diff --git a/src/qml/compiler/qv4calldata_p.h b/src/qml/common/qv4calldata_p.h
index 5a5280cb86..5a5280cb86 100644
--- a/src/qml/compiler/qv4calldata_p.h
+++ b/src/qml/common/qv4calldata_p.h
diff --git a/src/qml/compiler/qv4compileddata_p.h b/src/qml/common/qv4compileddata_p.h
index f3d5de3db1..c3ddce5884 100644
--- a/src/qml/compiler/qv4compileddata_p.h
+++ b/src/qml/common/qv4compileddata_p.h
@@ -50,6 +50,8 @@
// We mean it.
//
+#include <functional>
+
#include <QtCore/qstring.h>
#include <QtCore/qscopeguard.h>
#include <QtCore/qvector.h>
@@ -62,6 +64,7 @@
#include <private/qendian_p.h>
#include <private/qv4staticvalue_p.h>
+#include <functional>
QT_BEGIN_NAMESPACE
@@ -72,12 +75,10 @@ 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 0x23 // Remove trace slots
+#define QV4_DATA_STRUCTURE_VERSION 0x24 // Collect function parameter types
class QIODevice;
-class QQmlPropertyData;
class QQmlTypeNameCache;
-class QQmlScriptData;
class QQmlType;
class QQmlEngine;
@@ -255,6 +256,29 @@ struct Block
};
static_assert(sizeof(Block) == 12, "Block structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target");
+enum class BuiltinType : unsigned int {
+ Var = 0, Variant, Int, Bool, Real, String, Url, Color,
+ Font, Time, Date, DateTime, Rect, Point, Size,
+ Vector2D, Vector3D, Vector4D, Matrix4x4, Quaternion, InvalidBuiltin
+};
+
+struct ParameterType
+{
+ union {
+ quint32 _dummy;
+ quint32_le_bitfield<0, 1> indexIsBuiltinType;
+ quint32_le_bitfield<1, 31> typeNameIndexOrBuiltinType;
+ };
+};
+static_assert(sizeof(ParameterType) == 4, "ParameterType structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target");
+
+struct Parameter
+{
+ quint32_le nameIndex;
+ ParameterType type;
+};
+static_assert(sizeof(Parameter) == 8, "Parameter structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target");
+
// Function is aligned on an 8-byte boundary to make sure there are no bus errors or penalties
// for unaligned access. The ordering of the fields is also from largest to smallest.
struct Function
@@ -273,6 +297,7 @@ struct Function
quint16_le length;
quint16_le nFormals;
quint32_le formalsOffset; // Can't turn this into a calculated offset because of the mutation in CompilationUnit::createUnitData.
+ ParameterType returnType;
quint32_le localsOffset;
quint16_le nLocals;
quint16_le nLineNumbers;
@@ -294,13 +319,13 @@ struct Function
// quint32 formalsIndex[nFormals]
// quint32 localsIndex[nLocals]
- const quint32_le *formalsTable() const { return reinterpret_cast<const quint32_le *>(reinterpret_cast<const char *>(this) + formalsOffset); }
+ const Parameter *formalsTable() const { return reinterpret_cast<const Parameter *>(reinterpret_cast<const char *>(this) + formalsOffset); }
const quint32_le *localsTable() const { return reinterpret_cast<const quint32_le *>(reinterpret_cast<const char *>(this) + localsOffset); }
const CodeOffsetToLine *lineNumberTable() const { return reinterpret_cast<const CodeOffsetToLine *>(reinterpret_cast<const char *>(this) + lineNumberOffset()); }
// --- QQmlPropertyCacheCreator interface
- const quint32_le *formalsBegin() const { return formalsTable(); }
- const quint32_le *formalsEnd() const { return formalsTable() + nFormals; }
+ const Parameter *formalsBegin() const { return formalsTable(); }
+ const Parameter *formalsEnd() const { return formalsTable() + nFormals; }
// ---
const quint32_le *labelInfoTable() const { return reinterpret_cast<const quint32_le *>(reinterpret_cast<const char *>(this) + labelInfosOffset()); }
@@ -308,7 +333,7 @@ struct Function
const char *code() const { return reinterpret_cast<const char *>(this) + codeOffset; }
static int calculateSize(int nFormals, int nLocals, int nLines, int nInnerfunctions, int labelInfoSize, int codeSize) {
- int trailingData = (nFormals + nLocals + nInnerfunctions + labelInfoSize)*sizeof (quint32)
+ int trailingData = nFormals * sizeof(Parameter) + (nLocals + nInnerfunctions + labelInfoSize)*sizeof (quint32)
+ nLines*sizeof(CodeOffsetToLine);
size_t size = align(align(sizeof(Function)) + size_t(trailingData)) + align(codeSize);
Q_ASSERT(size < INT_MAX);
@@ -319,7 +344,7 @@ struct Function
return (a + 7) & ~size_t(7);
}
};
-static_assert(sizeof(Function) == 52, "Function structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target");
+static_assert(sizeof(Function) == 56, "Function structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target");
struct Method {
enum Type {
@@ -602,23 +627,6 @@ struct Enum
};
static_assert(sizeof(Enum) == 12, "Enum structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target");
-enum class BuiltinType : unsigned int {
- Var = 0, Variant, Int, Bool, Real, String, Url, Color,
- Font, Time, Date, DateTime, Rect, Point, Size,
- Vector2D, Vector3D, Vector4D, Matrix4x4, Quaternion, InvalidBuiltin
-};
-
-struct Parameter
-{
- quint32_le nameIndex;
- union {
- quint32 _dummy;
- quint32_le_bitfield<0, 1> indexIsBuiltinType;
- quint32_le_bitfield<1, 31> typeNameIndexOrBuiltinType;
- };
-};
-static_assert(sizeof(Parameter) == 8, "Parameter structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target");
-
struct Signal
{
quint32_le nameIndex;
@@ -1087,9 +1095,6 @@ struct TypeReferenceMap : QHash<int, TypeReference>
using DependentTypesHasher = std::function<QByteArray()>;
-// index is per-object binding index
-typedef QVector<QQmlPropertyData*> BindingPropertyData;
-
// This is how this hooks into the existing structures:
struct CompilationUnitBase
@@ -1119,10 +1124,10 @@ struct CompilationUnitBase
}
// pointers either to data->constants() or little-endian memory copy.
- QV4::Heap::String **runtimeStrings = nullptr; // Array
+ Heap::String **runtimeStrings = nullptr; // Array
const StaticValue* constants = nullptr;
QV4::StaticValue *runtimeRegularExpressions = nullptr;
- QV4::Heap::InternalClass **runtimeClasses = nullptr;
+ Heap::InternalClass **runtimeClasses = nullptr;
const StaticValue** imports = nullptr;
};
diff --git a/src/qml/compiler/qv4staticvalue_p.h b/src/qml/common/qv4staticvalue_p.h
index c6b4bdb158..8160bbb748 100644
--- a/src/qml/compiler/qv4staticvalue_p.h
+++ b/src/qml/common/qv4staticvalue_p.h
@@ -50,14 +50,24 @@
// We mean it.
//
-#include <QtQml/private/qtqmlglobal_p.h>
-#include <QtQml/private/qv4global_p.h>
#include <QtCore/private/qnumeric_p.h>
+#ifdef QT_NO_DEBUG
+#define QV4_NEARLY_ALWAYS_INLINE Q_ALWAYS_INLINE
+#else
+#define QV4_NEARLY_ALWAYS_INLINE inline
+#endif
+
QT_BEGIN_NAMESPACE
namespace QV4 {
+// ReturnedValue is used to return values from runtime methods
+// the type has to be a primitive type (no struct or union), so that the compiler
+// will return it in a register on all platforms.
+// It will be returned in rax on x64, [eax,edx] on x86 and [r0,r1] on arm
+typedef quint64 ReturnedValue;
+
struct Double {
quint64 d;
@@ -105,7 +115,7 @@ struct Double {
}
};
-struct Q_QML_PRIVATE_EXPORT StaticValue
+struct StaticValue
{
StaticValue() = default;
constexpr StaticValue(quint64 val) : _val(val) {}
@@ -180,9 +190,9 @@ struct Q_QML_PRIVATE_EXPORT StaticValue
quint64 _val;
- QML_NEARLY_ALWAYS_INLINE Q_DECL_RELAXED_CONSTEXPR quint64 &rawValueRef() { return _val; }
- QML_NEARLY_ALWAYS_INLINE Q_DECL_RELAXED_CONSTEXPR quint64 rawValue() const { return _val; }
- QML_NEARLY_ALWAYS_INLINE Q_DECL_RELAXED_CONSTEXPR void setRawValue(quint64 raw) { _val = raw; }
+ QV4_NEARLY_ALWAYS_INLINE Q_DECL_RELAXED_CONSTEXPR quint64 &rawValueRef() { return _val; }
+ QV4_NEARLY_ALWAYS_INLINE Q_DECL_RELAXED_CONSTEXPR quint64 rawValue() const { return _val; }
+ QV4_NEARLY_ALWAYS_INLINE Q_DECL_RELAXED_CONSTEXPR void setRawValue(quint64 raw) { _val = raw; }
#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
static inline int valueOffset() { return 0; }
@@ -192,22 +202,22 @@ struct Q_QML_PRIVATE_EXPORT StaticValue
static inline int tagOffset() { return 0; }
#endif
static inline constexpr quint64 tagValue(quint32 tag, quint32 value) { return quint64(tag) << 32 | value; }
- QML_NEARLY_ALWAYS_INLINE Q_DECL_RELAXED_CONSTEXPR void setTagValue(quint32 tag, quint32 value) { _val = quint64(tag) << 32 | value; }
- QML_NEARLY_ALWAYS_INLINE constexpr quint32 value() const { return _val & quint64(~quint32(0)); }
- QML_NEARLY_ALWAYS_INLINE constexpr quint32 tag() const { return _val >> 32; }
- QML_NEARLY_ALWAYS_INLINE Q_DECL_RELAXED_CONSTEXPR void setTag(quint32 tag) { setTagValue(tag, value()); }
+ QV4_NEARLY_ALWAYS_INLINE Q_DECL_RELAXED_CONSTEXPR void setTagValue(quint32 tag, quint32 value) { _val = quint64(tag) << 32 | value; }
+ QV4_NEARLY_ALWAYS_INLINE constexpr quint32 value() const { return _val & quint64(~quint32(0)); }
+ QV4_NEARLY_ALWAYS_INLINE constexpr quint32 tag() const { return _val >> 32; }
+ QV4_NEARLY_ALWAYS_INLINE Q_DECL_RELAXED_CONSTEXPR void setTag(quint32 tag) { setTagValue(tag, value()); }
- QML_NEARLY_ALWAYS_INLINE constexpr int int_32() const
+ QV4_NEARLY_ALWAYS_INLINE constexpr int int_32() const
{
return int(value());
}
- QML_NEARLY_ALWAYS_INLINE Q_DECL_RELAXED_CONSTEXPR void setInt_32(int i)
+ QV4_NEARLY_ALWAYS_INLINE Q_DECL_RELAXED_CONSTEXPR void setInt_32(int i)
{
setTagValue(quint32(ValueTypeInternal::Integer), quint32(i));
}
- QML_NEARLY_ALWAYS_INLINE uint uint_32() const { return value(); }
+ QV4_NEARLY_ALWAYS_INLINE uint uint_32() const { return value(); }
- QML_NEARLY_ALWAYS_INLINE Q_DECL_RELAXED_CONSTEXPR void setEmpty()
+ QV4_NEARLY_ALWAYS_INLINE Q_DECL_RELAXED_CONSTEXPR void setEmpty()
{
setTagValue(quint32(ValueTypeInternal::Empty), 0);
}
@@ -353,7 +363,7 @@ struct Q_QML_PRIVATE_EXPORT StaticValue
#endif
}
- QML_NEARLY_ALWAYS_INLINE double doubleValue() const {
+ QV4_NEARLY_ALWAYS_INLINE double doubleValue() const {
Q_ASSERT(isDouble());
double d;
StaticValue v = *this;
@@ -362,7 +372,7 @@ struct Q_QML_PRIVATE_EXPORT StaticValue
return d;
}
- QML_NEARLY_ALWAYS_INLINE void setDouble(double d) {
+ QV4_NEARLY_ALWAYS_INLINE void setDouble(double d) {
if (qt_is_nan(d))
d = qt_qnan();
memcpy(&_val, &d, 8);
@@ -383,7 +393,7 @@ struct Q_QML_PRIVATE_EXPORT StaticValue
return false;
}
- QML_NEARLY_ALWAYS_INLINE static bool isInt32(double d) {
+ QV4_NEARLY_ALWAYS_INLINE static bool isInt32(double d) {
int i = int(d);
return (i == d && !(d == 0 && std::signbit(d)));
}
diff --git a/src/qml/compiler/qv4stringtoarrayindex_p.h b/src/qml/common/qv4stringtoarrayindex_p.h
index 61bd988d1e..61bd988d1e 100644
--- a/src/qml/compiler/qv4stringtoarrayindex_p.h
+++ b/src/qml/common/qv4stringtoarrayindex_p.h
diff --git a/src/qml/compiler/compiler.pri b/src/qml/compiler/compiler.pri
index c6ae8c6b69..4d6926d420 100644
--- a/src/qml/compiler/compiler.pri
+++ b/src/qml/compiler/compiler.pri
@@ -2,21 +2,17 @@ INCLUDEPATH += $$PWD
INCLUDEPATH += $$OUT_PWD
HEADERS += \
- $$PWD/qv4alloca_p.h \
$$PWD/qv4bytecodegenerator_p.h \
- $$PWD/qv4compileddata_p.h \
$$PWD/qv4compiler_p.h \
$$PWD/qv4compilercontext_p.h \
$$PWD/qv4compilercontrolflow_p.h \
+ $$PWD/qv4compilerglobal_p.h \
$$PWD/qv4compilerscanfunctions_p.h \
$$PWD/qv4codegen_p.h \
$$PWD/qqmlirbuilder_p.h \
$$PWD/qv4instr_moth_p.h \
$$PWD/qv4bytecodehandler_p.h \
- $$PWD/qv4calldata_p.h \
- $$PWD/qv4util_p.h \
- $$PWD/qv4staticvalue_p.h \
- $$PWD/qv4stringtoarrayindex_p.h
+ $$PWD/qv4util_p.h
SOURCES += \
$$PWD/qv4bytecodegenerator.cpp \
diff --git a/src/qml/compiler/qqmlirbuilder.cpp b/src/qml/compiler/qqmlirbuilder.cpp
index 1891f31f13..aab3f8e9d6 100644
--- a/src/qml/compiler/qqmlirbuilder.cpp
+++ b/src/qml/compiler/qqmlirbuilder.cpp
@@ -56,6 +56,7 @@ QT_USE_NAMESPACE
static const quint32 emptyStringIndex = 0;
using namespace QmlIR;
+using namespace QQmlJS;
#define COMPILE_EXCEPTION(location, desc) \
{ \
@@ -63,6 +64,84 @@ using namespace QmlIR;
return false; \
}
+bool Parameter::init(QV4::Compiler::JSUnitGenerator *stringGenerator, const QString &parameterName,
+ const QString &typeName)
+{
+ return init(this, stringGenerator, stringGenerator->registerString(parameterName), stringGenerator->registerString(typeName));
+}
+
+bool Parameter::init(QV4::CompiledData::Parameter *param, const QV4::Compiler::JSUnitGenerator *stringGenerator,
+ int parameterNameIndex, int typeNameIndex)
+{
+ param->nameIndex = parameterNameIndex;
+ return initType(&param->type, stringGenerator, typeNameIndex);
+}
+
+bool Parameter::initType(QV4::CompiledData::ParameterType *paramType, const QV4::Compiler::JSUnitGenerator *stringGenerator, int typeNameIndex)
+{
+ paramType->indexIsBuiltinType = false;
+ paramType->typeNameIndexOrBuiltinType = 0;
+ const QString typeName = stringGenerator->stringForIndex(typeNameIndex);
+ auto builtinType = stringToBuiltinType(typeName);
+ if (builtinType == QV4::CompiledData::BuiltinType::InvalidBuiltin) {
+ if (typeName.isEmpty() || !typeName.at(0).isUpper())
+ return false;
+ paramType->indexIsBuiltinType = false;
+ paramType->typeNameIndexOrBuiltinType = typeNameIndex;
+ Q_ASSERT(quint32(typeNameIndex) < (1u << 31));
+ } else {
+ paramType->indexIsBuiltinType = true;
+ paramType->typeNameIndexOrBuiltinType = static_cast<quint32>(builtinType);
+ Q_ASSERT(quint32(builtinType) < (1u << 31));
+ }
+ return true;
+}
+
+QV4::CompiledData::BuiltinType Parameter::stringToBuiltinType(const QString &typeName)
+{
+ static const struct TypeNameToType {
+ const char *name;
+ size_t nameLength;
+ QV4::CompiledData::BuiltinType type;
+ } propTypeNameToTypes[] = {
+ { "int", strlen("int"), QV4::CompiledData::BuiltinType::Int },
+ { "bool", strlen("bool"), QV4::CompiledData::BuiltinType::Bool },
+ { "double", strlen("double"), QV4::CompiledData::BuiltinType::Real },
+ { "real", strlen("real"), QV4::CompiledData::BuiltinType::Real },
+ { "string", strlen("string"), QV4::CompiledData::BuiltinType::String },
+ { "url", strlen("url"), QV4::CompiledData::BuiltinType::Url },
+ { "color", strlen("color"), QV4::CompiledData::BuiltinType::Color },
+ // Internally QTime, QDate and QDateTime are all supported.
+ // To be more consistent with JavaScript we expose only
+ // QDateTime as it matches closely with the Date JS type.
+ // We also call it "date" to match.
+ // { "time", strlen("time"), Property::Time },
+ // { "date", strlen("date"), Property::Date },
+ { "date", strlen("date"), QV4::CompiledData::BuiltinType::DateTime },
+ { "rect", strlen("rect"), QV4::CompiledData::BuiltinType::Rect },
+ { "point", strlen("point"), QV4::CompiledData::BuiltinType::Point },
+ { "size", strlen("size"), QV4::CompiledData::BuiltinType::Size },
+ { "font", strlen("font"), QV4::CompiledData::BuiltinType::Font },
+ { "vector2d", strlen("vector2d"), QV4::CompiledData::BuiltinType::Vector2D },
+ { "vector3d", strlen("vector3d"), QV4::CompiledData::BuiltinType::Vector3D },
+ { "vector4d", strlen("vector4d"), QV4::CompiledData::BuiltinType::Vector4D },
+ { "quaternion", strlen("quaternion"), QV4::CompiledData::BuiltinType::Quaternion },
+ { "matrix4x4", strlen("matrix4x4"), QV4::CompiledData::BuiltinType::Matrix4x4 },
+ { "variant", strlen("variant"), QV4::CompiledData::BuiltinType::Variant },
+ { "var", strlen("var"), QV4::CompiledData::BuiltinType::Var }
+ };
+ static const int propTypeNameToTypesCount = sizeof(propTypeNameToTypes) /
+ sizeof(propTypeNameToTypes[0]);
+
+ for (int typeIndex = 0; typeIndex < propTypeNameToTypesCount; ++typeIndex) {
+ const TypeNameToType *t = propTypeNameToTypes + typeIndex;
+ if (typeName == QLatin1String(t->name, static_cast<int>(t->nameLength))) {
+ return t->type;
+ }
+ }
+ return QV4::CompiledData::BuiltinType::InvalidBuiltin;
+}
+
void Object::init(QQmlJS::MemoryPool *pool, int typeNameIndex, int idIndex, const QQmlJS::AST::SourceLocation &loc)
{
inheritedTypeNameIndex = typeNameIndex;
@@ -247,64 +326,11 @@ QStringList Signal::parameterStringList(const QV4::Compiler::StringTableGenerato
{
QStringList result;
result.reserve(parameters->count);
- for (SignalParameter *param = parameters->first; param; param = param->next)
+ for (Parameter *param = parameters->first; param; param = param->next)
result << stringPool->stringForIndex(param->nameIndex);
return result;
}
-static void replaceWithSpace(QString &str, int idx, int n)
-{
- QChar *data = str.data() + idx;
- const QChar space(QLatin1Char(' '));
- for (int ii = 0; ii < n; ++ii)
- *data++ = space;
-}
-
-void Document::removeScriptPragmas(QString &script)
-{
- const QLatin1String pragma("pragma");
- const QLatin1String library("library");
-
- QQmlJS::Lexer l(nullptr);
- l.setCode(script, 0);
-
- int token = l.lex();
-
- while (true) {
- if (token != QQmlJSGrammar::T_DOT)
- return;
-
- int startOffset = l.tokenOffset();
- int startLine = l.tokenStartLine();
-
- token = l.lex();
-
- if (token != QQmlJSGrammar::T_PRAGMA ||
- l.tokenStartLine() != startLine ||
- script.midRef(l.tokenOffset(), l.tokenLength()) != pragma)
- return;
-
- token = l.lex();
-
- if (token != QQmlJSGrammar::T_IDENTIFIER ||
- l.tokenStartLine() != startLine)
- return;
-
- const QStringRef pragmaValue = script.midRef(l.tokenOffset(), l.tokenLength());
- int endOffset = l.tokenLength() + l.tokenOffset();
-
- token = l.lex();
- if (l.tokenStartLine() == startLine)
- return;
-
- if (pragmaValue == library) {
- replaceWithSpace(script, startOffset, endOffset - startOffset);
- } else {
- return;
- }
- }
-}
-
Document::Document(bool debugMode)
: jsModule(debugMode)
, program(nullptr)
@@ -764,40 +790,6 @@ bool IRBuilder::visit(QQmlJS::AST::UiEnumDeclaration *node)
bool IRBuilder::visit(QQmlJS::AST::UiPublicMember *node)
{
- static const struct TypeNameToType {
- const char *name;
- size_t nameLength;
- QV4::CompiledData::BuiltinType type;
- } propTypeNameToTypes[] = {
- { "int", strlen("int"), QV4::CompiledData::BuiltinType::Int },
- { "bool", strlen("bool"), QV4::CompiledData::BuiltinType::Bool },
- { "double", strlen("double"), QV4::CompiledData::BuiltinType::Real },
- { "real", strlen("real"), QV4::CompiledData::BuiltinType::Real },
- { "string", strlen("string"), QV4::CompiledData::BuiltinType::String },
- { "url", strlen("url"), QV4::CompiledData::BuiltinType::Url },
- { "color", strlen("color"), QV4::CompiledData::BuiltinType::Color },
- // Internally QTime, QDate and QDateTime are all supported.
- // To be more consistent with JavaScript we expose only
- // QDateTime as it matches closely with the Date JS type.
- // We also call it "date" to match.
- // { "time", strlen("time"), Property::Time },
- // { "date", strlen("date"), Property::Date },
- { "date", strlen("date"), QV4::CompiledData::BuiltinType::DateTime },
- { "rect", strlen("rect"), QV4::CompiledData::BuiltinType::Rect },
- { "point", strlen("point"), QV4::CompiledData::BuiltinType::Point },
- { "size", strlen("size"), QV4::CompiledData::BuiltinType::Size },
- { "font", strlen("font"), QV4::CompiledData::BuiltinType::Font },
- { "vector2d", strlen("vector2d"), QV4::CompiledData::BuiltinType::Vector2D },
- { "vector3d", strlen("vector3d"), QV4::CompiledData::BuiltinType::Vector3D },
- { "vector4d", strlen("vector4d"), QV4::CompiledData::BuiltinType::Vector4D },
- { "quaternion", strlen("quaternion"), QV4::CompiledData::BuiltinType::Quaternion },
- { "matrix4x4", strlen("matrix4x4"), QV4::CompiledData::BuiltinType::Matrix4x4 },
- { "variant", strlen("variant"), QV4::CompiledData::BuiltinType::Variant },
- { "var", strlen("var"), QV4::CompiledData::BuiltinType::Var }
- };
- static const int propTypeNameToTypesCount = sizeof(propTypeNameToTypes) /
- sizeof(propTypeNameToTypes[0]);
-
if (node->type == QQmlJS::AST::UiPublicMember::Signal) {
Signal *signal = New<Signal>();
QString signalName = node->name.toString();
@@ -807,7 +799,7 @@ bool IRBuilder::visit(QQmlJS::AST::UiPublicMember *node)
signal->location.line = loc.startLine;
signal->location.column = loc.startColumn;
- signal->parameters = New<PoolList<SignalParameter> >();
+ signal->parameters = New<PoolList<Parameter> >();
QQmlJS::AST::UiParameterList *p = node->parameters;
while (p) {
@@ -818,38 +810,13 @@ bool IRBuilder::visit(QQmlJS::AST::UiPublicMember *node)
return false;
}
- const TypeNameToType *type = nullptr;
- for (int typeIndex = 0; typeIndex < propTypeNameToTypesCount; ++typeIndex) {
- const TypeNameToType *t = propTypeNameToTypes + typeIndex;
- if (memberType == QLatin1String(t->name, static_cast<int>(t->nameLength))) {
- type = t;
- break;
- }
- }
-
- SignalParameter *param = New<SignalParameter>();
-
- if (!type) {
- if (memberType.at(0).isUpper()) {
- // Must be a QML object type.
- // Lazily determine type during compilation.
- param->indexIsBuiltinType = false;
- param->typeNameIndexOrBuiltinType = registerString(memberType);
- Q_ASSERT(quint32(jsGenerator->getStringId(memberType)) < (1u << 31));
- } else {
- QString errStr = QCoreApplication::translate("QQmlParser","Invalid signal parameter type: ");
- errStr.append(memberType);
- recordError(node->typeToken, errStr);
- return false;
- }
- } else {
- // the parameter is a known basic type
- param->indexIsBuiltinType = true;
- param->typeNameIndexOrBuiltinType = static_cast<quint32>(type->type);
- Q_ASSERT(quint32(type->type) < (1u << 31));
+ Parameter *param = New<Parameter>();
+ if (!param->init(jsGenerator, p->name.toString(), memberType)) {
+ QString errStr = QCoreApplication::translate("QQmlParser","Invalid signal parameter type: ");
+ errStr.append(memberType);
+ recordError(node->typeToken, errStr);
+ return false;
}
-
- param->nameIndex = registerString(p->name.toString());
signal->parameters->append(param);
p = p->next;
}
@@ -875,15 +842,10 @@ bool IRBuilder::visit(QQmlJS::AST::UiPublicMember *node)
Property *property = New<Property>();
property->isReadOnly = node->isReadonlyMember;
- bool typeFound = false;
-
- for (int ii = 0; !typeFound && ii < propTypeNameToTypesCount; ++ii) {
- const TypeNameToType *t = propTypeNameToTypes + ii;
- if (memberType == QLatin1String(t->name, static_cast<int>(t->nameLength))) {
- property->setBuiltinType(t->type);
- typeFound = true;
- }
- }
+ QV4::CompiledData::BuiltinType builtinPropertyType = Parameter::stringToBuiltinType(memberType);
+ bool typeFound = builtinPropertyType != QV4::CompiledData::BuiltinType::InvalidBuiltin;
+ if (typeFound)
+ property->setBuiltinType(builtinPropertyType);
if (!typeFound && memberType.at(0).isUpper()) {
const QStringRef &typeModifier = node->typeModifier;
@@ -960,13 +922,16 @@ bool IRBuilder::visit(QQmlJS::AST::UiSourceElement *node)
f->index = index;
f->nameIndex = registerString(funDecl->name.toString());
- const QStringList formals = funDecl->formals ? funDecl->formals->formals() : QStringList();
+ QString returnTypeName = funDecl->typeAnnotation ? funDecl->typeAnnotation->type->toString() : QString();
+ Parameter::initType(&f->returnType, jsGenerator, registerString(returnTypeName));
+
+ const QQmlJS::AST::BoundNames formals = funDecl->formals ? funDecl->formals->formals() : QQmlJS::AST::BoundNames();
int formalsCount = formals.size();
f->formals.allocate(pool, formalsCount);
int i = 0;
- for (const QString &arg : formals) {
- f->formals[i] = registerString(arg);
+ for (const auto &arg : formals) {
+ f->formals[i].init(jsGenerator, arg.id, arg.typeName());
++i;
}
@@ -1696,7 +1661,7 @@ void QmlUnitGenerator::generate(Document &output, const QV4::CompiledData::Depen
signalToWrite->nParameters = s->parameters->count;
QV4::CompiledData::Parameter *parameterToWrite = reinterpret_cast<QV4::CompiledData::Parameter*>(signalPtr + sizeof(*signalToWrite));
- for (SignalParameter *param = s->parameters->first; param; param = param->next, ++parameterToWrite)
+ for (Parameter *param = s->parameters->first; param; param = param->next, ++parameterToWrite)
*parameterToWrite = *param;
int size = QV4::CompiledData::Signal::calculateSize(s->parameters->count);
@@ -1782,19 +1747,11 @@ char *QmlUnitGenerator::writeBindings(char *bindingPtr, const Object *o, Binding
return bindingPtr;
}
-JSCodeGen::JSCodeGen(const QString &sourceCode, QV4::Compiler::JSUnitGenerator *jsUnitGenerator,
- QV4::Compiler::Module *jsModule, QQmlJS::Engine *jsEngine,
- QQmlJS::AST::UiProgram *qmlRoot,
- const QV4::Compiler::StringTableGenerator *stringPool, const QSet<QString> &globalNames)
- : QV4::Compiler::Codegen(jsUnitGenerator, /*strict mode*/false)
- , sourceCode(sourceCode)
- , jsEngine(jsEngine)
- , qmlRoot(qmlRoot)
- , stringPool(stringPool)
+JSCodeGen::JSCodeGen(Document *document, const QSet<QString> &globalNames)
+ : QV4::Compiler::Codegen(&document->jsGenerator, /*strict mode*/false), document(document)
{
m_globalNames = globalNames;
-
- _module = jsModule;
+ _module = &document->jsModule;
_fileNameIsUrl = true;
}
@@ -1802,17 +1759,17 @@ QVector<int> JSCodeGen::generateJSCodeForFunctionsAndBindings(const QList<Compil
{
auto qmlName = [&](const CompiledFunctionOrExpression &c) {
if (c.nameIndex != 0)
- return stringPool->stringForIndex(c.nameIndex);
+ return document->stringAt(c.nameIndex);
else
return QStringLiteral("%qml-expression-entry");
};
QVector<int> runtimeFunctionIndices(functions.size());
- QV4::Compiler::ScanFunctions scan(this, sourceCode, QV4::Compiler::ContextType::Global);
+ QV4::Compiler::ScanFunctions scan(this, document->code, QV4::Compiler::ContextType::Global);
scan.enterGlobalEnvironment(QV4::Compiler::ContextType::Binding);
for (const CompiledFunctionOrExpression &f : functions) {
- Q_ASSERT(f.node != qmlRoot);
- Q_ASSERT(f.parentNode && f.parentNode != qmlRoot);
+ Q_ASSERT(f.node != document->program);
+ Q_ASSERT(f.parentNode && f.parentNode != document->program);
QQmlJS::AST::FunctionDeclaration *function = QQmlJS::AST::cast<QQmlJS::AST::FunctionDeclaration*>(f.node);
if (function) {
@@ -1835,7 +1792,7 @@ QVector<int> JSCodeGen::generateJSCodeForFunctionsAndBindings(const QList<Compil
for (int i = 0; i < functions.count(); ++i) {
const CompiledFunctionOrExpression &qmlFunction = functions.at(i);
QQmlJS::AST::Node *node = qmlFunction.node;
- Q_ASSERT(node != qmlRoot);
+ Q_ASSERT(node != document->program);
QQmlJS::AST::FunctionDeclaration *function = QQmlJS::AST::cast<QQmlJS::AST::FunctionDeclaration*>(node);
@@ -1850,7 +1807,7 @@ QVector<int> JSCodeGen::generateJSCodeForFunctionsAndBindings(const QList<Compil
body = function->body;
} else {
// Synthesize source elements.
- QQmlJS::MemoryPool *pool = jsEngine->pool();
+ QQmlJS::MemoryPool *pool = document->jsParserEngine.pool();
QQmlJS::AST::Statement *stmt = node->statementCast();
if (!stmt) {
@@ -1870,3 +1827,58 @@ QVector<int> JSCodeGen::generateJSCodeForFunctionsAndBindings(const QList<Compil
return runtimeFunctionIndices;
}
+
+bool JSCodeGen::generateCodeForComponents(const QVector<quint32> &componentRoots)
+{
+ for (int i = 0; i < componentRoots.count(); ++i) {
+ if (!compileComponent(componentRoots.at(i)))
+ return false;
+ }
+
+ return compileComponent(/*root object*/0);
+}
+
+bool JSCodeGen::compileComponent(int contextObject)
+{
+ const QmlIR::Object *obj = document->objects.at(contextObject);
+ if (obj->flags & QV4::CompiledData::Object::IsComponent) {
+ Q_ASSERT(obj->bindingCount() == 1);
+ const QV4::CompiledData::Binding *componentBinding = obj->firstBinding();
+ Q_ASSERT(componentBinding->type == QV4::CompiledData::Binding::Type_Object);
+ contextObject = componentBinding->value.objectIndex;
+ }
+
+ return compileJavaScriptCodeInObjectsRecursively(contextObject, contextObject);
+}
+
+bool JSCodeGen::compileJavaScriptCodeInObjectsRecursively(int objectIndex, int scopeObjectIndex)
+{
+ QmlIR::Object *object = document->objects.at(objectIndex);
+ if (object->flags & QV4::CompiledData::Object::IsComponent)
+ return true;
+
+ if (object->functionsAndExpressions->count > 0) {
+ QList<QmlIR::CompiledFunctionOrExpression> functionsToCompile;
+ for (QmlIR::CompiledFunctionOrExpression *foe = object->functionsAndExpressions->first; foe; foe = foe->next)
+ functionsToCompile << *foe;
+ const QVector<int> runtimeFunctionIndices = generateJSCodeForFunctionsAndBindings(functionsToCompile);
+ if (hasError())
+ return false;
+
+ object->runtimeFunctionIndices.allocate(document->jsParserEngine.pool(),
+ runtimeFunctionIndices);
+ }
+
+ for (const QmlIR::Binding *binding = object->firstBinding(); binding; binding = binding->next) {
+ if (binding->type < QV4::CompiledData::Binding::Type_Object)
+ continue;
+
+ int target = binding->value.objectIndex;
+ int scope = binding->type == QV4::CompiledData::Binding::Type_Object ? target : scopeObjectIndex;
+
+ if (!compileJavaScriptCodeInObjectsRecursively(binding->value.objectIndex, scope))
+ return false;
+ }
+
+ return true;
+}
diff --git a/src/qml/compiler/qqmlirbuilder_p.h b/src/qml/compiler/qqmlirbuilder_p.h
index 64298466e0..c366c8e459 100644
--- a/src/qml/compiler/qqmlirbuilder_p.h
+++ b/src/qml/compiler/qqmlirbuilder_p.h
@@ -55,6 +55,7 @@
#include <private/qv4compiler_p.h>
#include <private/qv4compileddata_p.h>
#include <private/qqmljsmemorypool_p.h>
+#include <private/qqmljsfixedpoolarray_p.h>
#include <private/qv4codegen_p.h>
#include <private/qv4compiler_p.h>
#include <QTextStream>
@@ -215,22 +216,30 @@ struct Enum
};
-struct SignalParameter : public QV4::CompiledData::Parameter
+struct Parameter : public QV4::CompiledData::Parameter
{
- SignalParameter *next;
+ Parameter *next;
+
+ bool init(QV4::Compiler::JSUnitGenerator *stringGenerator, const QString &parameterName, const QString &typeName);
+ static bool init(QV4::CompiledData::Parameter *param, const QV4::Compiler::JSUnitGenerator *stringGenerator,
+ int parameterNameIndex, int typeNameIndex);
+ static bool initType(QV4::CompiledData::ParameterType *paramType,
+ const QV4::Compiler::JSUnitGenerator *stringGenerator, int typeNameIndex);
+
+ static QV4::CompiledData::BuiltinType stringToBuiltinType(const QString &typeName);
};
struct Signal
{
int nameIndex;
QV4::CompiledData::Location location;
- PoolList<SignalParameter> *parameters;
+ PoolList<Parameter> *parameters;
QStringList parameterStringList(const QV4::Compiler::StringTableGenerator *stringPool) const;
int parameterCount() const { return parameters->count; }
- PoolList<SignalParameter>::Iterator parametersBegin() const { return parameters->begin(); }
- PoolList<SignalParameter>::Iterator parametersEnd() const { return parameters->end(); }
+ PoolList<Parameter>::Iterator parametersBegin() const { return parameters->begin(); }
+ PoolList<Parameter>::Iterator parametersEnd() const { return parameters->end(); }
Signal *next;
};
@@ -260,17 +269,18 @@ struct Function
QV4::CompiledData::Location location;
int nameIndex;
quint32 index; // index in parsedQML::functions
- FixedPoolArray<int> formals;
+ QQmlJS::FixedPoolArray<Parameter> formals;
+ QV4::CompiledData::ParameterType returnType;
// --- QQmlPropertyCacheCreator interface
- const int *formalsBegin() const { return formals.begin(); }
- const int *formalsEnd() const { return formals.end(); }
+ const Parameter *formalsBegin() const { return formals.begin(); }
+ const Parameter *formalsEnd() const { return formals.end(); }
// ---
Function *next;
};
-struct Q_QML_PRIVATE_EXPORT CompiledFunctionOrExpression
+struct Q_QMLCOMPILER_PRIVATE_EXPORT CompiledFunctionOrExpression
{
CompiledFunctionOrExpression()
{}
@@ -281,7 +291,7 @@ struct Q_QML_PRIVATE_EXPORT CompiledFunctionOrExpression
CompiledFunctionOrExpression *next = nullptr;
};
-struct Q_QML_PRIVATE_EXPORT Object
+struct Q_QMLCOMPILER_PRIVATE_EXPORT Object
{
Q_DECLARE_TR_FUNCTIONS(Object)
public:
@@ -340,9 +350,9 @@ public:
QString bindingAsString(Document *doc, int scriptIndex) const;
PoolList<CompiledFunctionOrExpression> *functionsAndExpressions;
- FixedPoolArray<int> runtimeFunctionIndices;
+ QQmlJS::FixedPoolArray<int> runtimeFunctionIndices;
- FixedPoolArray<quint32> namedObjectsInComponent;
+ QQmlJS::FixedPoolArray<quint32> namedObjectsInComponent;
int namedObjectsInComponentCount() const { return namedObjectsInComponent.size(); }
const quint32 *namedObjectsInComponentTable() const { return namedObjectsInComponent.begin(); }
@@ -357,7 +367,7 @@ private:
PoolList<Function> *functions;
};
-struct Q_QML_PRIVATE_EXPORT Pragma
+struct Q_QMLCOMPILER_PRIVATE_EXPORT Pragma
{
enum PragmaType {
PragmaSingleton = 0x1
@@ -367,7 +377,7 @@ struct Q_QML_PRIVATE_EXPORT Pragma
QV4::CompiledData::Location location;
};
-struct Q_QML_PRIVATE_EXPORT Document
+struct Q_QMLCOMPILER_PRIVATE_EXPORT Document
{
Document(bool debugMode);
QString code;
@@ -383,11 +393,9 @@ struct Q_QML_PRIVATE_EXPORT Document
int registerString(const QString &str) { return jsGenerator.registerString(str); }
QString stringAt(int index) const { return jsGenerator.stringForIndex(index); }
-
- static void removeScriptPragmas(QString &script);
};
-class Q_QML_PRIVATE_EXPORT ScriptDirectivesCollector : public QQmlJS::Directives
+class Q_QMLCOMPILER_PRIVATE_EXPORT ScriptDirectivesCollector : public QQmlJS::Directives
{
QmlIR::Document *document;
QQmlJS::Engine *engine;
@@ -401,7 +409,7 @@ public:
void importModule(const QString &uri, const QString &version, const QString &module, int lineNumber, int column) override;
};
-struct Q_QML_PRIVATE_EXPORT IRBuilder : public QQmlJS::AST::Visitor
+struct Q_QMLCOMPILER_PRIVATE_EXPORT IRBuilder : public QQmlJS::AST::Visitor
{
Q_DECLARE_TR_FUNCTIONS(QQmlCodeGenerator)
public:
@@ -432,7 +440,7 @@ public:
void throwRecursionDepthError() override
{
- recordError(AST::SourceLocation(),
+ recordError(QQmlJS::AST::SourceLocation(),
QStringLiteral("Maximum statement or expression depth exceeded"));
}
@@ -451,13 +459,19 @@ public:
QStringRef textRefAt(const QQmlJS::AST::SourceLocation &first,
const QQmlJS::AST::SourceLocation &last) const;
- void setBindingValue(QV4::CompiledData::Binding *binding, QQmlJS::AST::Statement *statement, AST::Node *parentNode);
+ void setBindingValue(QV4::CompiledData::Binding *binding, QQmlJS::AST::Statement *statement,
+ QQmlJS::AST::Node *parentNode);
void tryGeneratingTranslationBinding(const QStringRef &base, QQmlJS::AST::ArgumentList *args, QV4::CompiledData::Binding *binding);
- void appendBinding(QQmlJS::AST::UiQualifiedId *name, QQmlJS::AST::Statement *value, AST::Node *parentNode);
+ void appendBinding(QQmlJS::AST::UiQualifiedId *name, QQmlJS::AST::Statement *value,
+ QQmlJS::AST::Node *parentNode);
void appendBinding(QQmlJS::AST::UiQualifiedId *name, int objectIndex, bool isOnAssignment = false);
- void appendBinding(const QQmlJS::AST::SourceLocation &qualifiedNameLocation, const QQmlJS::AST::SourceLocation &nameLocation, quint32 propertyNameIndex, QQmlJS::AST::Statement *value, AST::Node *parentNode);
- void appendBinding(const QQmlJS::AST::SourceLocation &qualifiedNameLocation, const QQmlJS::AST::SourceLocation &nameLocation, quint32 propertyNameIndex, int objectIndex, bool isListItem = false, bool isOnAssignment = false);
+ void appendBinding(const QQmlJS::AST::SourceLocation &qualifiedNameLocation,
+ const QQmlJS::AST::SourceLocation &nameLocation, quint32 propertyNameIndex,
+ QQmlJS::AST::Statement *value, QQmlJS::AST::Node *parentNode);
+ void appendBinding(const QQmlJS::AST::SourceLocation &qualifiedNameLocation,
+ const QQmlJS::AST::SourceLocation &nameLocation, quint32 propertyNameIndex,
+ int objectIndex, bool isListItem = false, bool isOnAssignment = false);
bool appendAlias(QQmlJS::AST::UiPublicMember *node);
@@ -499,7 +513,7 @@ public:
QV4::Compiler::JSUnitGenerator *jsGenerator;
};
-struct Q_QML_PRIVATE_EXPORT QmlUnitGenerator
+struct Q_QMLCOMPILER_PRIVATE_EXPORT QmlUnitGenerator
{
void generate(Document &output, const QV4::CompiledData::DependentTypesHasher &dependencyHasher = QV4::CompiledData::DependentTypesHasher());
@@ -508,34 +522,23 @@ private:
char *writeBindings(char *bindingPtr, const Object *o, BindingFilter filter) const;
};
-struct Q_QML_PRIVATE_EXPORT JSCodeGen : public QV4::Compiler::Codegen
+struct Q_QMLCOMPILER_PRIVATE_EXPORT JSCodeGen : public QV4::Compiler::Codegen
{
- JSCodeGen(const QString &sourceCode, QV4::Compiler::JSUnitGenerator *jsUnitGenerator, QV4::Compiler::Module *jsModule,
- QQmlJS::Engine *jsEngine, QQmlJS::AST::UiProgram *qmlRoot,
- const QV4::Compiler::StringTableGenerator *stringPool, const QSet<QString> &globalNames);
+ JSCodeGen(Document *document, const QSet<QString> &globalNames);
// Returns mapping from input functions to index in IR::Module::functions / compiledData->runtimeFunctions
QVector<int> generateJSCodeForFunctionsAndBindings(const QList<CompiledFunctionOrExpression> &functions);
+ bool generateCodeForComponents(const QVector<quint32> &componentRoots);
+ bool compileComponent(int contextObject);
+ bool compileJavaScriptCodeInObjectsRecursively(int objectIndex, int scopeObjectIndex);
+
private:
- QString sourceCode;
- QQmlJS::Engine *jsEngine; // needed for memory pool
- QQmlJS::AST::UiProgram *qmlRoot;
- const QV4::Compiler::StringTableGenerator *stringPool;
+ Document *document;
};
} // namespace QmlIR
-inline QQmlJS::DiagnosticMessage qQmlCompileError(const QV4::CompiledData::Location &location,
- const QString &description)
-{
- QQmlJS::DiagnosticMessage error;
- error.line = location.line;
- error.column = location.column;
- error.message = description;
- return error;
-}
-
QT_END_NAMESPACE
#endif // QQMLIRBUILDER_P_H
diff --git a/src/qml/compiler/qv4bytecodegenerator.cpp b/src/qml/compiler/qv4bytecodegenerator.cpp
index ea252a6013..7df1614ffe 100644
--- a/src/qml/compiler/qv4bytecodegenerator.cpp
+++ b/src/qml/compiler/qv4bytecodegenerator.cpp
@@ -206,7 +206,6 @@ int BytecodeGenerator::addInstructionHelper(Instr::Type type, const Instr &i, in
lastInstrType = int(type);
lastInstr = i;
-#if QT_CONFIG(qml_debug)
if (debugMode && type != Instr::Type::Debug) {
QT_WARNING_PUSH
QT_WARNING_DISABLE_GCC("-Wmaybe-uninitialized") // broken gcc warns about Instruction::Debug()
@@ -219,9 +218,6 @@ QT_WARNING_DISABLE_GCC("-Wmaybe-uninitialized") // broken gcc warns about Instru
}
QT_WARNING_POP
}
-#else
- Q_UNUSED(debugMode);
-#endif
const int pos = instructions.size();
diff --git a/src/qml/compiler/qv4bytecodegenerator_p.h b/src/qml/compiler/qv4bytecodegenerator_p.h
index acd4aa62ea..8c509dd9f1 100644
--- a/src/qml/compiler/qv4bytecodegenerator_p.h
+++ b/src/qml/compiler/qv4bytecodegenerator_p.h
@@ -62,6 +62,11 @@ class SourceLocation;
}
namespace QV4 {
+
+namespace Compiler {
+struct Context;
+}
+
namespace Moth {
class BytecodeGenerator {
diff --git a/src/qml/compiler/qv4codegen.cpp b/src/qml/compiler/qv4codegen.cpp
index 453963c1dd..c43ea64e2e 100644
--- a/src/qml/compiler/qv4codegen.cpp
+++ b/src/qml/compiler/qv4codegen.cpp
@@ -48,7 +48,6 @@
#include <private/qqmljsast_p.h>
#include <private/qqmljslexer_p.h>
#include <private/qqmljsparser_p.h>
-#include <private/qv4stringtoarrayindex_p.h>
#include <private/qv4staticvalue_p.h>
#include <private/qv4compilercontext_p.h>
#include <private/qv4compilercontrolflow_p.h>
@@ -69,6 +68,7 @@ static const bool disable_lookups = false;
QT_USE_NAMESPACE
using namespace QV4;
using namespace QV4::Compiler;
+using namespace QQmlJS;
using namespace QQmlJS::AST;
static inline void setJumpOutLocation(QV4::Moth::BytecodeGenerator *bytecodeGenerator,
@@ -610,6 +610,8 @@ void Codegen::initializeAndDestructureBindingElement(AST::PatternElement *e, con
if (hasError())
return;
+ accept(e->typeAnnotation);
+
if (e->initializer) {
if (!baseRef.isValid()) {
// assignment
@@ -885,6 +887,12 @@ bool Codegen::visit(ExportDeclaration *ast)
return false;
}
+bool Codegen::visit(TypeAnnotation *ast)
+{
+ throwSyntaxError(ast->firstSourceLocation(), QLatin1String("Type annotations are not supported (yet)."));
+ return false;
+}
+
bool Codegen::visit(StatementList *)
{
Q_UNREACHABLE();
diff --git a/src/qml/compiler/qv4codegen_p.h b/src/qml/compiler/qv4codegen_p.h
index 51b821aafe..82a4fc3289 100644
--- a/src/qml/compiler/qv4codegen_p.h
+++ b/src/qml/compiler/qv4codegen_p.h
@@ -50,7 +50,6 @@
// We mean it.
//
-#include "private/qv4global_p.h"
#include <private/qqmljsastvisitor_p.h>
#include <private/qqmljsengine_p.h>
#include <private/qqmljsast_p.h>
@@ -63,8 +62,6 @@
QT_BEGIN_NAMESPACE
-using namespace QQmlJS;
-
namespace QV4 {
namespace Moth {
@@ -81,7 +78,7 @@ struct ControlFlow;
struct ControlFlowCatch;
struct ControlFlowFinally;
-class Q_QML_PRIVATE_EXPORT Codegen: protected QQmlJS::AST::Visitor
+class Q_QMLCOMPILER_PRIVATE_EXPORT Codegen: protected QQmlJS::AST::Visitor
{
protected:
using BytecodeGenerator = QV4::Moth::BytecodeGenerator;
@@ -93,14 +90,14 @@ public:
void generateFromProgram(const QString &fileName,
const QString &finalUrl,
const QString &sourceCode,
- AST::Program *ast,
+ QQmlJS::AST::Program *ast,
Module *module,
ContextType contextType = ContextType::Global);
void generateFromModule(const QString &fileName,
const QString &finalUrl,
const QString &sourceCode,
- AST::ESModule *ast,
+ QQmlJS::AST::ESModule *ast,
Module *module);
public:
@@ -487,10 +484,10 @@ protected:
}
};
- void enterContext(AST::Node *node);
+ void enterContext(QQmlJS::AST::Node *node);
int leaveContext();
public:
- Context *enterBlock(AST::Node *node);
+ Context *enterBlock(QQmlJS::AST::Node *node);
int leaveBlock() { return leaveContext(); }
protected:
void leaveLoop();
@@ -521,18 +518,18 @@ public:
int registerQmlContextPropertyGetterLookup(int nameIndex) { return jsUnitGenerator->registerQmlContextPropertyGetterLookup(nameIndex); }
// Returns index in _module->functions
- virtual int defineFunction(const QString &name, AST::Node *ast,
- AST::FormalParameterList *formals,
- AST::StatementList *body);
+ virtual int defineFunction(const QString &name, QQmlJS::AST::Node *ast,
+ QQmlJS::AST::FormalParameterList *formals,
+ QQmlJS::AST::StatementList *body);
protected:
- void statement(AST::Statement *ast);
- void statement(AST::ExpressionNode *ast);
- void condition(AST::ExpressionNode *ast, const BytecodeGenerator::Label *iftrue,
+ void statement(QQmlJS::AST::Statement *ast);
+ void statement(QQmlJS::AST::ExpressionNode *ast);
+ void condition(QQmlJS::AST::ExpressionNode *ast, const BytecodeGenerator::Label *iftrue,
const BytecodeGenerator::Label *iffalse,
bool trueBlockFollowsCondition);
- inline Reference expression(AST::ExpressionNode *ast, const QString &name = QString())
+ inline Reference expression(QQmlJS::AST::ExpressionNode *ast, const QString &name = QString())
{
if (!ast || hasError())
return Reference();
@@ -542,131 +539,134 @@ protected:
return popResult();
}
- inline void accept(AST::Node *node)
+ inline void accept(QQmlJS::AST::Node *node)
{
if (!hasError() && node)
node->accept(this);
}
- void program(AST::Program *ast);
- void statementList(AST::StatementList *ast);
- void variableDeclaration(AST::PatternElement *ast);
- void variableDeclarationList(AST::VariableDeclarationList *ast);
+ void program(QQmlJS::AST::Program *ast);
+ void statementList(QQmlJS::AST::StatementList *ast);
+ void variableDeclaration(QQmlJS::AST::PatternElement *ast);
+ void variableDeclarationList(QQmlJS::AST::VariableDeclarationList *ast);
- Reference targetForPatternElement(AST::PatternElement *p);
- void initializeAndDestructureBindingElement(AST::PatternElement *e, const Reference &baseRef = Reference(), bool isDefinition = false);
- void destructurePropertyList(const Reference &object, AST::PatternPropertyList *bindingList, bool isDefinition = false);
- void destructureElementList(const Reference &array, AST::PatternElementList *bindingList, bool isDefinition = false);
- void destructurePattern(AST::Pattern *p, const Reference &rhs);
+ Reference targetForPatternElement(QQmlJS::AST::PatternElement *p);
+ void initializeAndDestructureBindingElement(QQmlJS::AST::PatternElement *e, const Reference &baseRef = Reference(), bool isDefinition = false);
+ void destructurePropertyList(const Reference &object, QQmlJS::AST::PatternPropertyList *bindingList, bool isDefinition = false);
+ void destructureElementList(const Reference &array, QQmlJS::AST::PatternElementList *bindingList, bool isDefinition = false);
+ void destructurePattern(QQmlJS::AST::Pattern *p, const Reference &rhs);
- Reference referenceForPropertyName(const Codegen::Reference &object, AST::PropertyName *name);
+ Reference referenceForPropertyName(const Codegen::Reference &object, QQmlJS::AST::PropertyName *name);
void emitReturn(const Reference &expr);
// nodes
- bool visit(AST::ArgumentList *ast) override;
- bool visit(AST::CaseBlock *ast) override;
- bool visit(AST::CaseClause *ast) override;
- bool visit(AST::CaseClauses *ast) override;
- bool visit(AST::Catch *ast) override;
- bool visit(AST::DefaultClause *ast) override;
- bool visit(AST::Elision *ast) override;
- bool visit(AST::Finally *ast) override;
- bool visit(AST::FormalParameterList *ast) override;
- bool visit(AST::Program *ast) override;
- bool visit(AST::StatementList *ast) override;
- bool visit(AST::UiArrayMemberList *ast) override;
- bool visit(AST::UiImport *ast) override;
- bool visit(AST::UiHeaderItemList *ast) override;
- bool visit(AST::UiPragma *ast) override;
- bool visit(AST::UiObjectInitializer *ast) override;
- bool visit(AST::UiObjectMemberList *ast) override;
- bool visit(AST::UiParameterList *ast) override;
- bool visit(AST::UiProgram *ast) override;
- bool visit(AST::UiQualifiedId *ast) override;
- bool visit(AST::VariableDeclarationList *ast) override;
-
- bool visit(AST::PatternElement *ast) override;
- bool visit(AST::PatternElementList *ast) override;
- bool visit(AST::PatternProperty *ast) override;
- bool visit(AST::PatternPropertyList *ast) override;
-
- bool visit(AST::ExportDeclaration *ast) override;
+ bool visit(QQmlJS::AST::ArgumentList *ast) override;
+ bool visit(QQmlJS::AST::CaseBlock *ast) override;
+ bool visit(QQmlJS::AST::CaseClause *ast) override;
+ bool visit(QQmlJS::AST::CaseClauses *ast) override;
+ bool visit(QQmlJS::AST::Catch *ast) override;
+ bool visit(QQmlJS::AST::DefaultClause *ast) override;
+ bool visit(QQmlJS::AST::Elision *ast) override;
+ bool visit(QQmlJS::AST::Finally *ast) override;
+ bool visit(QQmlJS::AST::FormalParameterList *ast) override;
+ bool visit(QQmlJS::AST::Program *ast) override;
+ bool visit(QQmlJS::AST::StatementList *ast) override;
+ bool visit(QQmlJS::AST::UiArrayMemberList *ast) override;
+ bool visit(QQmlJS::AST::UiImport *ast) override;
+ bool visit(QQmlJS::AST::UiHeaderItemList *ast) override;
+ bool visit(QQmlJS::AST::UiPragma *ast) override;
+ bool visit(QQmlJS::AST::UiObjectInitializer *ast) override;
+ bool visit(QQmlJS::AST::UiObjectMemberList *ast) override;
+ bool visit(QQmlJS::AST::UiParameterList *ast) override;
+ bool visit(QQmlJS::AST::UiProgram *ast) override;
+ bool visit(QQmlJS::AST::UiQualifiedId *ast) override;
+ bool visit(QQmlJS::AST::VariableDeclarationList *ast) override;
+
+ bool visit(QQmlJS::AST::PatternElement *ast) override;
+ bool visit(QQmlJS::AST::PatternElementList *ast) override;
+ bool visit(QQmlJS::AST::PatternProperty *ast) override;
+ bool visit(QQmlJS::AST::PatternPropertyList *ast) override;
+
+ bool visit(QQmlJS::AST::ExportDeclaration *ast) override;
+
+ bool visit(QQmlJS::AST::TypeAnnotation *ast) override;
// expressions
- bool visit(AST::Expression *ast) override;
- bool visit(AST::ArrayPattern *ast) override;
- bool visit(AST::ArrayMemberExpression *ast) override;
- bool visit(AST::BinaryExpression *ast) override;
- bool visit(AST::CallExpression *ast) override;
- bool visit(AST::ConditionalExpression *ast) override;
- bool visit(AST::DeleteExpression *ast) override;
- bool visit(AST::FalseLiteral *ast) override;
- bool visit(AST::SuperLiteral *ast) override;
- bool visit(AST::FieldMemberExpression *ast) override;
- bool visit(AST::TaggedTemplate *ast) override;
- bool visit(AST::FunctionExpression *ast) override;
- bool visit(AST::IdentifierExpression *ast) override;
- bool visit(AST::NestedExpression *ast) override;
- bool visit(AST::NewExpression *ast) override;
- bool visit(AST::NewMemberExpression *ast) override;
- bool visit(AST::NotExpression *ast) override;
- bool visit(AST::NullExpression *ast) override;
- bool visit(AST::NumericLiteral *ast) override;
- bool visit(AST::ObjectPattern *ast) override;
- bool visit(AST::PostDecrementExpression *ast) override;
- bool visit(AST::PostIncrementExpression *ast) override;
- bool visit(AST::PreDecrementExpression *ast) override;
- bool visit(AST::PreIncrementExpression *ast) override;
- bool visit(AST::RegExpLiteral *ast) override;
- bool visit(AST::StringLiteral *ast) override;
- bool visit(AST::TemplateLiteral *ast) override;
- bool visit(AST::ThisExpression *ast) override;
- bool visit(AST::TildeExpression *ast) override;
- bool visit(AST::TrueLiteral *ast) override;
- bool visit(AST::TypeOfExpression *ast) override;
- bool visit(AST::UnaryMinusExpression *ast) override;
- bool visit(AST::UnaryPlusExpression *ast) override;
- bool visit(AST::VoidExpression *ast) override;
- bool visit(AST::FunctionDeclaration *ast) override;
- bool visit(AST::YieldExpression *ast) override;
- bool visit(AST::ClassExpression *ast) override;
- bool visit(AST::ClassDeclaration *ast) override;
+ bool visit(QQmlJS::AST::Expression *ast) override;
+ bool visit(QQmlJS::AST::ArrayPattern *ast) override;
+ bool visit(QQmlJS::AST::ArrayMemberExpression *ast) override;
+ bool visit(QQmlJS::AST::BinaryExpression *ast) override;
+ bool visit(QQmlJS::AST::CallExpression *ast) override;
+ bool visit(QQmlJS::AST::ConditionalExpression *ast) override;
+ bool visit(QQmlJS::AST::DeleteExpression *ast) override;
+ bool visit(QQmlJS::AST::FalseLiteral *ast) override;
+ bool visit(QQmlJS::AST::SuperLiteral *ast) override;
+ bool visit(QQmlJS::AST::FieldMemberExpression *ast) override;
+ bool visit(QQmlJS::AST::TaggedTemplate *ast) override;
+ bool visit(QQmlJS::AST::FunctionExpression *ast) override;
+ bool visit(QQmlJS::AST::IdentifierExpression *ast) override;
+ bool visit(QQmlJS::AST::NestedExpression *ast) override;
+ bool visit(QQmlJS::AST::NewExpression *ast) override;
+ bool visit(QQmlJS::AST::NewMemberExpression *ast) override;
+ bool visit(QQmlJS::AST::NotExpression *ast) override;
+ bool visit(QQmlJS::AST::NullExpression *ast) override;
+ bool visit(QQmlJS::AST::NumericLiteral *ast) override;
+ bool visit(QQmlJS::AST::ObjectPattern *ast) override;
+ bool visit(QQmlJS::AST::PostDecrementExpression *ast) override;
+ bool visit(QQmlJS::AST::PostIncrementExpression *ast) override;
+ bool visit(QQmlJS::AST::PreDecrementExpression *ast) override;
+ bool visit(QQmlJS::AST::PreIncrementExpression *ast) override;
+ bool visit(QQmlJS::AST::RegExpLiteral *ast) override;
+ bool visit(QQmlJS::AST::StringLiteral *ast) override;
+ bool visit(QQmlJS::AST::TemplateLiteral *ast) override;
+ bool visit(QQmlJS::AST::ThisExpression *ast) override;
+ bool visit(QQmlJS::AST::TildeExpression *ast) override;
+ bool visit(QQmlJS::AST::TrueLiteral *ast) override;
+ bool visit(QQmlJS::AST::TypeOfExpression *ast) override;
+ bool visit(QQmlJS::AST::UnaryMinusExpression *ast) override;
+ bool visit(QQmlJS::AST::UnaryPlusExpression *ast) override;
+ bool visit(QQmlJS::AST::VoidExpression *ast) override;
+ bool visit(QQmlJS::AST::FunctionDeclaration *ast) override;
+ bool visit(QQmlJS::AST::YieldExpression *ast) override;
+ bool visit(QQmlJS::AST::ClassExpression *ast) override;
+ bool visit(QQmlJS::AST::ClassDeclaration *ast) override;
// statements
- bool visit(AST::Block *ast) override;
- bool visit(AST::BreakStatement *ast) override;
- bool visit(AST::ContinueStatement *ast) override;
- bool visit(AST::DebuggerStatement *ast) override;
- bool visit(AST::DoWhileStatement *ast) override;
- bool visit(AST::EmptyStatement *ast) override;
- bool visit(AST::ExpressionStatement *ast) override;
- bool visit(AST::ForEachStatement *ast) override;
- bool visit(AST::ForStatement *ast) override;
- bool visit(AST::IfStatement *ast) override;
- bool visit(AST::LabelledStatement *ast) override;
- bool visit(AST::ReturnStatement *ast) override;
- bool visit(AST::SwitchStatement *ast) override;
- bool visit(AST::ThrowStatement *ast) override;
- bool visit(AST::TryStatement *ast) override;
- bool visit(AST::VariableStatement *ast) override;
- bool visit(AST::WhileStatement *ast) override;
- bool visit(AST::WithStatement *ast) override;
+ bool visit(QQmlJS::AST::Block *ast) override;
+ bool visit(QQmlJS::AST::BreakStatement *ast) override;
+ bool visit(QQmlJS::AST::ContinueStatement *ast) override;
+ bool visit(QQmlJS::AST::DebuggerStatement *ast) override;
+ bool visit(QQmlJS::AST::DoWhileStatement *ast) override;
+ bool visit(QQmlJS::AST::EmptyStatement *ast) override;
+ bool visit(QQmlJS::AST::ExpressionStatement *ast) override;
+ bool visit(QQmlJS::AST::ForEachStatement *ast) override;
+ bool visit(QQmlJS::AST::ForStatement *ast) override;
+ bool visit(QQmlJS::AST::IfStatement *ast) override;
+ bool visit(QQmlJS::AST::LabelledStatement *ast) override;
+ bool visit(QQmlJS::AST::ReturnStatement *ast) override;
+ bool visit(QQmlJS::AST::SwitchStatement *ast) override;
+ bool visit(QQmlJS::AST::ThrowStatement *ast) override;
+ bool visit(QQmlJS::AST::TryStatement *ast) override;
+ bool visit(QQmlJS::AST::VariableStatement *ast) override;
+ bool visit(QQmlJS::AST::WhileStatement *ast) override;
+ bool visit(QQmlJS::AST::WithStatement *ast) override;
// ui object members
- bool visit(AST::UiArrayBinding *ast) override;
- bool visit(AST::UiObjectBinding *ast) override;
- bool visit(AST::UiObjectDefinition *ast) override;
- bool visit(AST::UiPublicMember *ast) override;
- bool visit(AST::UiScriptBinding *ast) override;
- bool visit(AST::UiSourceElement *ast) override;
-
- bool throwSyntaxErrorOnEvalOrArgumentsInStrictMode(const Reference &r, const AST::SourceLocation &loc);
- virtual void throwSyntaxError(const AST::SourceLocation &loc, const QString &detail);
- virtual void throwReferenceError(const AST::SourceLocation &loc, const QString &detail);
+ bool visit(QQmlJS::AST::UiArrayBinding *ast) override;
+ bool visit(QQmlJS::AST::UiObjectBinding *ast) override;
+ bool visit(QQmlJS::AST::UiObjectDefinition *ast) override;
+ bool visit(QQmlJS::AST::UiPublicMember *ast) override;
+ bool visit(QQmlJS::AST::UiScriptBinding *ast) override;
+ bool visit(QQmlJS::AST::UiSourceElement *ast) override;
+
+ bool throwSyntaxErrorOnEvalOrArgumentsInStrictMode(const Reference &r,
+ const QQmlJS::AST::SourceLocation &loc);
+ virtual void throwSyntaxError(const QQmlJS::AST::SourceLocation &loc, const QString &detail);
+ virtual void throwReferenceError(const QQmlJS::AST::SourceLocation &loc, const QString &detail);
void throwRecursionDepthError() override
{
- throwSyntaxError(AST::SourceLocation(),
+ throwSyntaxError(QQmlJS::AST::SourceLocation(),
QStringLiteral("Maximum statement or expression depth exceeded"));
}
@@ -679,31 +679,33 @@ public:
ErrorType errorType() const { return _errorType; }
bool hasError() const { return _errorType != NoError; }
- DiagnosticMessage error() const;
+ QQmlJS::DiagnosticMessage error() const;
QUrl url() const;
Reference binopHelper(QSOperator::Op oper, Reference &left, Reference &right);
Reference jumpBinop(QSOperator::Op oper, Reference &left, Reference &right);
struct Arguments { int argc; int argv; bool hasSpread; };
- Arguments pushArgs(AST::ArgumentList *args);
+ Arguments pushArgs(QQmlJS::AST::ArgumentList *args);
void handleCall(Reference &base, Arguments calldata, int slotForFunction, int slotForThisObject);
- Arguments pushTemplateArgs(AST::TemplateLiteral *args);
- bool handleTaggedTemplate(Reference base, AST::TaggedTemplate *ast);
- void createTemplateObject(AST::TemplateLiteral *t);
+ Arguments pushTemplateArgs(QQmlJS::AST::TemplateLiteral *args);
+ bool handleTaggedTemplate(Reference base, QQmlJS::AST::TaggedTemplate *ast);
+ void createTemplateObject(QQmlJS::AST::TemplateLiteral *t);
void setUseFastLookups(bool b) { useFastLookups = b; }
- void handleTryCatch(AST::TryStatement *ast);
- void handleTryFinally(AST::TryStatement *ast);
+ void handleTryCatch(QQmlJS::AST::TryStatement *ast);
+ void handleTryFinally(QQmlJS::AST::TryStatement *ast);
- Reference referenceForName(const QString &name, bool lhs, const QQmlJS::AST::SourceLocation &accessLocation = QQmlJS::AST::SourceLocation());
+ Reference referenceForName(
+ const QString &name, bool lhs,
+ const QQmlJS::AST::SourceLocation &accessLocation = QQmlJS::AST::SourceLocation());
QV4::CompiledData::CompilationUnit generateCompilationUnit(bool generateUnitData = true);
static QV4::CompiledData::CompilationUnit compileModule(
bool debugMode, const QString &url, const QString &sourceCode,
- const QDateTime &sourceTimeStamp, QList<DiagnosticMessage> *diagnostics);
+ const QDateTime &sourceTimeStamp, QList<QQmlJS::DiagnosticMessage> *diagnostics);
Context *currentContext() const { return _context; }
BytecodeGenerator *generator() const { return bytecodeGenerator; }
@@ -762,7 +764,7 @@ protected:
int _returnAddress;
Context *_context;
Context *_functionContext = nullptr;
- AST::LabelledStatement *_labelledStatement;
+ QQmlJS::AST::LabelledStatement *_labelledStatement;
QV4::Compiler::JSUnitGenerator *jsUnitGenerator;
BytecodeGenerator *bytecodeGenerator = nullptr;
Moth::BytecodeGenerator::Label *_returnLabel = nullptr;
@@ -806,9 +808,10 @@ protected:
};
private:
- VolatileMemoryLocations scanVolatileMemoryLocations(AST::Node *ast);
- void handleConstruct(const Reference &base, AST::ArgumentList *args);
- void throwError(ErrorType errorType, const AST::SourceLocation &loc, const QString &detail);
+ VolatileMemoryLocations scanVolatileMemoryLocations(QQmlJS::AST::Node *ast);
+ void handleConstruct(const Reference &base, QQmlJS::AST::ArgumentList *args);
+ void throwError(ErrorType errorType, const QQmlJS::AST::SourceLocation &loc,
+ const QString &detail);
};
}
diff --git a/src/qml/compiler/qv4compiler.cpp b/src/qml/compiler/qv4compiler.cpp
index b378c294b7..acc4b02e96 100644
--- a/src/qml/compiler/qv4compiler.cpp
+++ b/src/qml/compiler/qv4compiler.cpp
@@ -38,13 +38,14 @@
****************************************************************************/
#include <qv4compiler_p.h>
-#include <qv4compileddata_p.h>
#include <qv4codegen_p.h>
+#include <private/qv4compileddata_p.h>
#include <private/qv4staticvalue_p.h>
#include <private/qv4alloca_p.h>
#include <private/qqmljslexer_p.h>
#include <private/qqmljsast_p.h>
#include <private/qml_compile_hash_p.h>
+#include <private/qqmlirbuilder_p.h>
#include <QCryptographicHash>
// Efficient implementation that takes advantage of powers of two.
@@ -268,8 +269,11 @@ QV4::CompiledData::Unit *QV4::Compiler::JSUnitGenerator::generateUnit(GeneratorO
registerString(module->finalUrl);
for (Context *f : qAsConst(module->functions)) {
registerString(f->name);
- for (int i = 0; i < f->arguments.size(); ++i)
- registerString(f->arguments.at(i));
+ registerString(f->returnType);
+ for (int i = 0; i < f->arguments.size(); ++i) {
+ registerString(f->arguments.at(i).id);
+ registerString(f->arguments.at(i).typeName());
+ }
for (int i = 0; i < f->locals.size(); ++i)
registerString(f->locals.at(i));
}
@@ -436,7 +440,9 @@ void QV4::Compiler::JSUnitGenerator::writeFunction(char *f, QV4::Compiler::Conte
function->length = irFunction->formals ? irFunction->formals->length() : 0;
function->nFormals = irFunction->arguments.size();
function->formalsOffset = currentOffset;
- currentOffset += function->nFormals * sizeof(quint32);
+ currentOffset += function->nFormals * sizeof(CompiledData::Parameter);
+
+ QmlIR::Parameter::initType(&function->returnType, this, getStringId(irFunction->returnType));
function->sizeOfLocalTemporalDeadZone = irFunction->sizeOfLocalTemporalDeadZone;
function->sizeOfRegisterTemporalDeadZone = irFunction->sizeOfRegisterTemporalDeadZone;
@@ -465,9 +471,11 @@ void QV4::Compiler::JSUnitGenerator::writeFunction(char *f, QV4::Compiler::Conte
function->codeSize = irFunction->code.size();
// write formals
- quint32_le *formals = (quint32_le *)(f + function->formalsOffset);
- for (int i = 0; i < irFunction->arguments.size(); ++i)
- formals[i] = getStringId(irFunction->arguments.at(i));
+ CompiledData::Parameter *formals = (CompiledData::Parameter *)(f + function->formalsOffset);
+ for (int i = 0; i < irFunction->arguments.size(); ++i) {
+ QmlIR::Parameter::init(&formals[i], this, getStringId(irFunction->arguments.at(i).id),
+ getStringId(irFunction->arguments.at(i).typeName()));
+ }
// write locals
quint32_le *locals = (quint32_le *)(f + function->localsOffset);
diff --git a/src/qml/compiler/qv4compiler_p.h b/src/qml/compiler/qv4compiler_p.h
index f5884f6478..4f3c718175 100644
--- a/src/qml/compiler/qv4compiler_p.h
+++ b/src/qml/compiler/qv4compiler_p.h
@@ -53,9 +53,10 @@
#include <QtCore/qstring.h>
#include <QtCore/qhash.h>
#include <QtCore/qstringlist.h>
-#include <private/qv4global_p.h>
+#include <private/qv4compilerglobal_p.h>
#include <private/qqmljsastfwd_p.h>
#include <private/qv4compileddata_p.h>
+#include <private/qv4staticvalue_p.h>
QT_BEGIN_NAMESPACE
@@ -72,10 +73,12 @@ struct JSClassMember;
namespace Compiler {
+struct Context;
+struct Module;
struct Class;
struct TemplateObject;
-struct Q_QML_PRIVATE_EXPORT StringTableGenerator {
+struct Q_QMLCOMPILER_PRIVATE_EXPORT StringTableGenerator {
StringTableGenerator();
int registerString(const QString &str);
@@ -102,7 +105,7 @@ private:
bool frozen = false;
};
-struct Q_QML_PRIVATE_EXPORT JSUnitGenerator {
+struct Q_QMLCOMPILER_PRIVATE_EXPORT JSUnitGenerator {
static void generateUnitChecksum(CompiledData::Unit *unit);
struct MemberInfo {
diff --git a/src/qml/compiler/qv4compilercontext_p.h b/src/qml/compiler/qv4compilercontext_p.h
index f56942fffa..8c124ac409 100644
--- a/src/qml/compiler/qv4compilercontext_p.h
+++ b/src/qml/compiler/qv4compilercontext_p.h
@@ -50,7 +50,6 @@
// We mean it.
//
-#include "private/qv4global_p.h"
#include <private/qqmljsast_p.h>
#include <private/qv4compileddata_p.h>
#include <QtCore/QStringList>
@@ -62,8 +61,13 @@ QT_BEGIN_NAMESPACE
namespace QV4 {
+namespace Moth {
+class BytecodeGenerator;
+}
+
namespace Compiler {
+class Codegen;
struct ControlFlow;
enum class ContextType {
@@ -189,7 +193,8 @@ struct Context {
MemberMap members;
QSet<QString> usedVariables;
QQmlJS::AST::FormalParameterList *formals = nullptr;
- QStringList arguments;
+ QQmlJS::AST::BoundNames arguments;
+ QString returnType;
QStringList locals;
QStringList moduleRequests;
QVector<ImportEntry> importEntries;
@@ -288,7 +293,7 @@ struct Context {
{
// search backwards to handle duplicate argument names correctly
for (int i = arguments.size() - 1; i >= 0; --i) {
- if (arguments.at(i) == name)
+ if (arguments.at(i).id == name)
return i;
}
return -1;
diff --git a/src/qml/compiler/qv4compilercontrolflow_p.h b/src/qml/compiler/qv4compilercontrolflow_p.h
index 5b622e81d8..5623473726 100644
--- a/src/qml/compiler/qv4compilercontrolflow_p.h
+++ b/src/qml/compiler/qv4compilercontrolflow_p.h
@@ -50,7 +50,6 @@
// We mean it.
//
-#include <private/qv4global_p.h>
#include <private/qv4codegen_p.h>
#include <private/qqmljsast_p.h>
#include <private/qv4bytecodegenerator_p.h>
@@ -279,7 +278,7 @@ struct ControlFlowWith : public ControlFlowUnwind
struct ControlFlowBlock : public ControlFlowUnwind
{
- ControlFlowBlock(Codegen *cg, AST::Node *ast)
+ ControlFlowBlock(Codegen *cg, QQmlJS::AST::Node *ast)
: ControlFlowUnwind(cg, Block)
{
block = cg->enterBlock(ast);
@@ -314,11 +313,11 @@ struct ControlFlowBlock : public ControlFlowUnwind
struct ControlFlowCatch : public ControlFlowUnwind
{
- AST::Catch *catchExpression;
+ QQmlJS::AST::Catch *catchExpression;
bool insideCatch = false;
BytecodeGenerator::ExceptionHandler exceptionLabel;
- ControlFlowCatch(Codegen *cg, AST::Catch *catchExpression)
+ ControlFlowCatch(Codegen *cg, QQmlJS::AST::Catch *catchExpression)
: ControlFlowUnwind(cg, Catch), catchExpression(catchExpression),
exceptionLabel(generator()->newExceptionHandler())
{
@@ -372,10 +371,10 @@ struct ControlFlowCatch : public ControlFlowUnwind
struct ControlFlowFinally : public ControlFlowUnwind
{
- AST::Finally *finally;
+ QQmlJS::AST::Finally *finally;
bool insideFinally = false;
- ControlFlowFinally(Codegen *cg, AST::Finally *finally)
+ ControlFlowFinally(Codegen *cg, QQmlJS::AST::Finally *finally)
: ControlFlowUnwind(cg, Finally), finally(finally)
{
Q_ASSERT(finally != nullptr);
diff --git a/src/qml/compiler/qv4compilerglobal_p.h b/src/qml/compiler/qv4compilerglobal_p.h
new file mode 100644
index 0000000000..3478074827
--- /dev/null
+++ b/src/qml/compiler/qv4compilerglobal_p.h
@@ -0,0 +1,74 @@
+/****************************************************************************
+**
+** 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 QV4COMPILERGLOBAL_H
+#define QV4COMPILERGLOBAL_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 <QString>
+
+#include <private/qtqmlcompilerglobal_p.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace QV4 {
+
+enum class ObjectLiteralArgument {
+ Value,
+ Method,
+ Getter,
+ Setter
+};
+
+} // namespace QV4
+
+QT_END_NAMESPACE
+
+#endif // QV4COMPILERGLOBAL_H
diff --git a/src/qml/compiler/qv4compilerscanfunctions.cpp b/src/qml/compiler/qv4compilerscanfunctions.cpp
index 416a0edee0..ab0ebf3d4b 100644
--- a/src/qml/compiler/qv4compilerscanfunctions.cpp
+++ b/src/qml/compiler/qv4compilerscanfunctions.cpp
@@ -52,6 +52,7 @@
QT_USE_NAMESPACE
using namespace QV4;
using namespace QV4::Compiler;
+using namespace QQmlJS;
using namespace QQmlJS::AST;
static CompiledData::Location location(const QQmlJS::AST::SourceLocation &astLocation)
@@ -202,16 +203,16 @@ bool ScanFunctions::visit(ExportDeclaration *declaration)
_context->exportEntries << entry;
}
} else if (auto *vstmt = AST::cast<AST::VariableStatement*>(declaration->variableStatementOrDeclaration)) {
- QStringList boundNames;
+ BoundNames boundNames;
for (VariableDeclarationList *it = vstmt->declarations; it; it = it->next) {
if (!it->declaration)
continue;
it->declaration->boundNames(&boundNames);
}
- for (const QString &name: boundNames) {
+ for (const auto &name: boundNames) {
Compiler::ExportEntry entry;
- entry.localName = name;
- entry.exportName = name;
+ entry.localName = name.id;
+ entry.exportName = name.id;
entry.location = location(vstmt->firstSourceLocation());
_context->exportEntries << entry;
}
@@ -326,26 +327,26 @@ bool ScanFunctions::visit(PatternElement *ast)
if (!ast->isVariableDeclaration())
return true;
- QStringList names;
+ BoundNames names;
ast->boundNames(&names);
QQmlJS::AST::SourceLocation lastInitializerLocation = ast->lastSourceLocation();
if (_context->lastBlockInitializerLocation.isValid())
lastInitializerLocation = _context->lastBlockInitializerLocation;
- for (const QString &name : qAsConst(names)) {
- if (_context->isStrict && (name == QLatin1String("eval") || name == QLatin1String("arguments")))
+ for (const auto &name : qAsConst(names)) {
+ if (_context->isStrict && (name.id == QLatin1String("eval") || name.id == QLatin1String("arguments")))
_cg->throwSyntaxError(ast->identifierToken, QStringLiteral("Variable name may not be eval or arguments in strict mode"));
- checkName(QStringRef(&name), ast->identifierToken);
- if (name == QLatin1String("arguments"))
+ checkName(QStringRef(&name.id), ast->identifierToken);
+ if (name.id == QLatin1String("arguments"))
_context->usesArgumentsObject = Context::ArgumentsObjectNotUsed;
if (ast->scope == VariableScope::Const && !ast->initializer && !ast->isForDeclaration && !ast->destructuringPattern()) {
_cg->throwSyntaxError(ast->identifierToken, QStringLiteral("Missing initializer in const declaration"));
return false;
}
- if (!_context->addLocalVar(name, ast->initializer ? Context::VariableDefinition : Context::VariableDeclaration, ast->scope,
+ if (!_context->addLocalVar(name.id, ast->initializer ? Context::VariableDefinition : Context::VariableDeclaration, ast->scope,
/*function*/nullptr, lastInitializerLocation)) {
- _cg->throwSyntaxError(ast->identifierToken, QStringLiteral("Identifier %1 has already been declared").arg(name));
+ _cg->throwSyntaxError(ast->identifierToken, QStringLiteral("Identifier %1 has already been declared").arg(name.id));
return false;
}
}
@@ -679,6 +680,9 @@ bool ScanFunctions::enterFunction(Node *ast, const QString &name, FormalParamete
_context->isArrowFunction = true;
else if (expr->isGenerator)
_context->isGenerator = true;
+
+ if (expr->typeAnnotation)
+ _context->returnType = expr->typeAnnotation->type->toString();
}
@@ -691,11 +695,11 @@ bool ScanFunctions::enterFunction(Node *ast, const QString &name, FormalParamete
bool isSimpleParameterList = formals && formals->isSimpleParameterList();
- _context->arguments = formals ? formals->formals() : QStringList();
+ _context->arguments = formals ? formals->formals() : BoundNames();
- const QStringList boundNames = formals ? formals->boundNames() : QStringList();
+ const BoundNames boundNames = formals ? formals->boundNames() : BoundNames();
for (int i = 0; i < boundNames.size(); ++i) {
- const QString &arg = boundNames.at(i);
+ const QString &arg = boundNames.at(i).id;
if (_context->isStrict || !isSimpleParameterList) {
bool duplicate = (boundNames.indexOf(arg, i + 1) != -1);
if (duplicate) {
@@ -712,6 +716,7 @@ bool ScanFunctions::enterFunction(Node *ast, const QString &name, FormalParamete
if (!_context->arguments.contains(arg))
_context->addLocalVar(arg, Context::VariableDefinition, VariableScope::Var);
}
+
return true;
}
diff --git a/src/qml/compiler/qv4compilerscanfunctions_p.h b/src/qml/compiler/qv4compilerscanfunctions_p.h
index 0f7bf1818a..f67db030a2 100644
--- a/src/qml/compiler/qv4compilerscanfunctions_p.h
+++ b/src/qml/compiler/qv4compilerscanfunctions_p.h
@@ -50,7 +50,7 @@
// We mean it.
//
-#include "private/qv4global_p.h"
+#include <private/qtqmlcompilerglobal_p.h>
#include <private/qqmljsastvisitor_p.h>
#include <private/qqmljsast_p.h>
#include <private/qqmljsengine_p.h>
@@ -62,8 +62,6 @@
QT_BEGIN_NAMESPACE
-using namespace QQmlJS;
-
namespace QV4 {
namespace Moth {
@@ -83,84 +81,87 @@ class ScanFunctions: protected QQmlJS::AST::Visitor
typedef QScopedValueRollback<bool> TemporaryBoolAssignment;
public:
ScanFunctions(Codegen *cg, const QString &sourceCode, ContextType defaultProgramType);
- void operator()(AST::Node *node);
+ void operator()(QQmlJS::AST::Node *node);
void enterGlobalEnvironment(ContextType compilationMode);
- void enterEnvironment(AST::Node *node, ContextType compilationMode, const QString &name);
+ void enterEnvironment(QQmlJS::AST::Node *node, ContextType compilationMode,
+ const QString &name);
void leaveEnvironment();
- void enterQmlFunction(AST::FunctionDeclaration *ast)
+ void enterQmlFunction(QQmlJS::AST::FunctionDeclaration *ast)
{ enterFunction(ast, false); }
protected:
using Visitor::visit;
using Visitor::endVisit;
- void checkDirectivePrologue(AST::StatementList *ast);
+ void checkDirectivePrologue(QQmlJS::AST::StatementList *ast);
- void checkName(const QStringRef &name, const AST::SourceLocation &loc);
+ void checkName(const QStringRef &name, const QQmlJS::AST::SourceLocation &loc);
- bool visit(AST::Program *ast) override;
- void endVisit(AST::Program *) override;
+ bool visit(QQmlJS::AST::Program *ast) override;
+ void endVisit(QQmlJS::AST::Program *) override;
- bool visit(AST::ESModule *ast) override;
- void endVisit(AST::ESModule *) override;
+ bool visit(QQmlJS::AST::ESModule *ast) override;
+ void endVisit(QQmlJS::AST::ESModule *) override;
- bool visit(AST::ExportDeclaration *declaration) override;
- bool visit(AST::ImportDeclaration *declaration) override;
+ bool visit(QQmlJS::AST::ExportDeclaration *declaration) override;
+ bool visit(QQmlJS::AST::ImportDeclaration *declaration) override;
- bool visit(AST::CallExpression *ast) override;
- bool visit(AST::PatternElement *ast) override;
- bool visit(AST::IdentifierExpression *ast) override;
- bool visit(AST::ExpressionStatement *ast) override;
- bool visit(AST::FunctionExpression *ast) override;
- bool visit(AST::TemplateLiteral *ast) override;
- bool visit(AST::SuperLiteral *) override;
- bool visit(AST::FieldMemberExpression *) override;
- bool visit(AST::ArrayPattern *) override;
+ bool visit(QQmlJS::AST::CallExpression *ast) override;
+ bool visit(QQmlJS::AST::PatternElement *ast) override;
+ bool visit(QQmlJS::AST::IdentifierExpression *ast) override;
+ bool visit(QQmlJS::AST::ExpressionStatement *ast) override;
+ bool visit(QQmlJS::AST::FunctionExpression *ast) override;
+ bool visit(QQmlJS::AST::TemplateLiteral *ast) override;
+ bool visit(QQmlJS::AST::SuperLiteral *) override;
+ bool visit(QQmlJS::AST::FieldMemberExpression *) override;
+ bool visit(QQmlJS::AST::ArrayPattern *) override;
- bool enterFunction(AST::FunctionExpression *ast, bool enterName);
+ bool enterFunction(QQmlJS::AST::FunctionExpression *ast, bool enterName);
- void endVisit(AST::FunctionExpression *) override;
+ void endVisit(QQmlJS::AST::FunctionExpression *) override;
- bool visit(AST::ObjectPattern *ast) override;
+ bool visit(QQmlJS::AST::ObjectPattern *ast) override;
- bool visit(AST::PatternProperty *ast) override;
- void endVisit(AST::PatternProperty *) override;
+ bool visit(QQmlJS::AST::PatternProperty *ast) override;
+ void endVisit(QQmlJS::AST::PatternProperty *) override;
- bool visit(AST::FunctionDeclaration *ast) override;
- void endVisit(AST::FunctionDeclaration *) override;
+ bool visit(QQmlJS::AST::FunctionDeclaration *ast) override;
+ void endVisit(QQmlJS::AST::FunctionDeclaration *) override;
- bool visit(AST::ClassExpression *ast) override;
- void endVisit(AST::ClassExpression *) override;
+ bool visit(QQmlJS::AST::ClassExpression *ast) override;
+ void endVisit(QQmlJS::AST::ClassExpression *) override;
- bool visit(AST::ClassDeclaration *ast) override;
- void endVisit(AST::ClassDeclaration *) override;
+ bool visit(QQmlJS::AST::ClassDeclaration *ast) override;
+ void endVisit(QQmlJS::AST::ClassDeclaration *) override;
- bool visit(AST::DoWhileStatement *ast) override;
- bool visit(AST::ForStatement *ast) override;
- void endVisit(AST::ForStatement *) override;
- bool visit(AST::ForEachStatement *ast) override;
- void endVisit(AST::ForEachStatement *) override;
+ bool visit(QQmlJS::AST::DoWhileStatement *ast) override;
+ bool visit(QQmlJS::AST::ForStatement *ast) override;
+ void endVisit(QQmlJS::AST::ForStatement *) override;
+ bool visit(QQmlJS::AST::ForEachStatement *ast) override;
+ void endVisit(QQmlJS::AST::ForEachStatement *) override;
- bool visit(AST::ThisExpression *ast) override;
+ bool visit(QQmlJS::AST::ThisExpression *ast) override;
- bool visit(AST::Block *ast) override;
- void endVisit(AST::Block *ast) override;
+ bool visit(QQmlJS::AST::Block *ast) override;
+ void endVisit(QQmlJS::AST::Block *ast) override;
- bool visit(AST::CaseBlock *ast) override;
- void endVisit(AST::CaseBlock *ast) override;
+ bool visit(QQmlJS::AST::CaseBlock *ast) override;
+ void endVisit(QQmlJS::AST::CaseBlock *ast) override;
- bool visit(AST::Catch *ast) override;
- void endVisit(AST::Catch *ast) override;
+ bool visit(QQmlJS::AST::Catch *ast) override;
+ void endVisit(QQmlJS::AST::Catch *ast) override;
- bool visit(AST::WithStatement *ast) override;
- void endVisit(AST::WithStatement *ast) override;
+ bool visit(QQmlJS::AST::WithStatement *ast) override;
+ void endVisit(QQmlJS::AST::WithStatement *ast) override;
void throwRecursionDepthError() override;
protected:
- bool enterFunction(AST::Node *ast, const QString &name, AST::FormalParameterList *formals, AST::StatementList *body, bool enterName);
+ bool enterFunction(QQmlJS::AST::Node *ast, const QString &name,
+ QQmlJS::AST::FormalParameterList *formals,
+ QQmlJS::AST::StatementList *body, bool enterName);
void calcEscapingVariables();
// fields:
@@ -173,7 +174,7 @@ protected:
ContextType defaultProgramType;
private:
- static constexpr AST::Node *astNodeForGlobalEnvironment = nullptr;
+ static constexpr QQmlJS::AST::Node *astNodeForGlobalEnvironment = nullptr;
};
}
diff --git a/src/qml/compiler/qv4instr_moth_p.h b/src/qml/compiler/qv4instr_moth_p.h
index ec81701160..c0dd696b8a 100644
--- a/src/qml/compiler/qv4instr_moth_p.h
+++ b/src/qml/compiler/qv4instr_moth_p.h
@@ -50,7 +50,7 @@
//
// We mean it.
//
-#include <private/qv4global_p.h>
+
#include <private/qv4staticvalue_p.h>
#include <private/qv4compileddata_p.h> // for CompiledData::CodeOffsetToLine used by the dumper
#include <qendian.h>
diff --git a/src/qml/configure.json b/src/qml/configure.json
index 9313e4594b..3fc1fd528b 100644
--- a/src/qml/configure.json
+++ b/src/qml/configure.json
@@ -178,6 +178,13 @@
"section": "QML",
"condition": "features.thread",
"output": [ "privateFeature" ]
+ },
+ "qml-itemmodel": {
+ "label": "QML Item Model",
+ "purpose": "Provides the item model for item views in QML",
+ "section": "QML",
+ "condition": "features.itemmodel",
+ "output": [ "privateFeature" ]
}
},
diff --git a/src/qml/doc/qtqml.qdocconf b/src/qml/doc/qtqml.qdocconf
index ba4155c08b..cb9fb575b2 100644
--- a/src/qml/doc/qtqml.qdocconf
+++ b/src/qml/doc/qtqml.qdocconf
@@ -1,4 +1,5 @@
include($QT_INSTALL_DOCS/global/qt-module-defaults.qdocconf)
+include($QT_INSTALL_DOCS/config/exampleurl-qtdeclarative.qdocconf)
project = QtQml
description = Qt QML Reference Documentation
diff --git a/src/qml/doc/snippets/qml/events.qml b/src/qml/doc/snippets/qml/events.qml
index 90bf5d7b3d..f437e32890 100644
--- a/src/qml/doc/snippets/qml/events.qml
+++ b/src/qml/doc/snippets/qml/events.qml
@@ -59,8 +59,8 @@ Rectangle {
//! [signal declaration]
signal trigger
- signal send (string notice)
- signal perform (string task, variant object)
+ signal send(notice: string)
+ signal perform(task: string, object: variant)
//! [signal declaration]
//! [signal handler declaration]
@@ -88,7 +88,7 @@ Rectangle {
Rectangle {
id: messenger
- signal send( string person, string notice)
+ signal send(person: string, notice: string)
onSend: {
console.log("For " + person + ", the notice is: " + notice)
@@ -102,7 +102,7 @@ Rectangle {
Rectangle {
id: relay
- signal send( string person, string notice)
+ signal send(person: string, notice: string)
onSend: console.log("Send signal to: " + person + ", " + notice)
Component.onCompleted: {
diff --git a/src/qml/doc/snippets/qml/qtbinding/functions-qml/MyItem.qml b/src/qml/doc/snippets/qml/qtbinding/functions-qml/MyItem.qml
index 073a5dc361..59907c38e7 100644
--- a/src/qml/doc/snippets/qml/qtbinding/functions-qml/MyItem.qml
+++ b/src/qml/doc/snippets/qml/qtbinding/functions-qml/MyItem.qml
@@ -52,7 +52,7 @@
import QtQuick 2.0
Item {
- function myQmlFunction(msg) {
+ function myQmlFunction(msg: string) : string {
console.log("Got message:", msg)
return "some return value"
}
diff --git a/src/qml/doc/snippets/qml/qtbinding/functions-qml/main.cpp b/src/qml/doc/snippets/qml/qtbinding/functions-qml/main.cpp
index c82f71f749..a562eae2b4 100644
--- a/src/qml/doc/snippets/qml/qtbinding/functions-qml/main.cpp
+++ b/src/qml/doc/snippets/qml/qtbinding/functions-qml/main.cpp
@@ -60,13 +60,13 @@ QQmlEngine engine;
QQmlComponent component(&engine, "MyItem.qml");
QObject *object = component.create();
-QVariant returnedValue;
-QVariant msg = "Hello from C++";
+QString returnedValue;
+QString msg = "Hello from C++";
QMetaObject::invokeMethod(object, "myQmlFunction",
- Q_RETURN_ARG(QVariant, returnedValue),
- Q_ARG(QVariant, msg));
+ Q_RETURN_ARG(QString, returnedValue),
+ Q_ARG(QString, msg));
-qDebug() << "QML function returned:" << returnedValue.toString();
+qDebug() << "QML function returned:" << returnedValue;
delete object;
//![0]
}
diff --git a/src/qml/doc/snippets/qml/qtbinding/signals-qml/MyItem.qml b/src/qml/doc/snippets/qml/qtbinding/signals-qml/MyItem.qml
index eebf2db832..aadc89b72c 100644
--- a/src/qml/doc/snippets/qml/qtbinding/signals-qml/MyItem.qml
+++ b/src/qml/doc/snippets/qml/qtbinding/signals-qml/MyItem.qml
@@ -55,7 +55,7 @@ Item {
id: item
width: 100; height: 100
- signal qmlSignal(string msg)
+ signal qmlSignal(msg: string)
MouseArea {
anchors.fill: parent
diff --git a/src/qml/doc/snippets/qml/statemachine/guardcondition.qml b/src/qml/doc/snippets/qml/statemachine/guardcondition.qml
index 8388b96c21..f1ec89b6ba 100644
--- a/src/qml/doc/snippets/qml/statemachine/guardcondition.qml
+++ b/src/qml/doc/snippets/qml/statemachine/guardcondition.qml
@@ -70,7 +70,7 @@ Rectangle {
}
}
// define the signal the SignalTransition is connected with
- signal mysignal(string mystr)
+ signal mysignal(mystr: string)
// on clicking the button emit the signal with a single string argument
onClicked: button.mysignal("test")
}
diff --git a/src/qml/doc/src/cppintegration/interactqmlfromcpp.qdoc b/src/qml/doc/src/cppintegration/interactqmlfromcpp.qdoc
index 9c33979f40..0a824bb5b5 100644
--- a/src/qml/doc/src/cppintegration/interactqmlfromcpp.qdoc
+++ b/src/qml/doc/src/cppintegration/interactqmlfromcpp.qdoc
@@ -166,9 +166,12 @@ updated, and any \c onButtonTextChanged handlers would not be called.
\section2 Invoking QML Methods
-All QML methods are exposed to the meta-object system and can be called from C++
-using QMetaObject::invokeMethod(). Method parameters and return values passed
-from QML are always translated into QVariant values in C++.
+All QML methods are exposed to the meta-object system and can be called from
+C++ using QMetaObject::invokeMethod(). You can specify types for the parameters
+and the return value after the colon character, as shown in the code snippet
+below. This can be useful, for example, when you want to connect a signal in
+C++ with a certain signature to a QML-defined method. If you omit the types,
+the C++ signature will use QVariant.
Here is a C++ application that calls a QML method using
QMetaObject::invokeMethod():
@@ -182,9 +185,12 @@ QMetaObject::invokeMethod():
\li \snippet qml/qtbinding/functions-qml/main.cpp 0
\endtable
-Notice the Q_RETURN_ARG() and Q_ARG() arguments for QMetaObject::invokeMethod()
-must be specified as QVariant types, as this is the generic data type used for
-QML method parameters and return values.
+Notice the parameter and return type specified after the colon. You can use \l
+{QML Basic Types}{basic types} and \l {QML Object Types}{object types} as type
+names.
+
+If the type is omitted in QML, then you must specify QVariant as type with
+Q_RETURN_ARG() and Q_ARG() when calling QMetaObject::invokeMethod.
\section2 Connecting to QML Signals
@@ -210,9 +216,8 @@ QObject::connect(), so that the \c cppSlot() method is called whenever the
\snippet qml/qtbinding/signals-qml/main.cpp 0
\endtable
-When a QML object type is used as a signal parameter, the parameter should
-use \l var as the type, and the value should be received in C++ using the
-QVariant type:
+A QML object type in a signal parameter is translated to a pointer to the class
+in C++:
\table
\row
@@ -226,7 +231,7 @@ QVariant type:
id: item
width: 100; height: 100
- signal qmlSignal(var anObject)
+ signal qmlSignal(anObject: Item)
MouseArea {
anchors.fill: parent
@@ -241,18 +246,16 @@ QVariant type:
{
Q_OBJECT
public slots:
- void cppSlot(const QVariant &v) {
- qDebug() << "Called the C++ slot with value:" << v;
+ void cppSlot(QQuickItem *item) {
+ qDebug() << "Called the C++ slot with item:" << item;
- QQuickItem *item =
- qobject_cast<QQuickItem*>(v.value<QObject*>());
qDebug() << "Item dimensions:" << item->width()
<< item->height();
}
};
int main(int argc, char *argv[]) {
- QApplication app(argc, argv);
+ QGuiApplication app(argc, argv);
QQuickView view(QUrl::fromLocalFile("MyItem.qml"));
QObject *item = view.rootObject();
diff --git a/src/qml/jsruntime/qv4argumentsobject.cpp b/src/qml/jsruntime/qv4argumentsobject.cpp
index 98e0ef9e70..206e2b9aa4 100644
--- a/src/qml/jsruntime/qv4argumentsobject.cpp
+++ b/src/qml/jsruntime/qv4argumentsobject.cpp
@@ -38,13 +38,14 @@
****************************************************************************/
#include <qv4argumentsobject_p.h>
#include <qv4arrayobject_p.h>
-#include <qv4alloca_p.h>
#include <qv4scopedvalue_p.h>
#include <qv4string_p.h>
#include <qv4function_p.h>
#include <qv4jscall_p.h>
#include <qv4symbol_p.h>
+#include <private/qv4alloca_p.h>
+
using namespace QV4;
DEFINE_OBJECT_VTABLE(ArgumentsObject);
diff --git a/src/qml/jsruntime/qv4compilationunitmapper.cpp b/src/qml/jsruntime/qv4compilationunitmapper.cpp
index 350f6f9485..74f34a284d 100644
--- a/src/qml/jsruntime/qv4compilationunitmapper.cpp
+++ b/src/qml/jsruntime/qv4compilationunitmapper.cpp
@@ -39,7 +39,7 @@
#include "qv4compilationunitmapper_p.h"
-#include "qv4compileddata_p.h"
+#include <private/qv4compileddata_p.h>
#include <QFileInfo>
#include <QDateTime>
#include <QCoreApplication>
diff --git a/src/qml/jsruntime/qv4dateobject.cpp b/src/qml/jsruntime/qv4dateobject.cpp
index 21c6a5d06b..1b26608bf3 100644
--- a/src/qml/jsruntime/qv4dateobject.cpp
+++ b/src/qml/jsruntime/qv4dateobject.cpp
@@ -52,8 +52,6 @@
#include <time.h>
-#include <private/qqmljsengine_p.h>
-
#include <wtf/MathExtras.h>
#if defined(Q_OS_LINUX) && QT_CONFIG(timezone)
diff --git a/src/qml/jsruntime/qv4debugging_p.h b/src/qml/jsruntime/qv4debugging_p.h
index 9b41bb6e7a..52263105fa 100644
--- a/src/qml/jsruntime/qv4debugging_p.h
+++ b/src/qml/jsruntime/qv4debugging_p.h
@@ -52,6 +52,7 @@
//
#include "qv4global_p.h"
+#include <private/qv4staticvalue_p.h>
#include <QtCore/qobject.h>
QT_BEGIN_NAMESPACE
diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp
index 0d3ae71b05..be0de09d79 100644
--- a/src/qml/jsruntime/qv4engine.cpp
+++ b/src/qml/jsruntime/qv4engine.cpp
@@ -39,8 +39,6 @@
#include <qv4engine_p.h>
#include <private/qv4compileddata_p.h>
-#include <private/qv4compiler_p.h>
-#include <private/qv4compilercontext_p.h>
#include <private/qv4codegen_p.h>
#include <private/qqmljsdiagnosticmessage_p.h>
diff --git a/src/qml/jsruntime/qv4engine_p.h b/src/qml/jsruntime/qv4engine_p.h
index ce25ab16b1..d233347060 100644
--- a/src/qml/jsruntime/qv4engine_p.h
+++ b/src/qml/jsruntime/qv4engine_p.h
@@ -57,7 +57,6 @@
#include <private/qintrusivelist_p.h>
#include "qv4enginebase_p.h"
#include <private/qqmlrefcount_p.h>
-#include <private/qqmljsengine_p.h>
#include <private/qqmldelayedcallqueue_p.h>
#include <QtCore/qelapsedtimer.h>
#include <QtCore/qmutex.h>
diff --git a/src/qml/jsruntime/qv4errorobject.cpp b/src/qml/jsruntime/qv4errorobject.cpp
index c6d6c77d11..525d3458f4 100644
--- a/src/qml/jsruntime/qv4errorobject.cpp
+++ b/src/qml/jsruntime/qv4errorobject.cpp
@@ -47,7 +47,7 @@
#include "qv4string_p.h"
#include <private/qv4mm_p.h>
-#include <qv4codegen_p.h>
+#include <private/qv4codegen_p.h>
#ifndef Q_OS_WIN
# include <time.h>
diff --git a/src/qml/jsruntime/qv4executablecompilationunit.cpp b/src/qml/jsruntime/qv4executablecompilationunit.cpp
index 492d1f4d03..a9283cfa54 100644
--- a/src/qml/jsruntime/qv4executablecompilationunit.cpp
+++ b/src/qml/jsruntime/qv4executablecompilationunit.cpp
@@ -44,11 +44,11 @@
#include <private/qv4lookup_p.h>
#include <private/qv4qmlcontext_p.h>
#include <private/qv4identifiertable_p.h>
-#include <private/qv4instr_moth_p.h>
#include <private/qv4objectproto_p.h>
#include <private/qqmlengine_p.h>
#include <private/qv4qobjectwrapper_p.h>
#include <private/qqmlvaluetypewrapper_p.h>
+#include <private/qqmlscriptdata_p.h>
#include <private/qv4module_p.h>
#include <private/qv4compilationunitmapper_p.h>
#include <private/qml_compile_hash_p.h>
@@ -784,7 +784,7 @@ QString ExecutableCompilationUnit::bindingValueAsString(const CompiledData::Bind
case Binding::Type_Boolean:
return binding->value.b ? QStringLiteral("true") : QStringLiteral("false");
case Binding::Type_Number:
- return QString::number(bindingValueAsNumber(binding));
+ return QString::number(bindingValueAsNumber(binding), 'g', QLocale::FloatingPointShortest);
case Binding::Type_Invalid:
return QString();
#if !QT_CONFIG(translation)
diff --git a/src/qml/jsruntime/qv4executablecompilationunit_p.h b/src/qml/jsruntime/qv4executablecompilationunit_p.h
index 010b8a2fd0..6eef3b12c3 100644
--- a/src/qml/jsruntime/qv4executablecompilationunit_p.h
+++ b/src/qml/jsruntime/qv4executablecompilationunit_p.h
@@ -61,9 +61,13 @@
QT_BEGIN_NAMESPACE
+class QQmlScriptData;
class QQmlEnginePrivate;
namespace QV4 {
+// index is per-object binding index
+typedef QVector<QQmlPropertyData*> BindingPropertyData;
+
class CompilationUnitMapper;
struct ResolvedTypeReference;
// map from name index
@@ -131,7 +135,7 @@ public:
// index is object index. This allows fast access to the
// property data when initializing bindings, avoiding expensive
// lookups by string (property name).
- QVector<CompiledData::BindingPropertyData> bindingPropertyDataPerObject;
+ QVector<BindingPropertyData> bindingPropertyDataPerObject;
// mapping from component object index (CompiledData::Unit object index that points to component) to identifier hash of named objects
// this is initialized on-demand by QQmlContextData
diff --git a/src/qml/jsruntime/qv4function.cpp b/src/qml/jsruntime/qv4function.cpp
index d870cec68a..aeb4835c40 100644
--- a/src/qml/jsruntime/qv4function.cpp
+++ b/src/qml/jsruntime/qv4function.cpp
@@ -100,9 +100,9 @@ Function::Function(ExecutionEngine *engine, ExecutableCompilationUnit *unit,
for (quint32 i = 0; i < compiledFunction->nLocals; ++i)
ic = ic->addMember(engine->identifierTable->asPropertyKey(compilationUnit->runtimeStrings[localsIndices[i]]), Attr_NotConfigurable);
- const quint32_le *formalsIndices = compiledFunction->formalsTable();
+ const CompiledData::Parameter *formalsIndices = compiledFunction->formalsTable();
for (quint32 i = 0; i < compiledFunction->nFormals; ++i)
- ic = ic->addMember(engine->identifierTable->asPropertyKey(compilationUnit->runtimeStrings[formalsIndices[i]]), Attr_NotConfigurable);
+ ic = ic->addMember(engine->identifierTable->asPropertyKey(compilationUnit->runtimeStrings[formalsIndices[i].nameIndex]), Attr_NotConfigurable);
internalClass = ic->d();
nFormals = compiledFunction->nFormals;
diff --git a/src/qml/jsruntime/qv4function_p.h b/src/qml/jsruntime/qv4function_p.h
index cbbb61c68c..51960863c4 100644
--- a/src/qml/jsruntime/qv4function_p.h
+++ b/src/qml/jsruntime/qv4function_p.h
@@ -53,6 +53,7 @@
#include "qv4global_p.h"
#include <private/qv4executablecompilationunit_p.h>
#include <private/qv4context_p.h>
+#include <private/qv4string_p.h>
namespace JSC {
class MacroAssemblerCodeRef;
@@ -93,7 +94,7 @@ public:
return static_cast<QV4::ExecutableCompilationUnit *>(compilationUnit);
}
- QV4::Heap::String *runtimeString(uint i)
+ QV4::Heap::String *runtimeString(uint i) const
{
return compilationUnit->runtimeStrings[i];
}
@@ -120,7 +121,7 @@ public:
void updateInternalClass(ExecutionEngine *engine, const QList<QByteArray> &parameters);
inline Heap::String *name() const {
- return compilationUnit->runtimeStrings[compiledFunction->nameIndex];
+ return runtimeString(compiledFunction->nameIndex);
}
static QString prettyName(const Function *function, const void *address);
diff --git a/src/qml/jsruntime/qv4functionobject.cpp b/src/qml/jsruntime/qv4functionobject.cpp
index b1b0d67e64..6fb7946023 100644
--- a/src/qml/jsruntime/qv4functionobject.cpp
+++ b/src/qml/jsruntime/qv4functionobject.cpp
@@ -59,10 +59,10 @@
#include "private/qqmlbuiltinfunctions_p.h"
#include <private/qv4jscall_p.h>
#include <private/qv4vme_moth_p.h>
+#include <private/qv4alloca_p.h>
#include <QtCore/QDebug>
#include <algorithm>
-#include "qv4alloca_p.h"
#include "qv4profiling_p.h"
using namespace QV4;
diff --git a/src/qml/jsruntime/qv4global_p.h b/src/qml/jsruntime/qv4global_p.h
index ebd21b3543..c6a737b467 100644
--- a/src/qml/jsruntime/qv4global_p.h
+++ b/src/qml/jsruntime/qv4global_p.h
@@ -52,6 +52,7 @@
//
#include <QtCore/qglobal.h>
+#include <private/qv4compilerglobal_p.h>
#include <QString>
#ifdef QT_NO_DEBUG
@@ -207,11 +208,6 @@ struct SetMapObject;
struct PromiseObject;
struct PromiseCapability;
-// ReturnedValue is used to return values from runtime methods
-// the type has to be a primitive type (no struct or union), so that the compiler
-// will return it in a register on all platforms.
-// It will be returned in rax on x64, [eax,edx] on x86 and [r0,r1] on arm
-typedef quint64 ReturnedValue;
struct CallData;
struct Scope;
struct ScopedValue;
@@ -341,13 +337,6 @@ struct Q_QML_EXPORT StackFrame {
};
typedef QVector<StackFrame> StackTrace;
-enum class ObjectLiteralArgument {
- Value,
- Method,
- Getter,
- Setter
-};
-
namespace JIT {
enum class CallResultDestination {
diff --git a/src/qml/jsruntime/qv4globalobject.cpp b/src/qml/jsruntime/qv4globalobject.cpp
index becdc3bc55..bb81fb52d4 100644
--- a/src/qml/jsruntime/qv4globalobject.cpp
+++ b/src/qml/jsruntime/qv4globalobject.cpp
@@ -49,18 +49,14 @@
#include "qv4string_p.h"
#include "qv4jscall_p.h"
-#include <private/qqmljsengine_p.h>
-#include <private/qqmljslexer_p.h>
-#include <private/qqmljsparser_p.h>
-#include <private/qqmljsast_p.h>
-#include <qv4codegen_p.h>
+#include <private/qv4codegen_p.h>
+#include <private/qv4alloca_p.h>
#include "private/qlocale_tools_p.h"
#include "private/qtools_p.h"
#include <QtCore/QDebug>
#include <QtCore/QString>
#include <iostream>
-#include "qv4alloca_p.h"
#include <wtf/MathExtras.h>
diff --git a/src/qml/jsruntime/qv4include.cpp b/src/qml/jsruntime/qv4include.cpp
index c0885a418c..92face6f94 100644
--- a/src/qml/jsruntime/qv4include.cpp
+++ b/src/qml/jsruntime/qv4include.cpp
@@ -167,7 +167,6 @@ void QV4Include::finished()
QByteArray data = m_reply->readAll();
QString code = QString::fromUtf8(data);
- QmlIR::Document::removeScriptPragmas(code);
QV4::Scoped<QV4::QmlContext> qml(scope, m_qmlContext.value());
QV4::Script script(v4, qml, /*parse as QML binding*/false, code, m_url.toString());
diff --git a/src/qml/jsruntime/qv4math_p.h b/src/qml/jsruntime/qv4math_p.h
index bca4c2ef66..6632d69c27 100644
--- a/src/qml/jsruntime/qv4math_p.h
+++ b/src/qml/jsruntime/qv4math_p.h
@@ -52,7 +52,7 @@
#include <qglobal.h>
-#include <QtQml/private/qv4staticvalue_p.h>
+#include <private/qv4staticvalue_p.h>
#include <QtCore/qnumeric.h>
#include <QtCore/private/qnumeric_p.h>
#include <cmath>
diff --git a/src/qml/jsruntime/qv4qobjectwrapper.cpp b/src/qml/jsruntime/qv4qobjectwrapper.cpp
index 8a4adfe69a..c36da3815d 100644
--- a/src/qml/jsruntime/qv4qobjectwrapper.cpp
+++ b/src/qml/jsruntime/qv4qobjectwrapper.cpp
@@ -57,6 +57,7 @@
#include <private/qv4variantobject_p.h>
#include <private/qv4identifiertable_p.h>
#include <private/qv4lookup_p.h>
+#include <private/qv4qmlcontext_p.h>
#if QT_CONFIG(qml_sequence_object)
#include <private/qv4sequenceobject_p.h>
@@ -80,7 +81,9 @@
#include <QtCore/qtimer.h>
#include <QtCore/qatomic.h>
#include <QtCore/qmetaobject.h>
+#if QT_CONFIG(qml_itemmodel)
#include <QtCore/qabstractitemmodel.h>
+#endif
#include <QtCore/qloggingcategory.h>
#include <vector>
@@ -1233,7 +1236,9 @@ private:
std::vector<bool> *stdVectorBoolPtr;
std::vector<QString> *stdVectorQStringPtr;
std::vector<QUrl> *stdVectorQUrlPtr;
+#if QT_CONFIG(qml_itemmodel)
std::vector<QModelIndex> *stdVectorQModelIndexPtr;
+#endif
char allocData[MaxSizeOf7<QVariant,
QString,
@@ -1693,8 +1698,10 @@ void *CallArgument::dataPtr()
return stdVectorQStringPtr;
else if (type == qMetaTypeId<std::vector<QUrl>>())
return stdVectorQUrlPtr;
+#if QT_CONFIG(qml_itemmodel)
else if (type == qMetaTypeId<std::vector<QModelIndex>>())
return stdVectorQModelIndexPtr;
+#endif
else if (type != 0)
return (void *)&allocData;
return nullptr;
@@ -1845,7 +1852,10 @@ bool CallArgument::fromValue(int callType, QV4::ExecutionEngine *engine, const Q
|| callType == qMetaTypeId<std::vector<bool>>()
|| callType == qMetaTypeId<std::vector<QString>>()
|| callType == qMetaTypeId<std::vector<QUrl>>()
- || callType == qMetaTypeId<std::vector<QModelIndex>>()) {
+#if QT_CONFIG(qml_itemmodel)
+ || callType == qMetaTypeId<std::vector<QModelIndex>>()
+#endif
+ ) {
queryEngine = true;
const QV4::Object* object = value.as<QV4::Object>();
if (callType == qMetaTypeId<std::vector<int>>()) {
@@ -1863,9 +1873,11 @@ bool CallArgument::fromValue(int callType, QV4::ExecutionEngine *engine, const Q
} else if (callType == qMetaTypeId<std::vector<QUrl>>()) {
stdVectorQUrlPtr = nullptr;
fromContainerValue<std::vector<QUrl>>(object, callType, &CallArgument::stdVectorQUrlPtr, queryEngine);
+#if QT_CONFIG(qml_itemmodel)
} else if (callType == qMetaTypeId<std::vector<QModelIndex>>()) {
stdVectorQModelIndexPtr = nullptr;
fromContainerValue<std::vector<QModelIndex>>(object, callType, &CallArgument::stdVectorQModelIndexPtr, queryEngine);
+#endif
}
#endif
} else if (QMetaType::typeFlags(callType)
diff --git a/src/qml/jsruntime/qv4regexpobject.cpp b/src/qml/jsruntime/qv4regexpobject.cpp
index 64aba1d85c..c1a42c4afa 100644
--- a/src/qml/jsruntime/qv4regexpobject.cpp
+++ b/src/qml/jsruntime/qv4regexpobject.cpp
@@ -56,7 +56,7 @@
#include <cassert>
#include <typeinfo>
#include <iostream>
-#include "qv4alloca_p.h"
+#include <private/qv4alloca_p.h>
QT_BEGIN_NAMESPACE
diff --git a/src/qml/jsruntime/qv4runtime.cpp b/src/qml/jsruntime/qv4runtime.cpp
index 38cce2a7a9..8a7cbdfb2a 100644
--- a/src/qml/jsruntime/qv4runtime.cpp
+++ b/src/qml/jsruntime/qv4runtime.cpp
@@ -59,6 +59,7 @@
#include <private/qqmltypewrapper_p.h>
#include <private/qqmlengine_p.h>
#include <private/qqmljavascriptexpression_p.h>
+#include <private/qqmljsast_p.h>
#include "qv4qobjectwrapper_p.h"
#include "qv4symbol_p.h"
#include "qv4generatorobject_p.h"
diff --git a/src/qml/jsruntime/qv4runtimeapi_p.h b/src/qml/jsruntime/qv4runtimeapi_p.h
index 13a73b7046..05ffb84d58 100644
--- a/src/qml/jsruntime/qv4runtimeapi_p.h
+++ b/src/qml/jsruntime/qv4runtimeapi_p.h
@@ -51,6 +51,7 @@
//
#include <private/qv4global_p.h>
+#include <private/qv4staticvalue_p.h>
QT_BEGIN_NAMESPACE
diff --git a/src/qml/jsruntime/qv4runtimecodegen.cpp b/src/qml/jsruntime/qv4runtimecodegen.cpp
index 8d324acbd0..162d75db63 100644
--- a/src/qml/jsruntime/qv4runtimecodegen.cpp
+++ b/src/qml/jsruntime/qv4runtimecodegen.cpp
@@ -39,9 +39,10 @@
#include "qv4engine_p.h"
#include "qv4runtimecodegen_p.h"
-#include "qv4compilerscanfunctions_p.h"
+#include <private/qv4compilerscanfunctions_p.h>
using namespace QV4;
+using namespace QQmlJS;
void RuntimeCodegen::generateFromFunctionExpression(const QString &fileName,
const QString &sourceCode,
diff --git a/src/qml/jsruntime/qv4runtimecodegen_p.h b/src/qml/jsruntime/qv4runtimecodegen_p.h
index 006a6a3cde..71aaf1fb55 100644
--- a/src/qml/jsruntime/qv4runtimecodegen_p.h
+++ b/src/qml/jsruntime/qv4runtimecodegen_p.h
@@ -66,11 +66,11 @@ public:
void generateFromFunctionExpression(const QString &fileName,
const QString &sourceCode,
- AST::FunctionExpression *ast,
+ QQmlJS::AST::FunctionExpression *ast,
Compiler::Module *module);
- void throwSyntaxError(const AST::SourceLocation &loc, const QString &detail) override;
- void throwReferenceError(const AST::SourceLocation &loc, const QString &detail) override;
+ void throwSyntaxError(const QQmlJS::AST::SourceLocation &loc, const QString &detail) override;
+ void throwReferenceError(const QQmlJS::AST::SourceLocation &loc, const QString &detail) override;
private:
ExecutionEngine *engine;
diff --git a/src/qml/jsruntime/qv4script.cpp b/src/qml/jsruntime/qv4script.cpp
index c463812590..2fab9e4b7b 100644
--- a/src/qml/jsruntime/qv4script.cpp
+++ b/src/qml/jsruntime/qv4script.cpp
@@ -60,6 +60,7 @@
#include <QScopedValueRollback>
using namespace QV4;
+using namespace QQmlJS;
Script::Script(ExecutionEngine *v4, QmlContext *qml, const QQmlRefPointer<ExecutableCompilationUnit> &compilationUnit)
: line(1), column(0), context(v4->rootContext()), strictMode(false), inheritContext(true), parsed(false)
@@ -245,7 +246,6 @@ Script *Script::createFromFileOrCache(ExecutionEngine *engine, QmlContext *qmlCo
QByteArray data = f.readAll();
QString sourceCode = QString::fromUtf8(data);
- QmlIR::Document::removeScriptPragmas(sourceCode);
auto result = new QV4::Script(engine, qmlContext, /*parseAsBinding*/false, sourceCode, originalUrl.toString());
result->contextType = QV4::Compiler::ContextType::ScriptImportedByQML;
diff --git a/src/qml/jsruntime/qv4sequenceobject.cpp b/src/qml/jsruntime/qv4sequenceobject.cpp
index 1eef12a491..77a98247ac 100644
--- a/src/qml/jsruntime/qv4sequenceobject.cpp
+++ b/src/qml/jsruntime/qv4sequenceobject.cpp
@@ -49,8 +49,10 @@
#include "qv4runtime_p.h"
#include "qv4objectiterator_p.h"
#include <private/qqmlvaluetypewrapper_p.h>
+#if QT_CONFIG(qml_itemmodel)
#include <private/qqmlmodelindexvaluetype_p.h>
#include <QtCore/qabstractitemmodel.h>
+#endif
#include <algorithm>
@@ -75,6 +77,16 @@ static void generateWarning(QV4::ExecutionEngine *v4, const QString& description
}
// F(elementType, elementTypeName, sequenceType, defaultValue)
+#if QT_CONFIG(qml_itemmodel)
+#define FOREACH_QML_SEQUENCE_TYPE_FOR_ITEMMODEL(F) \
+ F(QModelIndex, QModelIndex, QModelIndexList, QModelIndex()) \
+ F(QModelIndex, QModelIndexVector, QVector<QModelIndex>, QModelIndex()) \
+ F(QModelIndex, QModelIndexStdVector, std::vector<QModelIndex>, QModelIndex()) \
+ F(QItemSelectionRange, QItemSelectionRange, QItemSelection, QItemSelectionRange())
+#else
+#define FOREACH_QML_SEQUENCE_TYPE_FOR_ITEMMODEL(F)
+#endif
+
#define FOREACH_QML_SEQUENCE_TYPE(F) \
F(int, IntVector, QVector<int>, 0) \
F(qreal, RealVector, QVector<qreal>, 0.0) \
@@ -92,10 +104,7 @@ static void generateWarning(QV4::ExecutionEngine *v4, const QString& description
F(QUrl, Url, QList<QUrl>, QUrl()) \
F(QUrl, UrlVector, QVector<QUrl>, QUrl()) \
F(QUrl, UrlStdVector, std::vector<QUrl>, QUrl()) \
- F(QModelIndex, QModelIndex, QModelIndexList, QModelIndex()) \
- F(QModelIndex, QModelIndexVector, QVector<QModelIndex>, QModelIndex()) \
- F(QModelIndex, QModelIndexStdVector, std::vector<QModelIndex>, QModelIndex()) \
- F(QItemSelectionRange, QItemSelectionRange, QItemSelection, QItemSelectionRange())
+ FOREACH_QML_SEQUENCE_TYPE_FOR_ITEMMODEL(F)
static QV4::ReturnedValue convertElementToValue(QV4::ExecutionEngine *engine, const QString &element)
{
@@ -112,6 +121,7 @@ static QV4::ReturnedValue convertElementToValue(QV4::ExecutionEngine *engine, co
return engine->newString(element.toString())->asReturnedValue();
}
+#if QT_CONFIG(qml_itemmodel)
static QV4::ReturnedValue convertElementToValue(QV4::ExecutionEngine *engine, const QModelIndex &element)
{
const QMetaObject *vtmo = QQmlValueTypeFactory::metaObjectForMetaType(QMetaType::QModelIndex);
@@ -124,6 +134,7 @@ static QV4::ReturnedValue convertElementToValue(QV4::ExecutionEngine *engine, co
const QMetaObject *vtmo = QQmlValueTypeFactory::metaObjectForMetaType(metaTypeId);
return QV4::QQmlValueTypeWrapper::create(engine, QVariant::fromValue(element), vtmo, metaTypeId);
}
+#endif
static QV4::ReturnedValue convertElementToValue(QV4::ExecutionEngine *, qreal element)
{
@@ -150,6 +161,7 @@ static QString convertElementToString(const QUrl &element)
return element.toString();
}
+#if QT_CONFIG(qml_itemmodel)
static QString convertElementToString(const QModelIndex &element)
{
return reinterpret_cast<const QQmlModelIndexValueType *>(&element)->toString();
@@ -159,6 +171,7 @@ static QString convertElementToString(const QItemSelectionRange &element)
{
return reinterpret_cast<const QQmlItemSelectionRangeValueType *>(&element)->toString();
}
+#endif
static QString convertElementToString(qreal element)
{
@@ -192,6 +205,7 @@ template <> QUrl convertValueToElement(const Value &value)
return QUrl(value.toQString());
}
+#if QT_CONFIG(qml_itemmodel)
template <> QModelIndex convertValueToElement(const Value &value)
{
const QQmlValueTypeWrapper *v = value.as<QQmlValueTypeWrapper>();
@@ -207,6 +221,7 @@ template <> QItemSelectionRange convertValueToElement(const Value &value)
return v->toVariant().value<QItemSelectionRange>();
return QItemSelectionRange();
}
+#endif
template <> qreal convertValueToElement(const Value &value)
{
@@ -667,6 +682,7 @@ typedef QQmlSequence<QVector<QUrl> > QQmlUrlVectorList;
DEFINE_OBJECT_TEMPLATE_VTABLE(QQmlUrlVectorList);
typedef QQmlSequence<std::vector<QUrl> > QQmlUrlStdVectorList;
DEFINE_OBJECT_TEMPLATE_VTABLE(QQmlUrlStdVectorList);
+#if QT_CONFIG(qml_itemmodel)
typedef QQmlSequence<QModelIndexList> QQmlQModelIndexList;
DEFINE_OBJECT_TEMPLATE_VTABLE(QQmlQModelIndexList);
typedef QQmlSequence<QVector<QModelIndex> > QQmlQModelIndexVectorList;
@@ -675,6 +691,7 @@ typedef QQmlSequence<std::vector<QModelIndex> > QQmlQModelIndexStdVectorList;
DEFINE_OBJECT_TEMPLATE_VTABLE(QQmlQModelIndexStdVectorList);
typedef QQmlSequence<QItemSelection> QQmlQItemSelectionRangeList;
DEFINE_OBJECT_TEMPLATE_VTABLE(QQmlQItemSelectionRangeList);
+#endif
typedef QQmlSequence<QList<bool> > QQmlBoolList;
DEFINE_OBJECT_TEMPLATE_VTABLE(QQmlBoolList);
typedef QQmlSequence<QList<qreal> > QQmlRealList;
diff --git a/src/qml/jsruntime/qv4stringobject.cpp b/src/qml/jsruntime/qv4stringobject.cpp
index 227df4014e..9b4a2d575e 100644
--- a/src/qml/jsruntime/qv4stringobject.cpp
+++ b/src/qml/jsruntime/qv4stringobject.cpp
@@ -45,7 +45,7 @@
#include <private/qv4mm_p.h>
#include "qv4scopedvalue_p.h"
#include "qv4symbol_p.h"
-#include "qv4alloca_p.h"
+#include <private/qv4alloca_p.h>
#include "qv4jscall_p.h"
#include "qv4stringiterator_p.h"
#include <QtCore/QDateTime>
diff --git a/src/qml/jsruntime/qv4vme_moth.cpp b/src/qml/jsruntime/qv4vme_moth.cpp
index b2bbe985d3..b4c34d60fa 100644
--- a/src/qml/jsruntime/qv4vme_moth.cpp
+++ b/src/qml/jsruntime/qv4vme_moth.cpp
@@ -38,11 +38,11 @@
****************************************************************************/
#include "qv4vme_moth_p.h"
-#include "qv4instr_moth_p.h"
#include <QtCore/qjsondocument.h>
#include <QtCore/qjsonobject.h>
+#include <private/qv4instr_moth_p.h>
#include <private/qv4value_p.h>
#include <private/qv4debugging_p.h>
#include <private/qv4function_p.h>
@@ -56,11 +56,10 @@
#include <private/qv4profiling_p.h>
#include <private/qv4jscall_p.h>
#include <private/qv4generatorobject_p.h>
+#include <private/qv4alloca_p.h>
#include <private/qqmljavascriptexpression_p.h>
#include <iostream>
-#include "qv4alloca_p.h"
-
#if QT_CONFIG(qml_jit)
#include <private/qv4baselinejit_p.h>
#endif
diff --git a/src/qml/jsruntime/qv4vme_moth_p.h b/src/qml/jsruntime/qv4vme_moth_p.h
index 8a76e60f20..b3944f5454 100644
--- a/src/qml/jsruntime/qv4vme_moth_p.h
+++ b/src/qml/jsruntime/qv4vme_moth_p.h
@@ -52,6 +52,7 @@
//
#include <private/qv4global_p.h>
+#include <private/qv4staticvalue_p.h>
QT_BEGIN_NAMESPACE
diff --git a/src/qml/memory/qv4mm.cpp b/src/qml/memory/qv4mm.cpp
index 6ee36cbfcf..3465036c86 100644
--- a/src/qml/memory/qv4mm.cpp
+++ b/src/qml/memory/qv4mm.cpp
@@ -46,6 +46,7 @@
#include <QtCore/qalgorithms.h>
#include <QtCore/private/qnumeric_p.h>
#include <QtCore/qloggingcategory.h>
+#include <private/qv4alloca_p.h>
#include <qqmlengine.h>
#include "PageReservation.h"
#include "PageAllocation.h"
@@ -59,7 +60,6 @@
#include <iostream>
#include <cstdlib>
#include <algorithm>
-#include "qv4alloca_p.h"
#include "qv4profiling_p.h"
#include "qv4mapobject_p.h"
#include "qv4setobject_p.h"
diff --git a/src/qml/parser/parser.pri b/src/qml/parser/parser.pri
index 2c0175c94b..e15730f5d1 100644
--- a/src/qml/parser/parser.pri
+++ b/src/qml/parser/parser.pri
@@ -4,11 +4,9 @@ HEADERS += \
$$PWD/qqmljsastvisitor_p.h \
$$PWD/qqmljsengine_p.h \
$$PWD/qqmljslexer_p.h \
- $$PWD/qqmljsmemorypool_p.h \
$$PWD/qqmljsglobal_p.h \
$$PWD/qqmljskeywords_p.h \
$$PWD/qqmljsengine_p.h \
- $$PWD/qqmljsglobal_p.h \
$$PWD/qqmljssourcelocation_p.h
SOURCES += \
diff --git a/src/qml/parser/qqmljs.g b/src/qml/parser/qqmljs.g
index daaa402ef1..bdc4a0bb46 100644
--- a/src/qml/parser/qqmljs.g
+++ b/src/qml/parser/qqmljs.g
@@ -299,6 +299,9 @@ public:
AST::ExportsList *ExportsList;
AST::ExportClause *ExportClause;
AST::ExportDeclaration *ExportDeclaration;
+ AST::TypeAnnotation *TypeAnnotation;
+ AST::TypeArgumentList *TypeArgumentList;
+ AST::Type *Type;
AST::UiProgram *UiProgram;
AST::UiHeaderItemList *UiHeaderItemList;
@@ -424,6 +427,8 @@ protected:
diagnostic_messages.append(compileError(location, message));
}
+ bool ensureNoFunctionTypeAnnotations(AST::TypeAnnotation *returnTypeAnnotation, AST::FormalParameterList *formals);
+
protected:
Engine *driver;
MemoryPool *pool;
@@ -594,6 +599,21 @@ int Parser::lookaheadToken(Lexer *lexer)
return yytoken;
}
+bool Parser::ensureNoFunctionTypeAnnotations(AST::TypeAnnotation *returnValueAnnotation, AST::FormalParameterList *formals)
+{
+ for (auto formal = formals; formal; formal = formal->next) {
+ if (formal->element && formal->element->typeAnnotation) {
+ syntaxError(formal->element->typeAnnotation->firstSourceLocation(), "Type annotations are not permitted in function parameters in JavaScript functions");
+ return false;
+ }
+ }
+ if (returnValueAnnotation) {
+ syntaxError(returnValueAnnotation->firstSourceLocation(), "Type annotations are not permitted for the return value of JavaScript functions");
+ return false;
+ }
+ return true;
+}
+
//#define PARSER_DEBUG
bool Parser::parse(int startToken)
@@ -1086,6 +1106,17 @@ UiParameterListOpt: UiParameterList;
} break;
./
+UiParameterList: QmlIdentifier T_COLON UiPropertyType;
+/.
+ case $rule_number: {
+ AST::UiParameterList *node = new (pool) AST::UiParameterList(sym(3).UiQualifiedId->finish(), stringRef(1));
+ node->identifierToken = loc(1);
+ node->colonToken = loc(2);
+ node->propertyTypeToken = loc(3);
+ sym(1).Node = node;
+ } break;
+./
+
UiParameterList: UiPropertyType QmlIdentifier;
/.
case $rule_number: {
@@ -1096,6 +1127,18 @@ UiParameterList: UiPropertyType QmlIdentifier;
} break;
./
+UiParameterList: UiParameterList T_COMMA QmlIdentifier T_COLON UiPropertyType;
+/.
+ case $rule_number: {
+ AST::UiParameterList *node = new (pool) AST::UiParameterList(sym(1).UiParameterList, sym(5).UiQualifiedId->finish(), stringRef(3));
+ node->propertyTypeToken = loc(5);
+ node->commaToken = loc(2);
+ node->identifierToken = loc(3);
+ node->colonToken = loc(4);
+ sym(1).Node = node;
+ } break;
+./
+
UiParameterList: UiParameterList T_COMMA UiPropertyType QmlIdentifier;
/.
case $rule_number: {
@@ -1355,7 +1398,7 @@ UiObjectMember: T_READONLY T_PROPERTY UiPropertyType QmlIdentifier T_COLON Expre
} break;
./
-UiObjectMember: FunctionDeclaration;
+UiObjectMember: FunctionDeclarationWithTypes;
/.
case $rule_number: {
sym(1).Node = new (pool) AST::UiSourceElement(sym(1).Node);
@@ -1471,6 +1514,63 @@ IdentifierReference: JsIdentifier;
BindingIdentifier: IdentifierReference;
--------------------------------------------------------------------------------------------------------
+-- Types
+--------------------------------------------------------------------------------------------------------
+
+TypeArguments: Type;
+/.
+ case $rule_number: {
+ sym(1).TypeArgumentList = new (pool) AST::TypeArgumentList(sym(1).Type);
+ } break;
+./
+
+TypeArguments: TypeArguments T_COMMA Type;
+/.
+ case $rule_number: {
+ sym(1).TypeArgumentList = new (pool) AST::TypeArgumentList(sym(1).TypeArgumentList, sym(3).Type);
+ } break;
+./
+
+Type: UiQualifiedId T_LT TypeArguments T_GT;
+/.
+ case $rule_number: {
+ sym(1).Type = new (pool) AST::Type(sym(1).UiQualifiedId, sym(3).TypeArgumentList->finish());
+ } break;
+./
+
+Type: T_RESERVED_WORD;
+/.
+ case $rule_number: {
+ AST::UiQualifiedId *id = new (pool) AST::UiQualifiedId(stringRef(1));
+ id->identifierToken = loc(1);
+ sym(1).Type = new (pool) AST::Type(id->finish());
+ } break;
+./
+
+Type: UiQualifiedId;
+/.
+ case $rule_number: {
+ sym(1).Type = new (pool) AST::Type(sym(1).UiQualifiedId);
+ } break;
+./
+
+TypeAnnotation: T_COLON Type;
+/.
+ case $rule_number: {
+ sym(1).TypeAnnotation = new (pool) AST::TypeAnnotation(sym(2).Type);
+ sym(1).TypeAnnotation->colonToken = loc(1);
+ } break;
+./
+
+TypeAnnotationOpt: TypeAnnotation;
+TypeAnnotationOpt: ;
+/.
+ case $rule_number: {
+ sym(1).TypeAnnotation = nullptr;
+ } break;
+./
+
+--------------------------------------------------------------------------------------------------------
-- Expressions
--------------------------------------------------------------------------------------------------------
@@ -2851,7 +2951,14 @@ VarDeclaration: Var VariableDeclarationList;
VarDeclaration_In: Var VariableDeclarationList_In;
/.
case $rule_number: {
- AST::VariableStatement *node = new (pool) AST::VariableStatement(sym(2).VariableDeclarationList->finish(sym(1).scope));
+ AST::VariableDeclarationList *declarations = sym(2).VariableDeclarationList->finish(sym(1).scope);
+ for (auto it = declarations; it; it = it->next) {
+ if (it->declaration && it->declaration->typeAnnotation) {
+ syntaxError(it->declaration->typeAnnotation->firstSourceLocation(), "Type annotations are not permitted in variable declarations");
+ return false;
+ }
+ }
+ AST::VariableStatement *node = new (pool) AST::VariableStatement(declarations);
node->declarationKindToken = loc(1);
sym(1).Node = node;
} break;
@@ -2888,22 +2995,22 @@ VariableDeclarationList_In: VariableDeclarationList_In T_COMMA VariableDeclarati
} break;
./
-LexicalBinding: BindingIdentifier InitializerOpt;
+LexicalBinding: BindingIdentifier TypeAnnotationOpt InitializerOpt;
/. case $rule_number: Q_FALLTHROUGH(); ./
-LexicalBinding_In: BindingIdentifier InitializerOpt_In;
+LexicalBinding_In: BindingIdentifier TypeAnnotationOpt InitializerOpt_In;
/. case $rule_number: Q_FALLTHROUGH(); ./
-VariableDeclaration: BindingIdentifier InitializerOpt;
+VariableDeclaration: BindingIdentifier TypeAnnotationOpt InitializerOpt;
/. case $rule_number: Q_FALLTHROUGH(); ./
-VariableDeclaration_In: BindingIdentifier InitializerOpt_In;
+VariableDeclaration_In: BindingIdentifier TypeAnnotationOpt InitializerOpt_In;
/.
case $rule_number: {
- auto *node = new (pool) AST::PatternElement(stringRef(1), sym(2).Expression);
+ auto *node = new (pool) AST::PatternElement(stringRef(1), sym(2).TypeAnnotation, sym(3).Expression);
node->identifierToken = loc(1);
sym(1).Node = node;
// if initializer is an anonymous function expression, we need to assign identifierref as it's name
- if (auto *f = asAnonymousFunctionDefinition(sym(2).Expression))
+ if (auto *f = asAnonymousFunctionDefinition(sym(3).Expression))
f->name = stringRef(1);
- if (auto *c = asAnonymousClassDefinition(sym(2).Expression))
+ if (auto *c = asAnonymousClassDefinition(sym(3).Expression))
c->name = stringRef(1);
} break;
./
@@ -3053,15 +3160,15 @@ BindingProperty: PropertyName T_COLON BindingPattern InitializerOpt_In;
} break;
./
-BindingElement: BindingIdentifier InitializerOpt_In;
+BindingElement: BindingIdentifier TypeAnnotationOpt InitializerOpt_In;
/.
case $rule_number: {
- AST::PatternElement *node = new (pool) AST::PatternElement(stringRef(1), sym(2).Expression);
+ AST::PatternElement *node = new (pool) AST::PatternElement(stringRef(1), sym(2).TypeAnnotation, sym(3).Expression);
node->identifierToken = loc(1);
// if initializer is an anonymous function expression, we need to assign identifierref as it's name
- if (auto *f = asAnonymousFunctionDefinition(sym(2).Expression))
+ if (auto *f = asAnonymousFunctionDefinition(sym(3).Expression))
f->name = stringRef(1);
- if (auto *c = asAnonymousClassDefinition(sym(2).Expression))
+ if (auto *c = asAnonymousClassDefinition(sym(3).Expression))
c->name = stringRef(1);
sym(1).Node = node;
} break;
@@ -3078,7 +3185,7 @@ BindingElement: BindingPattern InitializerOpt_In;
BindingRestElement: T_ELLIPSIS BindingIdentifier;
/.
case $rule_number: {
- AST::PatternElement *node = new (pool) AST::PatternElement(stringRef(2), nullptr, AST::PatternElement::RestElement);
+ AST::PatternElement *node = new (pool) AST::PatternElement(stringRef(2), /*type annotation*/nullptr, nullptr, AST::PatternElement::RestElement);
node->identifierToken = loc(2);
sym(1).Node = node;
} break;
@@ -3268,12 +3375,16 @@ IterationStatement: T_FOR T_LPAREN ForDeclaration InOrOf Expression_In T_RPAREN
} break;
./
-ForDeclaration: LetOrConst BindingIdentifier;
+ForDeclaration: LetOrConst BindingIdentifier TypeAnnotationOpt;
/. case $rule_number: Q_FALLTHROUGH(); ./
-ForDeclaration: Var BindingIdentifier;
+ForDeclaration: Var BindingIdentifier TypeAnnotationOpt;
/.
case $rule_number: {
- auto *node = new (pool) AST::PatternElement(stringRef(2), nullptr);
+ if (auto typeAnnotation = sym(3).TypeAnnotation) {
+ syntaxError(typeAnnotation->firstSourceLocation(), "Type annotations are not permitted in variable declarations");
+ return false;
+ }
+ auto *node = new (pool) AST::PatternElement(stringRef(2), sym(3).TypeAnnotation, nullptr);
node->identifierToken = loc(2);
node->scope = sym(1).scope;
node->isForDeclaration = true;
@@ -3560,59 +3671,85 @@ DebuggerStatement: T_DEBUGGER T_SEMICOLON;
-- otherwise conflict.
Function: T_FUNCTION %prec REDUCE_HERE;
-FunctionDeclaration: Function BindingIdentifier T_LPAREN FormalParameters T_RPAREN FunctionLBrace FunctionBody FunctionRBrace;
+FunctionDeclaration: Function BindingIdentifier T_LPAREN FormalParameters T_RPAREN TypeAnnotationOpt FunctionLBrace FunctionBody FunctionRBrace;
/.
case $rule_number: {
- AST::FunctionDeclaration *node = new (pool) AST::FunctionDeclaration(stringRef(2), sym(4).FormalParameterList, sym(7).StatementList);
+ if (!ensureNoFunctionTypeAnnotations(sym(6).TypeAnnotation, sym(4).FormalParameterList))
+ return false;
+ AST::FunctionDeclaration *node = new (pool) AST::FunctionDeclaration(stringRef(2), sym(4).FormalParameterList, sym(8).StatementList,
+ /*type annotation*/nullptr);
node->functionToken = loc(1);
node->identifierToken = loc(2);
node->lparenToken = loc(3);
node->rparenToken = loc(5);
- node->lbraceToken = loc(6);
- node->rbraceToken = loc(8);
+ node->lbraceToken = loc(7);
+ node->rbraceToken = loc(9);
sym(1).Node = node;
} break;
./
+FunctionDeclarationWithTypes: Function BindingIdentifier T_LPAREN FormalParameters T_RPAREN TypeAnnotationOpt FunctionLBrace FunctionBody FunctionRBrace;
+/.
+ case $rule_number: {
+ AST::FunctionDeclaration *node = new (pool) AST::FunctionDeclaration(stringRef(2), sym(4).FormalParameterList, sym(8).StatementList,
+ sym(6).TypeAnnotation);
+ node->functionToken = loc(1);
+ node->identifierToken = loc(2);
+ node->lparenToken = loc(3);
+ node->rparenToken = loc(5);
+ node->lbraceToken = loc(7);
+ node->rbraceToken = loc(9);
+ sym(1).Node = node;
+ } break;
+./
FunctionDeclaration_Default: FunctionDeclaration;
-FunctionDeclaration_Default: Function T_LPAREN FormalParameters T_RPAREN FunctionLBrace FunctionBody FunctionRBrace;
+FunctionDeclaration_Default: Function T_LPAREN FormalParameters T_RPAREN TypeAnnotationOpt FunctionLBrace FunctionBody FunctionRBrace;
/.
case $rule_number: {
- AST::FunctionDeclaration *node = new (pool) AST::FunctionDeclaration(QStringRef(), sym(3).FormalParameterList, sym(6).StatementList);
+ if (!ensureNoFunctionTypeAnnotations(sym(5).TypeAnnotation, sym(3).FormalParameterList))
+ return false;
+ AST::FunctionDeclaration *node = new (pool) AST::FunctionDeclaration(QStringRef(), sym(3).FormalParameterList, sym(7).StatementList,
+ /*type annotation*/nullptr);
node->functionToken = loc(1);
node->lparenToken = loc(2);
node->rparenToken = loc(4);
- node->lbraceToken = loc(5);
- node->rbraceToken = loc(7);
+ node->lbraceToken = loc(6);
+ node->rbraceToken = loc(8);
sym(1).Node = node;
} break;
./
-FunctionExpression: T_FUNCTION BindingIdentifier T_LPAREN FormalParameters T_RPAREN FunctionLBrace FunctionBody FunctionRBrace;
+FunctionExpression: T_FUNCTION BindingIdentifier T_LPAREN FormalParameters T_RPAREN TypeAnnotationOpt FunctionLBrace FunctionBody FunctionRBrace;
/.
case $rule_number: {
- AST::FunctionExpression *node = new (pool) AST::FunctionExpression(stringRef(2), sym(4).FormalParameterList, sym(7).StatementList);
+ if (!ensureNoFunctionTypeAnnotations(sym(6).TypeAnnotation, sym(4).FormalParameterList))
+ return false;
+ AST::FunctionExpression *node = new (pool) AST::FunctionExpression(stringRef(2), sym(4).FormalParameterList, sym(8).StatementList,
+ /*type annotation*/nullptr);
node->functionToken = loc(1);
if (! stringRef(2).isNull())
node->identifierToken = loc(2);
node->lparenToken = loc(3);
node->rparenToken = loc(5);
- node->lbraceToken = loc(6);
- node->rbraceToken = loc(8);
+ node->lbraceToken = loc(7);
+ node->rbraceToken = loc(9);
sym(1).Node = node;
} break;
./
-FunctionExpression: T_FUNCTION T_LPAREN FormalParameters T_RPAREN FunctionLBrace FunctionBody FunctionRBrace;
+FunctionExpression: T_FUNCTION T_LPAREN FormalParameters T_RPAREN TypeAnnotationOpt FunctionLBrace FunctionBody FunctionRBrace;
/.
case $rule_number: {
- AST::FunctionExpression *node = new (pool) AST::FunctionExpression(QStringRef(), sym(3).FormalParameterList, sym(6).StatementList);
+ if (!ensureNoFunctionTypeAnnotations(sym(5).TypeAnnotation, sym(3).FormalParameterList))
+ return false;
+ AST::FunctionExpression *node = new (pool) AST::FunctionExpression(QStringRef(), sym(3).FormalParameterList, sym(7).StatementList,
+ /*type annotation*/nullptr);
node->functionToken = loc(1);
node->lparenToken = loc(2);
node->rparenToken = loc(4);
- node->lbraceToken = loc(5);
- node->rbraceToken = loc(7);
+ node->lbraceToken = loc(6);
+ node->rbraceToken = loc(8);
sym(1).Node = node;
} break;
./
@@ -3722,7 +3859,7 @@ ArrowFunction_In: ArrowParameters T_ARROW ConciseBodyLookahead T_FORCE_BLOCK Fun
ArrowParameters: BindingIdentifier;
/.
case $rule_number: {
- AST::PatternElement *e = new (pool) AST::PatternElement(stringRef(1), nullptr, AST::PatternElement::Binding);
+ AST::PatternElement *e = new (pool) AST::PatternElement(stringRef(1), /*type annotation*/nullptr, nullptr, AST::PatternElement::Binding);
e->identifierToken = loc(1);
sym(1).FormalParameterList = (new (pool) AST::FormalParameterList(nullptr, e))->finish(pool);
} break;
@@ -3756,30 +3893,34 @@ ConciseBodyLookahead: ;
} break;
./
-MethodDefinition: PropertyName T_LPAREN StrictFormalParameters T_RPAREN FunctionLBrace FunctionBody FunctionRBrace;
+MethodDefinition: PropertyName T_LPAREN StrictFormalParameters T_RPAREN TypeAnnotationOpt FunctionLBrace FunctionBody FunctionRBrace;
/.
case $rule_number: {
- AST::FunctionExpression *f = new (pool) AST::FunctionExpression(stringRef(1), sym(3).FormalParameterList, sym(6).StatementList);
+ if (!ensureNoFunctionTypeAnnotations(sym(5).TypeAnnotation, sym(3).FormalParameterList))
+ return false;
+ AST::FunctionExpression *f = new (pool) AST::FunctionExpression(stringRef(1), sym(3).FormalParameterList, sym(7).StatementList);
f->functionToken = sym(1).PropertyName->firstSourceLocation();
f->lparenToken = loc(2);
f->rparenToken = loc(4);
- f->lbraceToken = loc(5);
- f->rbraceToken = loc(7);
+ f->lbraceToken = loc(6);
+ f->rbraceToken = loc(8);
AST::PatternProperty *node = new (pool) AST::PatternProperty(sym(1).PropertyName, f, AST::PatternProperty::Method);
node->colonToken = loc(2);
sym(1).Node = node;
} break;
./
-MethodDefinition: T_STAR PropertyName GeneratorLParen StrictFormalParameters T_RPAREN FunctionLBrace GeneratorBody GeneratorRBrace;
+MethodDefinition: T_STAR PropertyName GeneratorLParen StrictFormalParameters T_RPAREN TypeAnnotationOpt FunctionLBrace GeneratorBody GeneratorRBrace;
/.
case $rule_number: {
- AST::FunctionExpression *f = new (pool) AST::FunctionExpression(stringRef(2), sym(4).FormalParameterList, sym(7).StatementList);
+ if (!ensureNoFunctionTypeAnnotations(sym(6).TypeAnnotation, sym(4).FormalParameterList))
+ return false;
+ AST::FunctionExpression *f = new (pool) AST::FunctionExpression(stringRef(2), sym(4).FormalParameterList, sym(8).StatementList);
f->functionToken = sym(2).PropertyName->firstSourceLocation();
f->lparenToken = loc(3);
f->rparenToken = loc(5);
- f->lbraceToken = loc(6);
- f->rbraceToken = loc(8);
+ f->lbraceToken = loc(7);
+ f->rbraceToken = loc(9);
f->isGenerator = true;
AST::PatternProperty *node = new (pool) AST::PatternProperty(sym(2).PropertyName, f, AST::PatternProperty::Method);
node->colonToken = loc(2);
@@ -3788,30 +3929,34 @@ MethodDefinition: T_STAR PropertyName GeneratorLParen StrictFormalParameters T_R
./
-MethodDefinition: T_GET PropertyName T_LPAREN T_RPAREN FunctionLBrace FunctionBody FunctionRBrace;
+MethodDefinition: T_GET PropertyName T_LPAREN T_RPAREN TypeAnnotationOpt FunctionLBrace FunctionBody FunctionRBrace;
/.
case $rule_number: {
- AST::FunctionExpression *f = new (pool) AST::FunctionExpression(stringRef(2), nullptr, sym(6).StatementList);
+ if (!ensureNoFunctionTypeAnnotations(sym(5).TypeAnnotation, /*formals*/nullptr))
+ return false;
+ AST::FunctionExpression *f = new (pool) AST::FunctionExpression(stringRef(2), nullptr, sym(7).StatementList);
f->functionToken = sym(2).PropertyName->firstSourceLocation();
f->lparenToken = loc(3);
f->rparenToken = loc(4);
- f->lbraceToken = loc(5);
- f->rbraceToken = loc(7);
+ f->lbraceToken = loc(6);
+ f->rbraceToken = loc(8);
AST::PatternProperty *node = new (pool) AST::PatternProperty(sym(2).PropertyName, f, AST::PatternProperty::Getter);
node->colonToken = loc(2);
sym(1).Node = node;
} break;
./
-MethodDefinition: T_SET PropertyName T_LPAREN PropertySetParameterList T_RPAREN FunctionLBrace FunctionBody FunctionRBrace;
+MethodDefinition: T_SET PropertyName T_LPAREN PropertySetParameterList T_RPAREN TypeAnnotationOpt FunctionLBrace FunctionBody FunctionRBrace;
/.
case $rule_number: {
- AST::FunctionExpression *f = new (pool) AST::FunctionExpression(stringRef(2), sym(4).FormalParameterList, sym(7).StatementList);
+ if (!ensureNoFunctionTypeAnnotations(sym(6).TypeAnnotation, sym(4).FormalParameterList))
+ return false;
+ AST::FunctionExpression *f = new (pool) AST::FunctionExpression(stringRef(2), sym(4).FormalParameterList, sym(8).StatementList);
f->functionToken = sym(2).PropertyName->firstSourceLocation();
f->lparenToken = loc(3);
f->rparenToken = loc(5);
- f->lbraceToken = loc(6);
- f->rbraceToken = loc(8);
+ f->lbraceToken = loc(7);
+ f->rbraceToken = loc(9);
AST::PatternProperty *node = new (pool) AST::PatternProperty(sym(2).PropertyName, f, AST::PatternProperty::Setter);
node->colonToken = loc(2);
sym(1).Node = node;
diff --git a/src/qml/parser/qqmljsast.cpp b/src/qml/parser/qqmljsast.cpp
index 1bc0e6e364..700c191499 100644
--- a/src/qml/parser/qqmljsast.cpp
+++ b/src/qml/parser/qqmljsast.cpp
@@ -131,7 +131,7 @@ FormalParameterList *ExpressionNode::reparseAsFormalParameterList(MemoryPool *po
}
AST::PatternElement *binding = nullptr;
if (AST::IdentifierExpression *idExpr = AST::cast<AST::IdentifierExpression *>(expr)) {
- binding = new (pool) AST::PatternElement(idExpr->name, rhs);
+ binding = new (pool) AST::PatternElement(idExpr->name, /*type annotation*/nullptr, rhs);
binding->identifierToken = idExpr->identifierToken;
} else if (AST::Pattern *p = expr->patternCast()) {
SourceLocation loc;
@@ -961,6 +961,7 @@ void FunctionDeclaration::accept0(Visitor *visitor)
{
if (visitor->visit(this)) {
accept(formals, visitor);
+ accept(typeAnnotation, visitor);
accept(body, visitor);
}
@@ -971,6 +972,7 @@ void FunctionExpression::accept0(Visitor *visitor)
{
if (visitor->visit(this)) {
accept(formals, visitor);
+ accept(typeAnnotation, visitor);
accept(body, visitor);
}
@@ -982,9 +984,9 @@ FunctionExpression *FunctionExpression::asFunctionDefinition()
return this;
}
-QStringList FormalParameterList::formals() const
+BoundNames FormalParameterList::formals() const
{
- QStringList formals;
+ BoundNames formals;
int i = 0;
for (const FormalParameterList *it = this; it; it = it->next) {
if (it->element) {
@@ -992,18 +994,18 @@ QStringList FormalParameterList::formals() const
int duplicateIndex = formals.indexOf(name);
if (duplicateIndex >= 0) {
// change the name of the earlier argument to enforce the lookup semantics from the spec
- formals[duplicateIndex] += QLatin1String("#") + QString::number(i);
+ formals[duplicateIndex].id += QLatin1String("#") + QString::number(i);
}
- formals += name;
+ formals += {name, it->element->typeAnnotation};
}
++i;
}
return formals;
}
-QStringList FormalParameterList::boundNames() const
+BoundNames FormalParameterList::boundNames() const
{
- QStringList names;
+ BoundNames names;
for (const FormalParameterList *it = this; it; it = it->next) {
if (it->element)
it->element->boundNames(&names);
@@ -1271,6 +1273,35 @@ void UiQualifiedId::accept0(Visitor *visitor)
visitor->endVisit(this);
}
+void Type::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(typeId, visitor);
+ accept(typeArguments, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void TypeArgumentList::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ for (TypeArgumentList *it = this; it; it = it->next)
+ accept(it->typeId, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void TypeAnnotation::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(type, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
void UiImport::accept0(Visitor *visitor)
{
if (visitor->visit(this)) {
@@ -1339,13 +1370,14 @@ void PatternElement::accept0(Visitor *visitor)
{
if (visitor->visit(this)) {
accept(bindingTarget, visitor);
+ accept(typeAnnotation, visitor);
accept(initializer, visitor);
}
visitor->endVisit(this);
}
-void PatternElement::boundNames(QStringList *names)
+void PatternElement::boundNames(BoundNames *names)
{
if (bindingTarget) {
if (PatternElementList *e = elementList())
@@ -1353,7 +1385,7 @@ void PatternElement::boundNames(QStringList *names)
else if (PatternPropertyList *p = propertyList())
p->boundNames(names);
} else {
- names->append(bindingIdentifier.toString());
+ names->append({bindingIdentifier.toString(), typeAnnotation});
}
}
@@ -1369,7 +1401,7 @@ void PatternElementList::accept0(Visitor *visitor)
visitor->endVisit(this);
}
-void PatternElementList::boundNames(QStringList *names)
+void PatternElementList::boundNames(BoundNames *names)
{
for (PatternElementList *it = this; it; it = it->next) {
if (it->element)
@@ -1382,13 +1414,14 @@ void PatternProperty::accept0(Visitor *visitor)
if (visitor->visit(this)) {
accept(name, visitor);
accept(bindingTarget, visitor);
+ accept(typeAnnotation, visitor);
accept(initializer, visitor);
}
visitor->endVisit(this);
}
-void PatternProperty::boundNames(QStringList *names)
+void PatternProperty::boundNames(BoundNames *names)
{
PatternElement::boundNames(names);
}
@@ -1404,7 +1437,7 @@ void PatternPropertyList::accept0(Visitor *visitor)
visitor->endVisit(this);
}
-void PatternPropertyList::boundNames(QStringList *names)
+void PatternPropertyList::boundNames(BoundNames *names)
{
for (PatternPropertyList *it = this; it; it = it->next)
it->property->boundNames(names);
@@ -1478,6 +1511,31 @@ void UiVersionSpecifier::accept0(Visitor *visitor)
}
visitor->endVisit(this);
}
+
+QString Type::toString() const
+{
+ QString result;
+ toString(&result);
+ return result;
+}
+
+void Type::toString(QString *out) const
+{
+ for (QQmlJS::AST::UiQualifiedId *it = typeId; it; it = it->next) {
+ out->append(it->name);
+
+ if (it->next)
+ out->append(QLatin1Char('.'));
+ }
+
+ if (typeArguments) {
+ out->append(QLatin1Char('<'));
+ if (auto subType = static_cast<TypeArgumentList*>(typeArguments)->typeId)
+ subType->toString(out);
+ out->append(QLatin1Char('>'));
+ };
+}
+
} } // namespace QQmlJS::AST
QT_END_NAMESPACE
diff --git a/src/qml/parser/qqmljsast_p.h b/src/qml/parser/qqmljsast_p.h
index 606137b67d..1502298d14 100644
--- a/src/qml/parser/qqmljsast_p.h
+++ b/src/qml/parser/qqmljsast_p.h
@@ -53,7 +53,8 @@
#include "qqmljsastvisitor_p.h"
#include "qqmljsglobal_p.h"
-#include "qqmljsmemorypool_p.h"
+
+#include <private/qqmljsmemorypool_p.h>
#include <QtCore/qstring.h>
@@ -233,6 +234,9 @@ public:
Kind_PatternElementList,
Kind_PatternProperty,
Kind_PatternPropertyList,
+ Kind_Type,
+ Kind_TypeArgumentList,
+ Kind_TypeAnnotation,
Kind_UiArrayBinding,
Kind_UiImport,
@@ -303,6 +307,131 @@ public:
int kind = Kind_Undefined;
};
+
+class QML_PARSER_EXPORT UiQualifiedId: public Node
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(UiQualifiedId)
+
+ UiQualifiedId(const QStringRef &name)
+ : next(this), name(name)
+ { kind = K; }
+
+ UiQualifiedId(UiQualifiedId *previous, const QStringRef &name)
+ : name(name)
+ {
+ kind = K;
+ next = previous->next;
+ previous->next = this;
+ }
+
+ UiQualifiedId *finish()
+ {
+ UiQualifiedId *head = next;
+ next = nullptr;
+ return head;
+ }
+
+ void accept0(Visitor *visitor) override;
+
+ SourceLocation firstSourceLocation() const override
+ { return identifierToken; }
+
+ SourceLocation lastSourceLocation() const override
+ { return next ? next->lastSourceLocation() : identifierToken; }
+
+// attributes
+ UiQualifiedId *next;
+ QStringRef name;
+ SourceLocation identifierToken;
+};
+
+class QML_PARSER_EXPORT Type: public Node
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(Type)
+
+ Type(UiQualifiedId *typeId, Node *typeArguments = nullptr)
+ : typeId(typeId)
+ , typeArguments(typeArguments)
+ { kind = K; }
+
+ void accept0(Visitor *visitor) override;
+
+ SourceLocation firstSourceLocation() const override
+ { return typeId->firstSourceLocation(); }
+
+ SourceLocation lastSourceLocation() const override
+ { return typeArguments ? typeArguments->lastSourceLocation() : typeId->lastSourceLocation(); }
+
+ QString toString() const;
+ void toString(QString *out) const;
+
+// attributes
+ UiQualifiedId *typeId;
+ Node *typeArguments; // TypeArgumentList
+};
+
+
+class QML_PARSER_EXPORT TypeArgumentList: public Node
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(TypeArgumentList)
+
+ TypeArgumentList(Type *typeId)
+ : typeId(typeId)
+ , next(nullptr)
+ { kind = K; }
+
+ TypeArgumentList(TypeArgumentList *previous, Type *typeId)
+ : typeId(typeId)
+ {
+ kind = K;
+ next = previous->next;
+ previous->next = this;
+ }
+
+ void accept0(Visitor *visitor) override;
+
+ SourceLocation firstSourceLocation() const override
+ { return typeId->firstSourceLocation(); }
+
+ SourceLocation lastSourceLocation() const override
+ { return next ? next->lastSourceLocation() : typeId->lastSourceLocation(); }
+
+ inline TypeArgumentList *finish()
+ {
+ TypeArgumentList *front = next;
+ next = nullptr;
+ return front;
+ }
+
+// attributes
+ Type *typeId;
+ TypeArgumentList *next;
+};
+
+class QML_PARSER_EXPORT TypeAnnotation: public Node
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(TypeAnnotation)
+
+ TypeAnnotation(Type *type)
+ : type(type)
+ { kind = K; }
+
+ void accept0(Visitor *visitor) override;
+
+ SourceLocation firstSourceLocation() const override
+ { return colonToken; }
+
+ SourceLocation lastSourceLocation() const override
+ { return type->lastSourceLocation(); }
+
+// attributes
+ Type *type;
+ SourceLocation colonToken;
+};
class QML_PARSER_EXPORT ExpressionNode: public Node
{
public:
@@ -704,6 +833,34 @@ public:
SourceLocation propertyNameToken;
};
+struct QML_PARSER_EXPORT BoundName
+{
+ QString id;
+ TypeAnnotation *typeAnnotation = nullptr;
+ BoundName(const QString &id, TypeAnnotation *typeAnnotation)
+ : id(id), typeAnnotation(typeAnnotation)
+ {}
+ BoundName() = default;
+ QString typeName() const { return typeAnnotation ? typeAnnotation->type->toString() : QString(); }
+};
+
+struct BoundNames : public QVector<BoundName>
+{
+ int indexOf(const QString &name, int from = 0) const
+ {
+ auto found = std::find_if(constBegin() + from, constEnd(),
+ [name](const BoundName &it) { return it.id == name; });
+ if (found == constEnd())
+ return -1;
+ return found - constBegin();
+ }
+
+ bool contains(const QString &name) const
+ {
+ return indexOf(name) != -1;
+ }
+};
+
class QML_PARSER_EXPORT PatternElement : public Node
{
public:
@@ -728,8 +885,9 @@ public:
: initializer(i), type(t)
{ kind = K; }
- PatternElement(const QStringRef &n, ExpressionNode *i = nullptr, Type t = Binding)
+ PatternElement(const QStringRef &n, TypeAnnotation *typeAnnotation = nullptr, ExpressionNode *i = nullptr, Type t = Binding)
: bindingIdentifier(n), initializer(i), type(t)
+ , typeAnnotation(typeAnnotation)
{
Q_ASSERT(t >= RestElement);
kind = K;
@@ -749,7 +907,7 @@ public:
{ return identifierToken.isValid() ? identifierToken : (bindingTarget ? bindingTarget->firstSourceLocation() : initializer->firstSourceLocation()); }
SourceLocation lastSourceLocation() const override
- { return initializer ? initializer->lastSourceLocation() : (bindingTarget ? bindingTarget->lastSourceLocation() : identifierToken); }
+ { return initializer ? initializer->lastSourceLocation() : (bindingTarget ? bindingTarget->lastSourceLocation() : (typeAnnotation ? typeAnnotation->lastSourceLocation() : identifierToken)); }
ExpressionNode *destructuringTarget() const { return bindingTarget; }
Pattern *destructuringPattern() const { return bindingTarget ? bindingTarget->patternCast() : nullptr; }
@@ -759,7 +917,7 @@ public:
bool isVariableDeclaration() const { return scope != VariableScope::NoScope; }
bool isLexicallyScoped() const { return scope == VariableScope::Let || scope == VariableScope::Const; }
- virtual void boundNames(QStringList *names);
+ virtual void boundNames(BoundNames *names);
// attributes
SourceLocation identifierToken;
@@ -767,6 +925,7 @@ public:
ExpressionNode *bindingTarget = nullptr;
ExpressionNode *initializer = nullptr;
Type type = Literal;
+ TypeAnnotation *typeAnnotation = nullptr;
// when used in a VariableDeclarationList
VariableScope scope = VariableScope::NoScope;
bool isForDeclaration = false;
@@ -796,7 +955,7 @@ public:
void accept0(Visitor *visitor) override;
- void boundNames(QStringList *names);
+ void boundNames(BoundNames *names);
SourceLocation firstSourceLocation() const override
{ return elision ? elision->firstSourceLocation() : element->firstSourceLocation(); }
@@ -819,7 +978,7 @@ public:
{ kind = K; }
PatternProperty(PropertyName *name, const QStringRef &n, ExpressionNode *i = nullptr)
- : PatternElement(n, i), name(name)
+ : PatternElement(n, /*type annotation*/nullptr, i), name(name)
{ kind = K; }
PatternProperty(PropertyName *name, Pattern *pattern, ExpressionNode *i = nullptr)
@@ -836,7 +995,7 @@ public:
return loc.isValid() ? loc : name->lastSourceLocation();
}
- void boundNames(QStringList *names) override;
+ void boundNames(BoundNames *names) override;
bool convertLiteralToAssignmentPattern(MemoryPool *pool, SourceLocation *errorLocation, QString *errorMessage) override;
// attributes
@@ -864,7 +1023,7 @@ public:
void accept0(Visitor *visitor) override;
- void boundNames(QStringList *names);
+ void boundNames(BoundNames *names);
inline PatternPropertyList *finish ()
{
@@ -2154,8 +2313,9 @@ class QML_PARSER_EXPORT FunctionExpression: public ExpressionNode
public:
QQMLJS_DECLARE_AST_NODE(FunctionExpression)
- FunctionExpression(const QStringRef &n, FormalParameterList *f, StatementList *b):
- name (n), formals (f), body (b)
+ FunctionExpression(const QStringRef &n, FormalParameterList *f, StatementList *b, TypeAnnotation *typeAnnotation = nullptr):
+ name (n), formals (f), body (b),
+ typeAnnotation(typeAnnotation)
{ kind = K; }
void accept0(Visitor *visitor) override;
@@ -2174,6 +2334,7 @@ public:
bool isGenerator = false;
FormalParameterList *formals;
StatementList *body;
+ TypeAnnotation *typeAnnotation;
SourceLocation functionToken;
SourceLocation identifierToken;
SourceLocation lparenToken;
@@ -2187,8 +2348,8 @@ class QML_PARSER_EXPORT FunctionDeclaration: public FunctionExpression
public:
QQMLJS_DECLARE_AST_NODE(FunctionDeclaration)
- FunctionDeclaration(const QStringRef &n, FormalParameterList *f, StatementList *b):
- FunctionExpression(n, f, b)
+ FunctionDeclaration(const QStringRef &n, FormalParameterList *f, StatementList *b, TypeAnnotation *typeAnnotation = nullptr):
+ FunctionExpression(n, f, b, typeAnnotation)
{ kind = K; }
void accept0(Visitor *visitor) override;
@@ -2258,9 +2419,9 @@ public:
return false;
}
- QStringList formals() const;
+ BoundNames formals() const;
- QStringList boundNames() const;
+ BoundNames boundNames() const;
void accept0(Visitor *visitor) override;
@@ -2809,44 +2970,6 @@ public:
SourceLocation semicolonToken;
};
-class QML_PARSER_EXPORT UiQualifiedId: public Node
-{
-public:
- QQMLJS_DECLARE_AST_NODE(UiQualifiedId)
-
- UiQualifiedId(const QStringRef &name)
- : next(this), name(name)
- { kind = K; }
-
- UiQualifiedId(UiQualifiedId *previous, const QStringRef &name)
- : name(name)
- {
- kind = K;
- next = previous->next;
- previous->next = this;
- }
-
- UiQualifiedId *finish()
- {
- UiQualifiedId *head = next;
- next = nullptr;
- return head;
- }
-
- void accept0(Visitor *visitor) override;
-
- SourceLocation firstSourceLocation() const override
- { return identifierToken; }
-
- SourceLocation lastSourceLocation() const override
- { return next ? next->lastSourceLocation() : identifierToken; }
-
-// attributes
- UiQualifiedId *next;
- QStringRef name;
- SourceLocation identifierToken;
-};
-
class QML_PARSER_EXPORT UiImport: public Node
{
public:
@@ -3114,10 +3237,10 @@ public:
void accept0(Visitor *) override;
SourceLocation firstSourceLocation() const override
- { return propertyTypeToken; }
+ { return colonToken.isValid() ? identifierToken : propertyTypeToken; }
SourceLocation lastSourceLocation() const override
- { return next ? next->lastSourceLocation() : identifierToken; }
+ { return next ? next->lastSourceLocation() : (colonToken.isValid() ? propertyTypeToken : identifierToken); }
inline UiParameterList *finish ()
{
@@ -3133,6 +3256,7 @@ public:
SourceLocation commaToken;
SourceLocation propertyTypeToken;
SourceLocation identifierToken;
+ SourceLocation colonToken;
};
class QML_PARSER_EXPORT UiPublicMember: public UiObjectMember
diff --git a/src/qml/parser/qqmljsastfwd_p.h b/src/qml/parser/qqmljsastfwd_p.h
index 6fe108e425..05226fd043 100644
--- a/src/qml/parser/qqmljsastfwd_p.h
+++ b/src/qml/parser/qqmljsastfwd_p.h
@@ -158,6 +158,9 @@ class NestedExpression;
class ClassExpression;
class ClassDeclaration;
class ClassElementList;
+class TypeArgumentList;
+class Type;
+class TypeAnnotation;
// ui elements
class UiProgram;
diff --git a/src/qml/parser/qqmljsastvisitor_p.h b/src/qml/parser/qqmljsastvisitor_p.h
index f3732cbba8..7146cd00ac 100644
--- a/src/qml/parser/qqmljsastvisitor_p.h
+++ b/src/qml/parser/qqmljsastvisitor_p.h
@@ -403,6 +403,15 @@ public:
virtual bool visit(DebuggerStatement *) { return true; }
virtual void endVisit(DebuggerStatement *) {}
+ virtual bool visit(Type *) { return true; }
+ virtual void endVisit(Type *) {}
+
+ virtual bool visit(TypeArgumentList *) { return true; }
+ virtual void endVisit(TypeArgumentList *) {}
+
+ virtual bool visit(TypeAnnotation *) { return true; }
+ virtual void endVisit(TypeAnnotation *) {}
+
virtual void throwRecursionDepthError() = 0;
quint16 recursionDepth() const { return m_recursionDepth; }
diff --git a/src/qml/parser/qqmljsengine_p.h b/src/qml/parser/qqmljsengine_p.h
index 6a754fc236..8a3e2db6a1 100644
--- a/src/qml/parser/qqmljsengine_p.h
+++ b/src/qml/parser/qqmljsengine_p.h
@@ -52,9 +52,10 @@
//
#include "qqmljsglobal_p.h"
-#include "qqmljsmemorypool_p.h"
#include "qqmljssourcelocation_p.h"
+#include <private/qqmljsmemorypool_p.h>
+
#include <QtCore/qstring.h>
#include <QtCore/qset.h>
diff --git a/src/qml/parser/qqmljslexer.cpp b/src/qml/parser/qqmljslexer.cpp
index 165925d2a2..1e0ac72bd1 100644
--- a/src/qml/parser/qqmljslexer.cpp
+++ b/src/qml/parser/qqmljslexer.cpp
@@ -39,10 +39,10 @@
#include "qqmljslexer_p.h"
#include "qqmljsengine_p.h"
-#include "qqmljsmemorypool_p.h"
#include "qqmljskeywords_p.h"
#include <private/qqmljsdiagnosticmessage_p.h>
+#include <private/qqmljsmemorypool_p.h>
#include <QtCore/qcoreapplication.h>
#include <QtCore/qvarlengtharray.h>
diff --git a/src/qml/qml.pro b/src/qml/qml.pro
index 99ad6ace60..3c889244f4 100644
--- a/src/qml/qml.pro
+++ b/src/qml/qml.pro
@@ -19,31 +19,6 @@ gcc:isEqual(QT_ARCH, "mips"): QMAKE_CXXFLAGS += -fno-reorder-blocks
DEFINES += QT_NO_FOREACH
-!build_pass {
- # Create a header containing a hash that describes this library. For a
- # released version of Qt, we'll use the .tag file that is updated by git
- # archive with the commit hash. For unreleased versions, we'll ask git
- # describe. Note that it won't update unless qmake is run again, even if
- # the commit change also changed something in this library.
- tagFile = $$PWD/../../.tag
- tag =
- exists($$tagFile) {
- tag = $$cat($$tagFile, singleline)
- QMAKE_INTERNAL_INCLUDED_FILES += $$tagFile
- }
- !equals(tag, "$${LITERAL_DOLLAR}Format:%H$${LITERAL_DOLLAR}") {
- QML_COMPILE_HASH = $$tag
- } else:exists($$PWD/../../.git) {
- commit = $$system(git rev-parse HEAD)
- QML_COMPILE_HASH = $$commit
- }
- compile_hash_contents = \
- "// Generated file, DO NOT EDIT" \
- "$${LITERAL_HASH}define QML_COMPILE_HASH \"$$QML_COMPILE_HASH\"" \
- "$${LITERAL_HASH}define QML_COMPILE_HASH_LENGTH $$str_size($$QML_COMPILE_HASH)"
- write_file("$$OUT_PWD/qml_compile_hash_p.h", compile_hash_contents)|error()
-}
-
exists("qqml_enable_gcov") {
QMAKE_CXXFLAGS = -fprofile-arcs -ftest-coverage -fno-elide-constructors
LIBS_PRIVATE += -lgcov
@@ -64,7 +39,9 @@ greaterThan(QT_CLANG_MAJOR_VERSION, 3)|greaterThan(QT_CLANG_MINOR_VERSION, 3)| \
WERROR += -Wno-error=unused-const-variable
HEADERS += qtqmlglobal.h \
- qtqmlglobal_p.h
+ qtqmlglobal_p.h \
+ qtqmlcompilerglobal.h \
+ qtqmlcompilerglobal_p.h
#modules
include(common/common.pri)
diff --git a/src/qml/qml/qml.pri b/src/qml/qml/qml.pri
index 15ea12cbe7..08591b5237 100644
--- a/src/qml/qml/qml.pri
+++ b/src/qml/qml/qml.pri
@@ -1,7 +1,14 @@
SOURCES += \
$$PWD/qqml.cpp \
+ $$PWD/qqmldatablob.cpp \
+ $$PWD/qqmldirdata.cpp \
$$PWD/qqmlerror.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 \
@@ -61,10 +68,18 @@ SOURCES += \
$$PWD/qqmlpropertyvalidator.cpp
HEADERS += \
+ $$PWD/qqmldatablob_p.h \
+ $$PWD/qqmldirdata_p.h \
$$PWD/qqmlglobal_p.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 \
@@ -163,5 +178,13 @@ qtConfig(qml-locale) {
$$PWD/qqmllocale.cpp
}
+qtConfig(qml-network) {
+ HEADERS += \
+ $$PWD/qqmltypeloadernetworkreplyproxy_p.h
+
+ SOURCES += \
+ $$PWD/qqmltypeloadernetworkreplyproxy.cpp
+}
+
include(ftw/ftw.pri)
include(v8/v8.pri)
diff --git a/src/qml/qml/qqmlapplicationengine.cpp b/src/qml/qml/qqmlapplicationengine.cpp
index 7149f8c134..e93cfcadb9 100644
--- a/src/qml/qml/qqmlapplicationengine.cpp
+++ b/src/qml/qml/qqmlapplicationengine.cpp
@@ -37,6 +37,7 @@
**
****************************************************************************/
+#include <QtQml/qqmlfile.h>
#include <QtCore/QCoreApplication>
#include <QtCore/QTranslator>
#include <QQmlComponent>
diff --git a/src/qml/qml/qqmlbinding.cpp b/src/qml/qml/qqmlbinding.cpp
index 7fb15af570..3a437eab8d 100644
--- a/src/qml/qml/qqmlbinding.cpp
+++ b/src/qml/qml/qqmlbinding.cpp
@@ -49,6 +49,7 @@
#include <private/qqmlbuiltinfunctions_p.h>
#include <private/qqmlvmemetaobject_p.h>
#include <private/qqmlvaluetypewrapper_p.h>
+#include <private/qv4qmlcontext_p.h>
#include <private/qv4qobjectwrapper_p.h>
#include <private/qv4variantobject_p.h>
#include <private/qv4jscall_p.h>
diff --git a/src/qml/qml/qqmlbinding_p.h b/src/qml/qml/qqmlbinding_p.h
index 85b02dcde4..7f96b4df9f 100644
--- a/src/qml/qml/qqmlbinding_p.h
+++ b/src/qml/qml/qqmlbinding_p.h
@@ -63,6 +63,7 @@
#include <private/qqmlabstractbinding_p.h>
#include <private/qqmljavascriptexpression_p.h>
+#include <private/qv4functionobject_p.h>
QT_BEGIN_NAMESPACE
diff --git a/src/qml/qml/qqmlboundsignal.cpp b/src/qml/qml/qqmlboundsignal.cpp
index dc973630a7..ff01e737ca 100644
--- a/src/qml/qml/qqmlboundsignal.cpp
+++ b/src/qml/qml/qqmlboundsignal.cpp
@@ -56,6 +56,7 @@
#include <private/qv4value_p.h>
#include <private/qv4jscall_p.h>
#include <private/qv4qobjectwrapper_p.h>
+#include <private/qv4qmlcontext_p.h>
#include <QtCore/qdebug.h>
diff --git a/src/qml/qml/qqmlcomponent.cpp b/src/qml/qml/qqmlcomponent.cpp
index 59b5cc2691..fefe2bc685 100644
--- a/src/qml/qml/qqmlcomponent.cpp
+++ b/src/qml/qml/qqmlcomponent.cpp
@@ -569,6 +569,12 @@ void QQmlComponent::setData(const QByteArray &data, const QUrl &url)
{
Q_D(QQmlComponent);
+ if (!d->engine) {
+ // ###Qt6: In Qt 6, it should be impossible for users to create a QQmlComponent without an engine, and we can remove this check
+ qWarning("QQmlComponent: Must provide an engine before calling setData");
+ return;
+ }
+
d->clear();
d->url = url;
@@ -774,6 +780,12 @@ QObject *QQmlComponent::create(QQmlContext *context)
{
Q_D(QQmlComponent);
+ if (!d->engine) {
+ // ###Qt6: In Qt 6, it should be impossible for users to create a QQmlComponent without an engine, and we can remove this check
+ qWarning("QQmlComponent: Must provide an engine before calling create");
+ return nullptr;
+ }
+
if (!context)
context = d->engine->rootContext();
diff --git a/src/qml/qml/qqmlcomponent_p.h b/src/qml/qml/qqmlcomponent_p.h
index 71275a2cd3..9a967501c9 100644
--- a/src/qml/qml/qqmlcomponent_p.h
+++ b/src/qml/qml/qqmlcomponent_p.h
@@ -60,6 +60,7 @@
#include "qqmlerror.h"
#include "qqml.h"
#include <private/qqmlobjectcreator_p.h>
+#include <private/qqmltypedata_p.h>
#include <QtCore/QString>
#include <QtCore/QStringList>
diff --git a/src/qml/qml/qqmlcustomparser.cpp b/src/qml/qml/qqmlcustomparser.cpp
index c477415ef7..a5f34dafdf 100644
--- a/src/qml/qml/qqmlcustomparser.cpp
+++ b/src/qml/qml/qqmlcustomparser.cpp
@@ -39,7 +39,7 @@
#include "qqmlcustomparser_p.h"
-#include <private/qqmltypecompiler_p.h>
+#include <private/qv4compileddata_p.h>
#include <QtCore/qdebug.h>
diff --git a/src/qml/qml/qqmlcustomparser_p.h b/src/qml/qml/qqmlcustomparser_p.h
index 94671a4f35..df8cbc9072 100644
--- a/src/qml/qml/qqmlcustomparser_p.h
+++ b/src/qml/qml/qqmlcustomparser_p.h
@@ -53,7 +53,7 @@
#include "qqmlerror.h"
#include "qqmlbinding_p.h"
-#include <private/qqmltypecompiler_p.h>
+#include <private/qv4compileddata_p.h>
#include <QtCore/qbytearray.h>
#include <QtCore/qxmlstream.h>
diff --git a/src/qml/qml/qqmldatablob.cpp b/src/qml/qml/qqmldatablob.cpp
new file mode 100644
index 0000000000..2183721d32
--- /dev/null
+++ b/src/qml/qml/qqmldatablob.cpp
@@ -0,0 +1,639 @@
+/****************************************************************************
+**
+** 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 <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 <QtQml/qqmlengine.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
+#define ASSERT_CALLBACK()
+#endif
+
+DEFINE_BOOL_CONFIG_OPTION(dumpErrors, QML_DUMP_ERRORS);
+
+QT_BEGIN_NAMESPACE
+
+/*!
+\class QQmlDataBlob
+\brief The QQmlDataBlob encapsulates a data request that can be issued to a QQmlTypeLoader.
+\internal
+
+QQmlDataBlob's are loaded by a QQmlTypeLoader. The user creates the QQmlDataBlob
+and then calls QQmlTypeLoader::load() or QQmlTypeLoader::loadWithStaticData() to load it.
+The QQmlTypeLoader invokes callbacks on the QQmlDataBlob as data becomes available.
+*/
+
+/*!
+\enum QQmlDataBlob::Status
+
+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
+*/
+
+/*!
+\enum QQmlDataBlob::Type
+
+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
+*/
+
+/*!
+Create a new QQmlDataBlob for \a url and of the provided \a type.
+*/
+QQmlDataBlob::QQmlDataBlob(const QUrl &url, Type type, QQmlTypeLoader *manager)
+: m_typeLoader(manager), m_type(type), m_url(url), m_finalUrl(url), m_redirectCount(0),
+ 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);
+}
+
+/*! \internal */
+QQmlDataBlob::~QQmlDataBlob()
+{
+ Q_ASSERT(m_waitingOnMe.isEmpty());
+
+ cancelAllWaitingFor();
+}
+
+/*!
+ Must be called before loading can occur.
+*/
+void QQmlDataBlob::startLoading()
+{
+ Q_ASSERT(status() == QQmlDataBlob::Null);
+ m_data.setStatus(QQmlDataBlob::Loading);
+}
+
+/*!
+Returns the type provided to the constructor.
+*/
+QQmlDataBlob::Type QQmlDataBlob::type() const
+{
+ return m_type;
+}
+
+/*!
+Returns the blob's status.
+*/
+QQmlDataBlob::Status QQmlDataBlob::status() const
+{
+ return m_data.status();
+}
+
+/*!
+Returns true if the status is Null.
+*/
+bool QQmlDataBlob::isNull() const
+{
+ return status() == Null;
+}
+
+/*!
+Returns true if the status is Loading.
+*/
+bool QQmlDataBlob::isLoading() const
+{
+ return status() == Loading;
+}
+
+/*!
+Returns true if the status is WaitingForDependencies.
+*/
+bool QQmlDataBlob::isWaiting() const
+{
+ return status() == WaitingForDependencies ||
+ status() == ResolvingDependencies;
+}
+
+/*!
+Returns true if the status is Complete.
+*/
+bool QQmlDataBlob::isComplete() const
+{
+ return status() == Complete;
+}
+
+/*!
+Returns true if the status is Error.
+*/
+bool QQmlDataBlob::isError() const
+{
+ return status() == Error;
+}
+
+/*!
+Returns true if the status is Complete or Error.
+*/
+bool QQmlDataBlob::isCompleteOrError() const
+{
+ Status s = status();
+ return s == Error || s == Complete;
+}
+
+/*!
+Returns the data download progress from 0 to 1.
+*/
+qreal QQmlDataBlob::progress() const
+{
+ quint8 p = m_data.progress();
+ if (p == 0xFF) return 1.;
+ else return qreal(p) / qreal(0xFF);
+}
+
+/*!
+Returns the physical url of the data. Initially this is the same as
+finalUrl(), but if a URL interceptor is set, it will work on this URL
+and leave finalUrl() alone.
+
+\sa finalUrl()
+*/
+QUrl QQmlDataBlob::url() const
+{
+ return m_url;
+}
+
+QString QQmlDataBlob::urlString() const
+{
+ if (m_urlString.isEmpty())
+ m_urlString = m_url.toString();
+
+ return m_urlString;
+}
+
+/*!
+Returns the logical URL to be used for resolving further URLs referred to in
+the code.
+
+This is the blob url passed to the constructor. If a URL interceptor rewrites
+the URL, this one stays the same. If a network redirect happens while fetching
+the data, this url is updated to reflect the new location. Therefore, if both
+an interception and a redirection happen, the final url will indirectly
+incorporate the result of the interception, potentially breaking further
+lookups.
+
+\sa url()
+*/
+QUrl QQmlDataBlob::finalUrl() const
+{
+ return m_finalUrl;
+}
+
+/*!
+Returns the finalUrl() as a string.
+*/
+QString QQmlDataBlob::finalUrlString() const
+{
+ if (m_finalUrlString.isEmpty())
+ m_finalUrlString = m_finalUrl.toString();
+
+ return m_finalUrlString;
+}
+
+/*!
+Return the errors on this blob.
+
+May only be called from the load thread, or after the blob isCompleteOrError().
+*/
+QList<QQmlError> QQmlDataBlob::errors() const
+{
+ Q_ASSERT(isCompleteOrError() || (m_typeLoader && m_typeLoader->m_thread->isThisThread()));
+ return m_errors;
+}
+
+/*!
+Mark this blob as having \a errors.
+
+All outstanding dependencies will be cancelled. Requests to add new dependencies
+will be ignored. Entry into the Error state is irreversable.
+
+The setError() method may only be called from within a QQmlDataBlob callback.
+*/
+void QQmlDataBlob::setError(const QQmlError &errors)
+{
+ ASSERT_CALLBACK();
+
+ QList<QQmlError> l;
+ l << errors;
+ setError(l);
+}
+
+/*!
+\overload
+*/
+void QQmlDataBlob::setError(const QList<QQmlError> &errors)
+{
+ ASSERT_CALLBACK();
+
+ Q_ASSERT(status() != Error);
+ Q_ASSERT(m_errors.isEmpty());
+
+ m_errors = errors; // Must be set before the m_data fence
+ m_data.setStatus(Error);
+
+ if (dumpErrors()) {
+ qWarning().nospace() << "Errors for " << urlString();
+ for (int ii = 0; ii < errors.count(); ++ii)
+ qWarning().nospace() << " " << qPrintable(errors.at(ii).toString());
+ }
+ cancelAllWaitingFor();
+
+ if (!m_inCallback)
+ tryDone();
+}
+
+void QQmlDataBlob::setError(const QQmlJS::DiagnosticMessage &error)
+{
+ QQmlError e;
+ e.setColumn(error.column);
+ e.setLine(error.line);
+ 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;
+ e.setDescription(description);
+ e.setUrl(url());
+ setError(e);
+}
+
+/*!
+Wait for \a blob to become complete or to error. If \a blob is already
+complete or in error, or this blob is already complete, this has no effect.
+
+The setError() method may only be called from within a QQmlDataBlob callback.
+*/
+void QQmlDataBlob::addDependency(QQmlDataBlob *blob)
+{
+ ASSERT_CALLBACK();
+
+ Q_ASSERT(status() != Null);
+
+ if (!blob ||
+ blob->status() == Error || blob->status() == Complete ||
+ status() == Error || status() == Complete || m_isDone)
+ return;
+
+ for (auto existingDep: qAsConst(m_waitingFor))
+ if (existingDep.data() == blob)
+ return;
+
+ m_data.setStatus(WaitingForDependencies);
+
+ m_waitingFor.append(blob);
+ blob->m_waitingOnMe.append(this);
+}
+
+/*!
+\fn void QQmlDataBlob::dataReceived(const Data &data)
+
+Invoked when data for the blob is received. Implementors should use this callback
+to determine a blob's dependencies. Within this callback you may call setError()
+or addDependency().
+*/
+
+/*!
+Invoked once data has either been received or a network error occurred, and all
+dependencies are complete.
+
+You can set an error in this method, but you cannot add new dependencies. Implementors
+should use this callback to finalize processing of data.
+
+The default implementation does nothing.
+
+XXX Rename processData() or some such to avoid confusion between done() (processing thread)
+and completed() (main thread)
+*/
+void QQmlDataBlob::done()
+{
+}
+
+#if QT_CONFIG(qml_network)
+/*!
+Invoked if there is a network error while fetching this blob.
+
+The default implementation sets an appropriate QQmlError.
+*/
+void QQmlDataBlob::networkError(QNetworkReply::NetworkError networkError)
+{
+ Q_UNUSED(networkError);
+
+ QQmlError error;
+ error.setUrl(m_url);
+
+ const char *errorString = nullptr;
+ switch (networkError) {
+ default:
+ errorString = "Network error";
+ break;
+ case QNetworkReply::ConnectionRefusedError:
+ errorString = "Connection refused";
+ break;
+ case QNetworkReply::RemoteHostClosedError:
+ errorString = "Remote host closed the connection";
+ break;
+ case QNetworkReply::HostNotFoundError:
+ errorString = "Host not found";
+ break;
+ case QNetworkReply::TimeoutError:
+ errorString = "Timeout";
+ break;
+ case QNetworkReply::ProxyConnectionRefusedError:
+ case QNetworkReply::ProxyConnectionClosedError:
+ case QNetworkReply::ProxyNotFoundError:
+ case QNetworkReply::ProxyTimeoutError:
+ case QNetworkReply::ProxyAuthenticationRequiredError:
+ case QNetworkReply::UnknownProxyError:
+ errorString = "Proxy error";
+ break;
+ case QNetworkReply::ContentAccessDenied:
+ errorString = "Access denied";
+ break;
+ case QNetworkReply::ContentNotFoundError:
+ errorString = "File not found";
+ break;
+ case QNetworkReply::AuthenticationRequiredError:
+ errorString = "Authentication required";
+ break;
+ };
+
+ error.setDescription(QLatin1String(errorString));
+
+ setError(error);
+}
+#endif // qml_network
+
+/*!
+Called if \a blob, which was previously waited for, has an error.
+
+The default implementation does nothing.
+*/
+void QQmlDataBlob::dependencyError(QQmlDataBlob *blob)
+{
+ Q_UNUSED(blob);
+}
+
+/*!
+Called if \a blob, which was previously waited for, has completed.
+
+The default implementation does nothing.
+*/
+void QQmlDataBlob::dependencyComplete(QQmlDataBlob *blob)
+{
+ Q_UNUSED(blob);
+}
+
+/*!
+Called when all blobs waited for have completed. This occurs regardless of
+whether they are in error, or complete state.
+
+The default implementation does nothing.
+*/
+void QQmlDataBlob::allDependenciesDone()
+{
+ m_data.setStatus(QQmlDataBlob::ResolvingDependencies);
+}
+
+/*!
+Called when the download progress of this blob changes. \a progress goes
+from 0 to 1.
+
+This callback is only invoked if an asynchronous load for this blob is
+made. An asynchronous load is one in which the Asynchronous mode is
+specified explicitly, or one that is implicitly delayed due to a network
+operation.
+
+The default implementation does nothing.
+*/
+void QQmlDataBlob::downloadProgressChanged(qreal progress)
+{
+ Q_UNUSED(progress);
+}
+
+/*!
+Invoked on the main thread sometime after done() was called on the load thread.
+
+You cannot modify the blobs state at all in this callback and cannot depend on the
+order or timeliness of these callbacks. Implementors should use this callback to notify
+dependencies on the main thread that the blob is done and not a lot else.
+
+This callback is only invoked if an asynchronous load for this blob is
+made. An asynchronous load is one in which the Asynchronous mode is
+specified explicitly, or one that is implicitly delayed due to a network
+operation.
+
+The default implementation does nothing.
+*/
+void QQmlDataBlob::completed()
+{
+}
+
+
+void QQmlDataBlob::tryDone()
+{
+ if (status() != Loading && m_waitingFor.isEmpty() && !m_isDone) {
+ m_isDone = true;
+ addref();
+
+#ifdef DATABLOB_DEBUG
+ qWarning("QQmlDataBlob::done() %s", qPrintable(urlString()));
+#endif
+ done();
+
+ if (status() != Error)
+ m_data.setStatus(Complete);
+
+ notifyAllWaitingOnMe();
+
+ // Locking is not required here, as anyone expecting callbacks must
+ // already be protected against the blob being completed (as set above);
+#ifdef DATABLOB_DEBUG
+ qWarning("QQmlDataBlob: Dispatching completed");
+#endif
+ m_typeLoader->m_thread->callCompleted(this);
+
+ release();
+ }
+}
+
+void QQmlDataBlob::cancelAllWaitingFor()
+{
+ while (m_waitingFor.count()) {
+ QQmlRefPointer<QQmlDataBlob> blob = m_waitingFor.takeLast();
+
+ Q_ASSERT(blob->m_waitingOnMe.contains(this));
+
+ blob->m_waitingOnMe.removeOne(this);
+ }
+}
+
+void QQmlDataBlob::notifyAllWaitingOnMe()
+{
+ while (m_waitingOnMe.count()) {
+ QQmlDataBlob *blob = m_waitingOnMe.takeLast();
+
+ Q_ASSERT(std::any_of(blob->m_waitingFor.constBegin(), blob->m_waitingFor.constEnd(),
+ [this](const QQmlRefPointer<QQmlDataBlob> &waiting) { return waiting.data() == this; }));
+
+ blob->notifyComplete(this);
+ }
+}
+
+void QQmlDataBlob::notifyComplete(QQmlDataBlob *blob)
+{
+ Q_ASSERT(blob->status() == Error || blob->status() == Complete);
+ QQmlCompilingProfiler prof(typeLoader()->profiler(), blob);
+
+ m_inCallback = true;
+
+ QQmlRefPointer<QQmlDataBlob> blobRef;
+ for (int i = 0; i < m_waitingFor.count(); ++i) {
+ if (m_waitingFor.at(i).data() == blob) {
+ blobRef = m_waitingFor.takeAt(i);
+ break;
+ }
+ }
+ Q_ASSERT(blobRef);
+
+ if (blob->status() == Error) {
+ dependencyError(blob);
+ } else if (blob->status() == Complete) {
+ dependencyComplete(blob);
+ }
+
+ if (!isError() && m_waitingFor.isEmpty())
+ allDependenciesDone();
+
+ m_inCallback = false;
+
+ tryDone();
+}
+
+QString QQmlDataBlob::SourceCodeData::readAll(QString *error) const
+{
+ error->clear();
+ if (hasInlineSourceCode)
+ return inlineSourceCode;
+
+ QFile f(fileInfo.absoluteFilePath());
+ if (!f.open(QIODevice::ReadOnly)) {
+ *error = f.errorString();
+ return QString();
+ }
+
+ const qint64 fileSize = fileInfo.size();
+
+ if (uchar *mappedData = f.map(0, fileSize)) {
+ QString source = QString::fromUtf8(reinterpret_cast<const char *>(mappedData), fileSize);
+ f.unmap(mappedData);
+ return source;
+ }
+
+ QByteArray data(fileSize, Qt::Uninitialized);
+ if (f.read(data.data(), data.length()) != data.length()) {
+ *error = f.errorString();
+ return QString();
+ }
+ return QString::fromUtf8(data);
+}
+
+QDateTime QQmlDataBlob::SourceCodeData::sourceTimeStamp() const
+{
+ if (hasInlineSourceCode)
+ return QDateTime();
+
+ return fileInfo.lastModified();
+}
+
+bool QQmlDataBlob::SourceCodeData::exists() const
+{
+ if (hasInlineSourceCode)
+ return true;
+ return fileInfo.exists();
+}
+
+bool QQmlDataBlob::SourceCodeData::isEmpty() const
+{
+ if (hasInlineSourceCode)
+ return inlineSourceCode.isEmpty();
+ return fileInfo.size() == 0;
+}
+
+QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmldatablob_p.h b/src/qml/qml/qqmldatablob_p.h
new file mode 100644
index 0000000000..da3bbe2c1f
--- /dev/null
+++ b/src/qml/qml/qqmldatablob_p.h
@@ -0,0 +1,257 @@
+/****************************************************************************
+**
+** 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 QQMLDATABLOB_P_H
+#define QQMLDATABLOB_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/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/qqmlerror.h>
+#include <QtQml/qqmlabstracturlinterceptor.h>
+
+#include <QtCore/qdatetime.h>
+#include <QtCore/qfileinfo.h>
+#include <QtCore/qurl.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQmlTypeLoader;
+class Q_QML_PRIVATE_EXPORT QQmlDataBlob : public QQmlRefCount
+{
+public:
+ enum Status {
+ Null, // Prior to QQmlTypeLoader::load()
+ Loading, // Prior to data being received and dataReceived() being called
+ WaitingForDependencies, // While there are outstanding addDependency()s
+ ResolvingDependencies, // While resolving outstanding dependencies, to detect cycles
+ Complete, // Finished
+ Error // Error
+ };
+
+ enum Type { //Matched in QQmlAbstractUrlInterceptor
+ QmlFile = QQmlAbstractUrlInterceptor::QmlFile,
+ JavaScriptFile = QQmlAbstractUrlInterceptor::JavaScriptFile,
+ QmldirFile = QQmlAbstractUrlInterceptor::QmldirFile
+ };
+
+ QQmlDataBlob(const QUrl &, Type, QQmlTypeLoader* manager);
+ ~QQmlDataBlob() override;
+
+ void startLoading();
+
+ QQmlTypeLoader *typeLoader() const { return m_typeLoader; }
+
+ Type type() const;
+
+ Status status() const;
+ bool isNull() const;
+ bool isLoading() const;
+ bool isWaiting() const;
+ bool isComplete() const;
+ bool isError() const;
+ bool isCompleteOrError() const;
+
+ qreal progress() const;
+
+ QUrl url() const;
+ QString urlString() const;
+ QUrl finalUrl() const;
+ QString finalUrlString() const;
+
+ QList<QQmlError> errors() const;
+
+ class SourceCodeData {
+ public:
+ QString readAll(QString *error) const;
+ QDateTime sourceTimeStamp() const;
+ bool exists() const;
+ bool isEmpty() const;
+ private:
+ friend class QQmlDataBlob;
+ friend class QQmlTypeLoader;
+ QString inlineSourceCode;
+ QFileInfo fileInfo;
+ bool hasInlineSourceCode = false;
+ };
+
+protected:
+ // Can be called from within callbacks
+ 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 done();
+#if QT_CONFIG(qml_network)
+ virtual void networkError(QNetworkReply::NetworkError);
+#endif
+ virtual void dependencyError(QQmlDataBlob *);
+ virtual void dependencyComplete(QQmlDataBlob *);
+ virtual void allDependenciesDone();
+
+ // Callbacks made in main thread
+ virtual void downloadProgressChanged(qreal);
+ virtual void completed();
+
+protected:
+ // Manager that is currently fetching data for me
+ QQmlTypeLoader *m_typeLoader;
+
+private:
+ friend class QQmlTypeLoader;
+ friend class QQmlTypeLoaderThread;
+
+ void tryDone();
+ void cancelAllWaitingFor();
+ void notifyAllWaitingOnMe();
+ void notifyComplete(QQmlDataBlob *);
+
+ struct ThreadData {
+ private:
+ enum {
+ StatusMask = 0x0000FFFF,
+ StatusShift = 0,
+ ProgressMask = 0x00FF0000,
+ ProgressShift = 16,
+ AsyncMask = 0x80000000,
+ NoMask = 0
+ };
+
+ public:
+ inline ThreadData()
+ : _p(0)
+ {
+ }
+
+ inline QQmlDataBlob::Status status() const
+ {
+ return QQmlDataBlob::Status((_p.loadRelaxed() & StatusMask) >> StatusShift);
+ }
+
+ inline void setStatus(QQmlDataBlob::Status status)
+ {
+ while (true) {
+ int d = _p.loadRelaxed();
+ int nd = (d & ~StatusMask) | ((status << StatusShift) & StatusMask);
+ if (d == nd || _p.testAndSetOrdered(d, nd)) return;
+ }
+ }
+
+ inline bool isAsync() const
+ {
+ return _p.loadRelaxed() & AsyncMask;
+ }
+
+ inline void setIsAsync(bool v)
+ {
+ while (true) {
+ int d = _p.loadRelaxed();
+ int nd = (d & ~AsyncMask) | (v ? AsyncMask : NoMask);
+ if (d == nd || _p.testAndSetOrdered(d, nd)) return;
+ }
+ }
+
+ inline quint8 progress() const
+ {
+ return quint8((_p.loadRelaxed() & ProgressMask) >> ProgressShift);
+ }
+
+ inline void setProgress(quint8 v)
+ {
+ while (true) {
+ int d = _p.loadRelaxed();
+ int nd = (d & ~ProgressMask) | ((v << ProgressShift) & ProgressMask);
+ if (d == nd || _p.testAndSetOrdered(d, nd)) return;
+ }
+ }
+
+ private:
+ QAtomicInt _p;
+ };
+ ThreadData m_data;
+
+ // m_errors should *always* be written before the status is set to Error.
+ // We use the status change as a memory fence around m_errors so that locking
+ // isn't required. Once the status is set to Error (or Complete), m_errors
+ // cannot be changed.
+ QList<QQmlError> m_errors;
+
+ Type m_type;
+
+ QUrl m_url;
+ QUrl m_finalUrl;
+ mutable QString m_urlString;
+ mutable QString m_finalUrlString;
+
+ // List of QQmlDataBlob's that are waiting for me to complete.
+ QList<QQmlDataBlob *> m_waitingOnMe;
+
+ // List of QQmlDataBlob's that I am waiting for to complete.
+ QVector<QQmlRefPointer<QQmlDataBlob>> m_waitingFor;
+
+ int m_redirectCount:30;
+ bool m_inCallback:1;
+ bool m_isDone:1;
+};
+
+QT_END_NAMESPACE
+
+#endif // QQMLDATABLOB_P_H
diff --git a/src/qml/qml/qqmldelayedcallqueue.cpp b/src/qml/qml/qqmldelayedcallqueue.cpp
index 857b5be8b8..02fde97b3d 100644
--- a/src/qml/qml/qqmldelayedcallqueue.cpp
+++ b/src/qml/qml/qqmldelayedcallqueue.cpp
@@ -43,6 +43,7 @@
#include <private/qv4value_p.h>
#include <private/qv4jscall_p.h>
#include <private/qv4qobjectwrapper_p.h>
+#include <private/qv4qmlcontext_p.h>
#include <QQmlError>
diff --git a/src/qml/qml/qqmldirdata.cpp b/src/qml/qml/qqmldirdata.cpp
new file mode 100644
index 0000000000..ec398fa896
--- /dev/null
+++ b/src/qml/qml/qqmldirdata.cpp
@@ -0,0 +1,96 @@
+/****************************************************************************
+**
+** 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 <private/qqmldirdata_p.h>
+
+QT_BEGIN_NAMESPACE
+
+QQmlQmldirData::QQmlQmldirData(const QUrl &url, QQmlTypeLoader *loader)
+ : QQmlTypeLoader::Blob(url, QmldirFile, loader)
+{
+}
+
+const QString &QQmlQmldirData::content() const
+{
+ return m_content;
+}
+
+const QV4::CompiledData::Import *QQmlQmldirData::import(QQmlTypeLoader::Blob *blob) const
+{
+ QHash<QQmlTypeLoader::Blob *, const QV4::CompiledData::Import *>::const_iterator it =
+ m_imports.find(blob);
+ if (it == m_imports.end())
+ return nullptr;
+ return *it;
+}
+
+void QQmlQmldirData::setImport(QQmlTypeLoader::Blob *blob, const QV4::CompiledData::Import *import)
+{
+ m_imports[blob] = 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;
+}
+
+void QQmlQmldirData::dataReceived(const SourceCodeData &data)
+{
+ QString error;
+ m_content = data.readAll(&error);
+ if (!error.isEmpty()) {
+ setError(error);
+ return;
+ }
+}
+
+void QQmlQmldirData::initializeFromCachedUnit(const QV4::CompiledData::Unit *)
+{
+ Q_UNIMPLEMENTED();
+}
+
+QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmldirdata_p.h b/src/qml/qml/qqmldirdata_p.h
new file mode 100644
index 0000000000..6af393c47f
--- /dev/null
+++ b/src/qml/qml/qqmldirdata_p.h
@@ -0,0 +1,86 @@
+/****************************************************************************
+**
+** 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 QQMLDIRDATA_P_H
+#define QQMLDIRDATA_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/qqmltypeloader_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class Q_AUTOTEST_EXPORT QQmlQmldirData : public QQmlTypeLoader::Blob
+{
+private:
+ friend class QQmlTypeLoader;
+
+ QQmlQmldirData(const QUrl &, QQmlTypeLoader *);
+
+public:
+ const QString &content() const;
+
+ const QV4::CompiledData::Import *import(QQmlTypeLoader::Blob *) const;
+ void setImport(QQmlTypeLoader::Blob *, const QV4::CompiledData::Import *);
+
+ int priority(QQmlTypeLoader::Blob *) const;
+ void setPriority(QQmlTypeLoader::Blob *, int);
+
+protected:
+ void dataReceived(const SourceCodeData &) override;
+ void initializeFromCachedUnit(const QV4::CompiledData::Unit *) override;
+
+private:
+ QString m_content;
+ QHash<QQmlTypeLoader::Blob *, const QV4::CompiledData::Import *> m_imports;
+ QHash<QQmlTypeLoader::Blob *, int> m_priorities;
+};
+
+QT_END_NAMESPACE
+
+#endif // QQMLDIRDATA_P_H
diff --git a/src/qml/qml/qqmlengine.cpp b/src/qml/qml/qqmlengine.cpp
index e726e0810d..00d2a6b502 100644
--- a/src/qml/qml/qqmlengine.cpp
+++ b/src/qml/qml/qqmlengine.cpp
@@ -51,14 +51,15 @@
#include "qqmlscriptstring.h"
#include "qqmlglobal_p.h"
#include "qqmlcomponent_p.h"
-#include "qqmldirparser_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/qqmlboundsignal_p.h>
+#include <private/qqmljsdiagnosticmessage_p.h>
#include <QtCore/qstandardpaths.h>
#include <QtCore/qsettings.h>
#include <QtCore/qmetaobject.h>
@@ -1790,7 +1791,7 @@ void QQmlData::deferData(int objectIndex, const QQmlRefPointer<QV4::ExecutableCo
deferData->context = context;
const QV4::CompiledData::Object *compiledObject = compilationUnit->objectAt(objectIndex);
- const QV4::CompiledData::BindingPropertyData &propertyData = compilationUnit->bindingPropertyDataPerObject.at(objectIndex);
+ const QV4::BindingPropertyData &propertyData = compilationUnit->bindingPropertyDataPerObject.at(objectIndex);
const QV4::CompiledData::Binding *binding = compiledObject->bindingTable();
for (quint32 i = 0; i < compiledObject->nBindings; ++i, ++binding) {
@@ -2115,10 +2116,11 @@ void QQmlEnginePrivate::warning(QQmlEnginePrivate *engine, const QList<QQmlError
dumpwarning(error);
}
-QList<QQmlError> QQmlEnginePrivate::qmlErrorFromDiagnostics(const QString &fileName, const QList<DiagnosticMessage> &diagnosticMessages)
+QList<QQmlError> QQmlEnginePrivate::qmlErrorFromDiagnostics(
+ const QString &fileName, const QList<QQmlJS::DiagnosticMessage> &diagnosticMessages)
{
QList<QQmlError> errors;
- for (const DiagnosticMessage &m : diagnosticMessages) {
+ for (const QQmlJS::DiagnosticMessage &m : diagnosticMessages) {
if (m.isWarning()) {
qWarning("%s:%d : %s", qPrintable(fileName), m.line, qPrintable(m.message));
continue;
@@ -2325,6 +2327,17 @@ 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);
diff --git a/src/qml/qml/qqmlengine_p.h b/src/qml/qml/qqmlengine_p.h
index e58ff554a7..385ae02ce5 100644
--- a/src/qml/qml/qqmlengine_p.h
+++ b/src/qml/qml/qqmlengine_p.h
@@ -66,6 +66,7 @@
#include <private/qintrusivelist_p.h>
#include <private/qrecyclepool_p.h>
#include <private/qfieldlist_p.h>
+#include <private/qv4engine_p.h>
#include <QtCore/qlist.h>
#include <QtCore/qpair.h>
diff --git a/src/qml/qml/qqmlexpression.cpp b/src/qml/qml/qqmlexpression.cpp
index be0adc54a7..f6a5afb891 100644
--- a/src/qml/qml/qqmlexpression.cpp
+++ b/src/qml/qml/qqmlexpression.cpp
@@ -46,6 +46,7 @@
#include "qqmlscriptstring_p.h"
#include "qqmlbinding_p.h"
#include <private/qqmlsourcecoordinate_p.h>
+#include <private/qv4qmlcontext_p.h>
#include <QtCore/qdebug.h>
diff --git a/src/qml/qml/qqmlimport.cpp b/src/qml/qml/qqmlimport.cpp
index 95ab79070d..f4cdb45aff 100644
--- a/src/qml/qml/qqmlimport.cpp
+++ b/src/qml/qml/qqmlimport.cpp
@@ -55,6 +55,7 @@
#include <private/qqmlengine_p.h>
#include <private/qfieldlist_p.h>
#include <private/qqmltypemodule_p.h>
+#include <private/qqmltypeloaderqmldircontent_p.h>
#include <QtCore/qjsonobject.h>
#include <QtCore/qjsonarray.h>
diff --git a/src/qml/qml/qqmlinfo.h b/src/qml/qml/qqmlinfo.h
index 673125632e..faa112d4af 100644
--- a/src/qml/qml/qqmlinfo.h
+++ b/src/qml/qml/qqmlinfo.h
@@ -40,6 +40,7 @@
#ifndef QQMLINFO_H
#define QQMLINFO_H
+#include <QtQml/qtqmlglobal.h>
#include <QtCore/qdebug.h>
#include <QtCore/qurl.h>
#include <QtQml/qqmlerror.h>
diff --git a/src/qml/qml/qqmlirloader.cpp b/src/qml/qml/qqmlirloader.cpp
index c2eb6da2fa..82cad8eba8 100644
--- a/src/qml/qml/qqmlirloader.cpp
+++ b/src/qml/qml/qqmlirloader.cpp
@@ -136,10 +136,10 @@ QmlIR::Object *QQmlIRLoader::loadObject(const QV4::CompiledData::Object *seriali
QmlIR::Signal *s = pool->New<QmlIR::Signal>();
s->nameIndex = serializedSignal->nameIndex;
s->location = serializedSignal->location;
- s->parameters = pool->New<QmlIR::PoolList<QmlIR::SignalParameter> >();
+ s->parameters = pool->New<QmlIR::PoolList<QmlIR::Parameter> >();
for (uint i = 0; i < serializedSignal->nParameters; ++i) {
- QmlIR::SignalParameter *p = pool->New<QmlIR::SignalParameter>();
+ QmlIR::Parameter *p = pool->New<QmlIR::Parameter>();
*static_cast<QV4::CompiledData::Parameter*>(p) = *serializedSignal->parameterAt(i);
s->parameters->append(p);
}
@@ -188,11 +188,12 @@ QmlIR::Object *QQmlIRLoader::loadObject(const QV4::CompiledData::Object *seriali
f->index = functionIndices.count() - 1;
f->location = compiledFunction->location;
f->nameIndex = compiledFunction->nameIndex;
+ f->returnType = compiledFunction->returnType;
f->formals.allocate(pool, int(compiledFunction->nFormals));
- const quint32_le *formalNameIdx = compiledFunction->formalsTable();
+ const QV4::CompiledData::Parameter *formalNameIdx = compiledFunction->formalsTable();
for (uint i = 0; i < compiledFunction->nFormals; ++i, ++formalNameIdx)
- f->formals[i] = *formalNameIdx;
+ *static_cast<QV4::CompiledData::Parameter*>(&f->formals[i]) = *formalNameIdx;
object->functions->append(f);
}
diff --git a/src/qml/qml/qqmlmetatype.cpp b/src/qml/qml/qqmlmetatype.cpp
index 67fdf8847b..f21427ff69 100644
--- a/src/qml/qml/qqmlmetatype.cpp
+++ b/src/qml/qml/qqmlmetatype.cpp
@@ -44,6 +44,7 @@
#include <private/qqmltype_p_p.h>
#include <private/qqmltypeloader_p.h>
#include <private/qqmlextensionplugin_p.h>
+#include <private/qv4executablecompilationunit_p.h>
#include <QtCore/qcoreapplication.h>
#include <QtCore/qmutex.h>
diff --git a/src/qml/qml/qqmlobjectcreator.cpp b/src/qml/qml/qqmlobjectcreator.cpp
index be40eeb58a..d5681b3449 100644
--- a/src/qml/qml/qqmlobjectcreator.cpp
+++ b/src/qml/qml/qqmlobjectcreator.cpp
@@ -55,6 +55,7 @@
#include <private/qqmlvaluetypeproxybinding_p.h>
#include <private/qqmldebugconnector_p.h>
#include <private/qqmldebugserviceinterfaces_p.h>
+#include <private/qqmlscriptdata_p.h>
#include <private/qjsvalue_p.h>
#include <qtqml_tracepoints_p.h>
@@ -735,7 +736,7 @@ void QQmlObjectCreator::setupBindings(bool applyDeferredBindings)
QQmlListProperty<void> savedList;
qSwap(_currentList, savedList);
- const QV4::CompiledData::BindingPropertyData &propertyData = compilationUnit->bindingPropertyDataPerObject.at(_compiledObjectIndex);
+ const QV4::BindingPropertyData &propertyData = compilationUnit->bindingPropertyDataPerObject.at(_compiledObjectIndex);
if (_compiledObject->idNameIndex) {
const QQmlPropertyData *idProperty = propertyData.last();
@@ -1445,8 +1446,12 @@ void QQmlObjectCreator::clear()
return;
Q_ASSERT(phase != Startup);
- while (!sharedState->allCreatedObjects.isEmpty())
- delete sharedState->allCreatedObjects.pop();
+ while (!sharedState->allCreatedObjects.isEmpty()) {
+ auto object = sharedState->allCreatedObjects.pop();
+ if (engine->objectOwnership(object) != QQmlEngine::CppOwnership) {
+ delete object;
+ }
+ }
while (sharedState->componentAttached) {
QQmlComponentAttached *a = sharedState->componentAttached;
diff --git a/src/qml/qml/qqmlobjectcreator_p.h b/src/qml/qml/qqmlobjectcreator_p.h
index 1cbad87920..ecdbcc56dd 100644
--- a/src/qml/qml/qqmlobjectcreator_p.h
+++ b/src/qml/qml/qqmlobjectcreator_p.h
@@ -53,17 +53,16 @@
#include <private/qqmlimport_p.h>
#include <private/qqmltypenamecache_p.h>
#include <private/qv4compileddata_p.h>
-#include <private/qqmltypecompiler_p.h>
#include <private/qfinitestack_p.h>
#include <private/qrecursionwatcher_p.h>
#include <private/qqmlprofiler_p.h>
+#include <private/qv4qmlcontext_p.h>
#include <qpointer.h>
QT_BEGIN_NAMESPACE
class QQmlAbstractBinding;
-struct QQmlTypeCompiler;
class QQmlInstantiationInterrupt;
class QQmlIncubatorPrivate;
diff --git a/src/qml/qml/qqmlpropertycache.cpp b/src/qml/qml/qqmlpropertycache.cpp
index 48c4216d54..69957ab282 100644
--- a/src/qml/qml/qqmlpropertycache.cpp
+++ b/src/qml/qml/qqmlpropertycache.cpp
@@ -348,17 +348,18 @@ void QQmlPropertyCache::appendSignal(const QString &name, QQmlPropertyData::Flag
}
void QQmlPropertyCache::appendMethod(const QString &name, QQmlPropertyData::Flags flags,
- int coreIndex, const QList<QByteArray> &names)
+ int coreIndex, int returnType, const QList<QByteArray> &names,
+ const QVector<int> &parameterTypes)
{
int argumentCount = names.count();
QQmlPropertyData data;
- data.setPropType(QMetaType::QVariant);
+ data.setPropType(returnType);
data.setCoreIndex(coreIndex);
QQmlPropertyCacheMethodArguments *args = createArgumentsObject(argumentCount, names);
for (int ii = 0; ii < argumentCount; ++ii)
- args->arguments[ii + 1] = QMetaType::QVariant;
+ args->arguments[ii + 1] = parameterTypes.at(ii);
args->argumentsValid = true;
data.setArguments(args);
diff --git a/src/qml/qml/qqmlpropertycache_p.h b/src/qml/qml/qqmlpropertycache_p.h
index 72692ee522..bfd78eef88 100644
--- a/src/qml/qml/qqmlpropertycache_p.h
+++ b/src/qml/qml/qqmlpropertycache_p.h
@@ -103,8 +103,8 @@ public:
int propType, int 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,
- 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);
void appendEnum(const QString &, const QVector<QQmlEnumValue> &);
const QMetaObject *metaObject() const;
diff --git a/src/qml/qml/qqmlpropertycachecreator_p.h b/src/qml/qml/qqmlpropertycachecreator_p.h
index 14f734277d..9c7a69d571 100644
--- a/src/qml/qml/qqmlpropertycachecreator_p.h
+++ b/src/qml/qml/qqmlpropertycachecreator_p.h
@@ -54,9 +54,20 @@
#include <private/qqmlengine_p.h>
#include <private/qqmlmetaobject_p.h>
#include <private/qqmlpropertyresolver_p.h>
+#include <private/qqmltypedata_p.h>
QT_BEGIN_NAMESPACE
+inline QQmlJS::DiagnosticMessage qQmlCompileError(const QV4::CompiledData::Location &location,
+ const QString &description)
+{
+ QQmlJS::DiagnosticMessage error;
+ error.line = location.line;
+ error.column = location.column;
+ error.message = description;
+ return error;
+}
+
struct QQmlBindingInstantiationContext {
QQmlBindingInstantiationContext() {}
QQmlBindingInstantiationContext(int referencingObjectIndex,
@@ -106,6 +117,8 @@ protected:
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);
+ int metaTypeForParameter(const QV4::CompiledData::ParameterType &param, QString *customTypeName = nullptr);
+
QString stringAt(int index) const { return objectContainer->stringAt(index); }
QQmlEnginePrivate * const enginePrivate;
@@ -404,28 +417,13 @@ inline QQmlJS::DiagnosticMessage QQmlPropertyCacheCreator<ObjectContainer>::crea
auto end = s->parametersEnd();
for ( ; param != end; ++param, ++i) {
names.append(stringAt(param->nameIndex).toUtf8());
- if (param->indexIsBuiltinType) {
- // built-in type
- paramTypes[i + 1] = metaTypeForPropertyType(static_cast<QV4::CompiledData::BuiltinType>(int(param->typeNameIndexOrBuiltinType)));
- } else {
- // lazily resolved type
- const QString customTypeName = stringAt(param->typeNameIndexOrBuiltinType);
- QQmlType qmltype;
- if (!imports->resolveType(customTypeName, &qmltype, nullptr, nullptr, nullptr))
- return qQmlCompileError(s->location, QQmlPropertyCacheCreatorBase::tr("Invalid signal parameter type: %1").arg(customTypeName));
-
- if (qmltype.isComposite()) {
- QQmlRefPointer<QQmlTypeData> tdata = enginePrivate->typeLoader.getType(qmltype.sourceUrl());
- Q_ASSERT(tdata);
- Q_ASSERT(tdata->isComplete());
-
- auto compilationUnit = tdata->compilationUnit();
-
- paramTypes[i + 1] = compilationUnit->metaTypeId;
- } else {
- paramTypes[i + 1] = qmltype.typeId();
- }
- }
+
+ QString customTypeName;
+ auto type = metaTypeForParameter(param->type, &customTypeName);
+ if (type == QMetaType::UnknownType)
+ return qQmlCompileError(s->location, QQmlPropertyCacheCreatorBase::tr("Invalid signal parameter type: %1").arg(customTypeName));
+
+ paramTypes[i + 1] = type;
}
}
@@ -456,14 +454,23 @@ inline QQmlJS::DiagnosticMessage QQmlPropertyCacheCreator<ObjectContainer>::crea
// protect against overriding change signals or methods with properties.
QList<QByteArray> parameterNames;
+ QVector<int> parameterTypes;
auto formal = function->formalsBegin();
auto end = function->formalsEnd();
for ( ; formal != end; ++formal) {
flags.hasArguments = true;
- parameterNames << stringAt(*formal).toUtf8();
+ parameterNames << stringAt(formal->nameIndex).toUtf8();
+ int type = metaTypeForParameter(formal->type);
+ if (type == QMetaType::UnknownType)
+ type = QMetaType::QVariant;
+ parameterTypes << type;
}
- cache->appendMethod(slotName, flags, effectiveMethodIndex++, parameterNames);
+ int returnType = metaTypeForParameter(function->returnType);
+ if (returnType == QMetaType::UnknownType)
+ returnType = QMetaType::QVariant;
+
+ cache->appendMethod(slotName, flags, effectiveMethodIndex++, returnType, parameterNames, parameterTypes);
}
@@ -542,6 +549,35 @@ inline QQmlJS::DiagnosticMessage QQmlPropertyCacheCreator<ObjectContainer>::crea
}
template <typename ObjectContainer>
+inline int QQmlPropertyCacheCreator<ObjectContainer>::metaTypeForParameter(const QV4::CompiledData::ParameterType &param,
+ QString *customTypeName)
+{
+ if (param.indexIsBuiltinType) {
+ // built-in type
+ return metaTypeForPropertyType(static_cast<QV4::CompiledData::BuiltinType>(int(param.typeNameIndexOrBuiltinType)));
+ }
+
+ // lazily resolved type
+ const QString typeName = stringAt(param.typeNameIndexOrBuiltinType);
+ if (customTypeName)
+ *customTypeName = typeName;
+ QQmlType qmltype;
+ if (!imports->resolveType(typeName, &qmltype, nullptr, nullptr, nullptr))
+ return QMetaType::UnknownType;
+
+ if (!qmltype.isComposite())
+ return qmltype.typeId();
+
+ QQmlRefPointer<QQmlTypeData> tdata = enginePrivate->typeLoader.getType(qmltype.sourceUrl());
+ Q_ASSERT(tdata);
+ Q_ASSERT(tdata->isComplete());
+
+ auto compilationUnit = tdata->compilationUnit();
+
+ return compilationUnit->metaTypeId;
+}
+
+template <typename ObjectContainer>
class QQmlPropertyCacheAliasCreator
{
public:
diff --git a/src/qml/qml/qqmlpropertyvalidator.cpp b/src/qml/qml/qqmlpropertyvalidator.cpp
index 6bb00e438d..71964aca64 100644
--- a/src/qml/qml/qqmlpropertyvalidator.cpp
+++ b/src/qml/qml/qqmlpropertyvalidator.cpp
@@ -40,8 +40,11 @@
#include "qqmlpropertyvalidator_p.h"
#include <private/qqmlcustomparser_p.h>
+#include <private/qqmlirbuilder_p.h>
#include <private/qqmlstringconverters_p.h>
+#include <private/qqmlpropertycachecreator_p.h>
#include <private/qqmlpropertyresolver_p.h>
+
#include <QtCore/qdatetime.h>
QT_BEGIN_NAMESPACE
@@ -136,7 +139,7 @@ QVector<QQmlJS::DiagnosticMessage> QQmlPropertyValidator::validateObject(
defaultProperty = propertyCache->defaultProperty();
}
- QV4::CompiledData::BindingPropertyData collectedBindingPropertyData(obj->nBindings);
+ QV4::BindingPropertyData collectedBindingPropertyData(obj->nBindings);
binding = obj->bindingTable();
for (quint32 i = 0; i < obj->nBindings; ++i, ++binding) {
diff --git a/src/qml/qml/qqmlpropertyvalidator_p.h b/src/qml/qml/qqmlpropertyvalidator_p.h
index f2b892e978..74a1281927 100644
--- a/src/qml/qml/qqmlpropertyvalidator_p.h
+++ b/src/qml/qml/qqmlpropertyvalidator_p.h
@@ -50,7 +50,13 @@
// We mean it.
//
-#include <private/qqmltypecompiler_p.h>
+#include <private/qqmlengine_p.h>
+#include <private/qqmlimport_p.h>
+#include <private/qqmljsdiagnosticmessage_p.h>
+#include <private/qqmlpropertycache_p.h>
+#include <private/qv4compileddata_p.h>
+
+#include <QtCore/qcoreapplication.h>
QT_BEGIN_NAMESPACE
@@ -91,7 +97,7 @@ private:
const QV4::CompiledData::Unit *qmlUnit;
const QQmlPropertyCacheVector &propertyCaches;
- QVector<QV4::CompiledData::BindingPropertyData> * const bindingPropertyDataPerObject;
+ QVector<QV4::BindingPropertyData> * const bindingPropertyDataPerObject;
};
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlscriptblob.cpp b/src/qml/qml/qqmlscriptblob.cpp
new file mode 100644
index 0000000000..69b26894a8
--- /dev/null
+++ b/src/qml/qml/qqmlscriptblob.cpp
@@ -0,0 +1,263 @@
+/****************************************************************************
+**
+** 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 <private/qqmlengine_p.h>
+#include <private/qqmlirbuilder_p.h>
+#include <private/qqmlscriptblob_p.h>
+#include <private/qqmlscriptdata_p.h>
+#include <private/qv4runtimecodegen_p.h>
+#include <private/qv4script_p.h>
+
+#include <QtCore/qloggingcategory.h>
+
+Q_DECLARE_LOGGING_CATEGORY(DBG_DISK_CACHE)
+Q_LOGGING_CATEGORY(DBG_DISK_CACHE, "qt.qml.diskcache")
+
+QT_BEGIN_NAMESPACE
+
+QQmlScriptBlob::QQmlScriptBlob(const QUrl &url, QQmlTypeLoader *loader)
+ : QQmlTypeLoader::Blob(url, JavaScriptFile, loader)
+ , m_isModule(url.path().endsWith(QLatin1String(".mjs")))
+{
+}
+
+QQmlScriptBlob::~QQmlScriptBlob()
+{
+}
+
+QQmlRefPointer<QQmlScriptData> QQmlScriptBlob::scriptData() const
+{
+ return m_scriptData;
+}
+
+void QQmlScriptBlob::dataReceived(const SourceCodeData &data)
+{
+ if (!diskCacheDisabled() || diskCacheForced()) {
+ QQmlRefPointer<QV4::ExecutableCompilationUnit> unit
+ = QV4::ExecutableCompilationUnit::create();
+ QString error;
+ if (unit->loadFromDisk(url(), data.sourceTimeStamp(), &error)) {
+ initializeFromCompilationUnit(unit);
+ return;
+ } else {
+ qCDebug(DBG_DISK_CACHE()) << "Error loading" << urlString() << "from disk cache:" << error;
+ }
+ }
+
+ if (!data.exists()) {
+ if (m_cachedUnitStatus == QQmlMetaType::CachedUnitLookupError::VersionMismatch)
+ setError(QQmlTypeLoader::tr("File was compiled ahead of time with an incompatible version of Qt and the original file cannot be found. Please recompile"));
+ else
+ setError(QQmlTypeLoader::tr("No such file or directory"));
+ return;
+ }
+
+ QString error;
+ QString source = data.readAll(&error);
+ if (!error.isEmpty()) {
+ setError(error);
+ return;
+ }
+
+ QV4::CompiledData::CompilationUnit unit;
+
+ if (m_isModule) {
+ QList<QQmlJS::DiagnosticMessage> diagnostics;
+ unit = QV4::Compiler::Codegen::compileModule(isDebugging(), urlString(), source,
+ data.sourceTimeStamp(), &diagnostics);
+ QList<QQmlError> errors = QQmlEnginePrivate::qmlErrorFromDiagnostics(urlString(), diagnostics);
+ if (!errors.isEmpty()) {
+ setError(errors);
+ return;
+ }
+ } else {
+ QmlIR::Document irUnit(isDebugging());
+
+ irUnit.jsModule.sourceTimeStamp = data.sourceTimeStamp();
+
+ QmlIR::ScriptDirectivesCollector collector(&irUnit);
+ irUnit.jsParserEngine.setDirectives(&collector);
+
+ QList<QQmlError> errors;
+ irUnit.javaScriptCompilationUnit = QV4::Script::precompile(
+ &irUnit.jsModule, &irUnit.jsParserEngine, &irUnit.jsGenerator, urlString(), finalUrlString(),
+ source, &errors, QV4::Compiler::ContextType::ScriptImportedByQML);
+
+ source.clear();
+ if (!errors.isEmpty()) {
+ setError(errors);
+ return;
+ }
+
+ QmlIR::QmlUnitGenerator qmlGenerator;
+ qmlGenerator.generate(irUnit);
+ unit = std::move(irUnit.javaScriptCompilationUnit);
+ }
+
+ auto executableUnit = QV4::ExecutableCompilationUnit::create(std::move(unit));
+
+ if ((!diskCacheDisabled() || diskCacheForced()) && !isDebugging()) {
+ QString errorString;
+ if (executableUnit->saveToDisk(url(), &errorString)) {
+ QString error;
+ if (!executableUnit->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;
+ }
+ }
+
+ initializeFromCompilationUnit(executableUnit);
+}
+
+void QQmlScriptBlob::initializeFromCachedUnit(const QV4::CompiledData::Unit *unit)
+{
+ initializeFromCompilationUnit(QV4::ExecutableCompilationUnit::create(
+ QV4::CompiledData::CompilationUnit(unit, urlString(), finalUrlString())));
+}
+
+void QQmlScriptBlob::done()
+{
+ if (isError())
+ return;
+
+ // Check all script dependencies for errors
+ for (int ii = 0; ii < m_scripts.count(); ++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.setDescription(QQmlTypeLoader::tr("Script %1 unavailable").arg(script.script->urlString()));
+ errors.prepend(error);
+ setError(errors);
+ return;
+ }
+ }
+
+ if (!m_isModule) {
+ m_scriptData->typeNameCache = new QQmlTypeNameCache(m_importCache);
+
+ QSet<QString> ns;
+
+ for (int scriptIndex = 0; scriptIndex < m_scripts.count(); ++scriptIndex) {
+ const ScriptReference &script = m_scripts.at(scriptIndex);
+
+ m_scriptData->scripts.append(script.script);
+
+ if (!script.nameSpace.isNull()) {
+ if (!ns.contains(script.nameSpace)) {
+ ns.insert(script.nameSpace);
+ m_scriptData->typeNameCache->add(script.nameSpace);
+ }
+ }
+ m_scriptData->typeNameCache->add(script.qualifier, scriptIndex, script.nameSpace);
+ }
+
+ m_importCache.populateCache(m_scriptData->typeNameCache);
+ }
+ m_scripts.clear();
+}
+
+QString QQmlScriptBlob::stringAt(int index) const
+{
+ return m_scriptData->m_precompiledScript->stringAt(index);
+}
+
+void QQmlScriptBlob::scriptImported(const QQmlRefPointer<QQmlScriptBlob> &blob, const QV4::CompiledData::Location &location, const QString &qualifier, const QString &nameSpace)
+{
+ ScriptReference ref;
+ ref.script = blob;
+ ref.location = location;
+ ref.qualifier = qualifier;
+ ref.nameSpace = nameSpace;
+
+ m_scripts << ref;
+}
+
+void QQmlScriptBlob::initializeFromCompilationUnit(const QQmlRefPointer<QV4::ExecutableCompilationUnit> &unit)
+{
+ Q_ASSERT(!m_scriptData);
+ 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;
+
+ 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)) {
+ 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);
+ return;
+ }
+ }
+ }
+
+ auto *v4 = QQmlEnginePrivate::getV4Engine(typeLoader()->engine());
+
+ v4->injectModule(unit);
+
+ for (const QString &request: unit->moduleRequests()) {
+ if (v4->moduleForUrl(QUrl(request), unit.data()))
+ 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());
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlscriptblob_p.h b/src/qml/qml/qqmlscriptblob_p.h
new file mode 100644
index 0000000000..10c0437e7b
--- /dev/null
+++ b/src/qml/qml/qqmlscriptblob_p.h
@@ -0,0 +1,97 @@
+/****************************************************************************
+**
+** 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 QQMLSCRIPTBLOB_P_H
+#define QQMLSCRIPTBLOB_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/qqmltypeloader_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQmlScriptData;
+class Q_AUTOTEST_EXPORT QQmlScriptBlob : public QQmlTypeLoader::Blob
+{
+private:
+ friend class QQmlTypeLoader;
+
+ QQmlScriptBlob(const QUrl &, QQmlTypeLoader *);
+
+public:
+ ~QQmlScriptBlob() override;
+
+ struct ScriptReference
+ {
+ QV4::CompiledData::Location location;
+ QString qualifier;
+ QString nameSpace;
+ QQmlRefPointer<QQmlScriptBlob> script;
+ };
+
+ QQmlRefPointer<QQmlScriptData> scriptData() const;
+
+protected:
+ void dataReceived(const SourceCodeData &) override;
+ void initializeFromCachedUnit(const QV4::CompiledData::Unit *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);
+
+ QList<ScriptReference> m_scripts;
+ QQmlRefPointer<QQmlScriptData> m_scriptData;
+ const bool m_isModule;
+};
+
+QT_END_NAMESPACE
+
+#endif // QQMLSCRIPTBLOB_P_H
diff --git a/src/qml/qml/qqmlscriptdata.cpp b/src/qml/qml/qqmlscriptdata.cpp
new file mode 100644
index 0000000000..0725f40d2a
--- /dev/null
+++ b/src/qml/qml/qqmlscriptdata.cpp
@@ -0,0 +1,170 @@
+/****************************************************************************
+**
+** 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 <private/qqmlscriptdata_p.h>
+#include <private/qqmlcontext_p.h>
+#include <private/qqmlengine_p.h>
+#include <private/qqmlscriptblob_p.h>
+#include <private/qv4engine_p.h>
+#include <private/qv4scopedvalue_p.h>
+#include <private/qv4object_p.h>
+#include <private/qv4qmlcontext_p.h>
+#include <private/qv4module_p.h>
+
+QT_BEGIN_NAMESPACE
+
+QQmlScriptData::QQmlScriptData()
+ : typeNameCache(nullptr)
+ , m_loaded(false)
+{
+}
+
+QQmlContextData *QQmlScriptData::qmlContextDataForContext(QQmlContextData *parentQmlContextData)
+{
+ Q_ASSERT(parentQmlContextData && parentQmlContextData->engine);
+
+ if (m_precompiledScript->isESModule())
+ return nullptr;
+
+ auto qmlContextData = new QQmlContextData();
+
+ qmlContextData->isInternal = true;
+ qmlContextData->isJSContext = true;
+ if (m_precompiledScript->isSharedLibrary())
+ qmlContextData->isPragmaLibraryContext = true;
+ else
+ qmlContextData->isPragmaLibraryContext = parentQmlContextData->isPragmaLibraryContext;
+ qmlContextData->baseUrl = url;
+ qmlContextData->baseUrlString = 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;
+ } else if (!m_precompiledScript->isSharedLibrary()) {
+ qmlContextData->imports = parentQmlContextData->imports;
+ qmlContextData->importedScripts = parentQmlContextData->importedScripts;
+ }
+
+ if (!m_precompiledScript->isSharedLibrary()) {
+ qmlContextData->setParent(parentQmlContextData);
+ } else {
+ qmlContextData->engine = parentQmlContextData->engine; // Fix for QTBUG-21620
+ }
+
+ 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);
+ } else {
+ 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)));
+
+ return qmlContextData;
+}
+
+QV4::ReturnedValue QQmlScriptData::scriptValueForContext(QQmlContextData *parentQmlContextData)
+{
+ if (m_loaded)
+ return m_value.value();
+
+ Q_ASSERT(parentQmlContextData && parentQmlContextData->engine);
+ QV4::ExecutionEngine *v4 = parentQmlContextData->engine->handle();
+ QV4::Scope scope(v4);
+
+ if (!hasEngine()) {
+ addToEngine(parentQmlContextData->engine);
+ addref();
+ }
+
+ 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, m_precompiledScript->instantiate(v4));
+ if (module) {
+ if (qmlContextData) {
+ module->d()->scope->outer.set(v4, qmlExecutionContext->d());
+ qmlExecutionContext->d()->qml()->module.set(v4, module->d());
+ }
+
+ module->evaluate();
+ }
+
+ if (v4->hasException) {
+ QQmlError error = v4->catchExceptionAsQmlError();
+ if (error.isValid())
+ QQmlEnginePrivate::get(v4)->warning(error);
+ }
+
+ QV4::ScopedValue value(scope);
+ if (qmlContextData)
+ value = qmlExecutionContext->d()->qml();
+ else if (module)
+ value = module->d();
+
+ if (m_precompiledScript->isSharedLibrary() || m_precompiledScript->isESModule()) {
+ m_loaded = true;
+ m_value.set(v4, value);
+ }
+
+ return value->asReturnedValue();
+}
+
+void QQmlScriptData::clear()
+{
+ if (typeNameCache) {
+ typeNameCache->release();
+ 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
new file mode 100644
index 0000000000..273ba3691f
--- /dev/null
+++ b/src/qml/qml/qqmlscriptdata_p.h
@@ -0,0 +1,108 @@
+/****************************************************************************
+**
+** 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 QQMLSCRIPTDATA_P_H
+#define QQMLSCRIPTDATA_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/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 <QtCore/qurl.h>
+
+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
+{
+private:
+ friend class QQmlTypeLoader;
+
+ QQmlScriptData();
+
+public:
+ QUrl url;
+ QString urlString;
+ QQmlTypeNameCache *typeNameCache;
+ QVector<QQmlRefPointer<QQmlScriptBlob>> scripts;
+
+ QV4::ReturnedValue scriptValueForContext(QQmlContextData *parentCtxt);
+
+ QQmlRefPointer<QV4::ExecutableCompilationUnit> compilationUnit() const { return m_precompiledScript; }
+
+protected:
+ void clear() override; // From QQmlCleanup
+
+private:
+ friend class QQmlScriptBlob;
+
+ void initialize(QQmlEngine *);
+ QQmlContextData *qmlContextDataForContext(QQmlContextData *parentQmlContextData);
+
+ bool m_loaded;
+ QQmlRefPointer<QV4::ExecutableCompilationUnit> m_precompiledScript;
+ QV4::PersistentValue m_value;
+};
+
+QT_END_NAMESPACE
+
+#endif // QQMLSCRIPTDATA_P_H
diff --git a/src/qml/qml/qqmltype.cpp b/src/qml/qml/qqmltype.cpp
index 6b4e0a0734..2a6831d898 100644
--- a/src/qml/qml/qqmltype.cpp
+++ b/src/qml/qml/qqmltype.cpp
@@ -48,6 +48,7 @@
#include <private/qqmldata_p.h>
#include <private/qqmlmetatypedata_p.h>
#include <private/qqmlpropertycache_p.h>
+#include <private/qqmltypedata_p.h>
QT_BEGIN_NAMESPACE
diff --git a/src/qml/qml/qqmltypecompiler.cpp b/src/qml/qml/qqmltypecompiler.cpp
index 6cbe81b4b8..e7633a1bba 100644
--- a/src/qml/qml/qqmltypecompiler.cpp
+++ b/src/qml/qml/qqmltypecompiler.cpp
@@ -39,7 +39,6 @@
#include "qqmltypecompiler_p.h"
-#include <private/qqmlirbuilder_p.h>
#include <private/qqmlobjectcreator_p.h>
#include <private/qqmlcustomparser_p.h>
#include <private/qqmlvmemetaobject_p.h>
@@ -145,11 +144,11 @@ QQmlRefPointer<QV4::ExecutableCompilationUnit> QQmlTypeCompiler::compile()
document->jsModule.fileName = typeData->urlString();
document->jsModule.finalUrl = typeData->finalUrlString();
- QmlIR::JSCodeGen v4CodeGenerator(document->code, &document->jsGenerator, &document->jsModule, &document->jsParserEngine,
- document->program, &document->jsGenerator.stringTable, engine->v4engine()->illegalNames());
- QQmlJSCodeGenerator jsCodeGen(this, &v4CodeGenerator);
- if (!jsCodeGen.generateCodeForComponents())
+ QmlIR::JSCodeGen v4CodeGenerator(document, engine->v4engine()->illegalNames());
+ if (!v4CodeGenerator.generateCodeForComponents(componentRoots())) {
+ recordError(v4CodeGenerator.error());
return nullptr;
+ }
document->javaScriptCompilationUnit = v4CodeGenerator.generateCompilationUnit(/*generated unit data*/false);
}
@@ -1309,76 +1308,6 @@ bool QQmlDeferredAndCustomParserBindingScanner::scanObject(int objectIndex)
return true;
}
-QQmlJSCodeGenerator::QQmlJSCodeGenerator(QQmlTypeCompiler *typeCompiler, QmlIR::JSCodeGen *v4CodeGen)
- : QQmlCompilePass(typeCompiler)
- , customParsers(typeCompiler->customParserCache())
- , qmlObjects(*typeCompiler->qmlObjects())
- , propertyCaches(typeCompiler->propertyCaches())
- , v4CodeGen(v4CodeGen)
-{
-}
-
-bool QQmlJSCodeGenerator::generateCodeForComponents()
-{
- const QVector<quint32> &componentRoots = compiler->componentRoots();
- for (int i = 0; i < componentRoots.count(); ++i) {
- if (!compileComponent(componentRoots.at(i)))
- return false;
- }
-
- return compileComponent(/*root object*/0);
-}
-
-bool QQmlJSCodeGenerator::compileComponent(int contextObject)
-{
- const QmlIR::Object *obj = qmlObjects.at(contextObject);
- if (obj->flags & QV4::CompiledData::Object::IsComponent) {
- Q_ASSERT(obj->bindingCount() == 1);
- const QV4::CompiledData::Binding *componentBinding = obj->firstBinding();
- Q_ASSERT(componentBinding->type == QV4::CompiledData::Binding::Type_Object);
- contextObject = componentBinding->value.objectIndex;
- }
-
- if (!compileJavaScriptCodeInObjectsRecursively(contextObject, contextObject))
- return false;
-
- return true;
-}
-
-bool QQmlJSCodeGenerator::compileJavaScriptCodeInObjectsRecursively(int objectIndex, int scopeObjectIndex)
-{
- QmlIR::Object *object = qmlObjects.at(objectIndex);
- if (object->flags & QV4::CompiledData::Object::IsComponent)
- return true;
-
- if (object->functionsAndExpressions->count > 0) {
- QList<QmlIR::CompiledFunctionOrExpression> functionsToCompile;
- for (QmlIR::CompiledFunctionOrExpression *foe = object->functionsAndExpressions->first; foe; foe = foe->next)
- functionsToCompile << *foe;
- const QVector<int> runtimeFunctionIndices = v4CodeGen->generateJSCodeForFunctionsAndBindings(functionsToCompile);
- if (v4CodeGen->hasError()) {
- compiler->recordError(v4CodeGen->error());
- return false;
- }
-
- QQmlJS::MemoryPool *pool = compiler->memoryPool();
- object->runtimeFunctionIndices.allocate(pool, runtimeFunctionIndices);
- }
-
- for (const QmlIR::Binding *binding = object->firstBinding(); binding; binding = binding->next) {
- if (binding->type < QV4::CompiledData::Binding::Type_Object)
- continue;
-
- int target = binding->value.objectIndex;
- int scope = binding->type == QV4::CompiledData::Binding::Type_Object ? target : scopeObjectIndex;
-
- if (!compileJavaScriptCodeInObjectsRecursively(binding->value.objectIndex, scope))
- return false;
- }
-
- return true;
-}
-
QQmlDefaultPropertyMerger::QQmlDefaultPropertyMerger(QQmlTypeCompiler *typeCompiler)
: QQmlCompilePass(typeCompiler)
, qmlObjects(*typeCompiler->qmlObjects())
diff --git a/src/qml/qml/qqmltypecompiler_p.h b/src/qml/qml/qqmltypecompiler_p.h
index 615694d4bc..40b0337848 100644
--- a/src/qml/qml/qqmltypecompiler_p.h
+++ b/src/qml/qml/qqmltypecompiler_p.h
@@ -309,24 +309,6 @@ private:
bool _seenObjectWithId;
};
-// ### merge with QtQml::JSCodeGen and operate directly on object->functionsAndExpressions once old compiler is gone.
-class QQmlJSCodeGenerator : public QQmlCompilePass
-{
-public:
- QQmlJSCodeGenerator(QQmlTypeCompiler *typeCompiler, QmlIR::JSCodeGen *v4CodeGen);
-
- bool generateCodeForComponents();
-
-private:
- bool compileComponent(int componentRoot);
- bool compileJavaScriptCodeInObjectsRecursively(int objectIndex, int scopeObjectIndex);
-
- const QHash<int, QQmlCustomParser*> &customParsers;
- const QVector<QmlIR::Object*> &qmlObjects;
- const QQmlPropertyCacheVector * const propertyCaches;
- QmlIR::JSCodeGen * const v4CodeGen;
-};
-
class QQmlDefaultPropertyMerger : public QQmlCompilePass
{
public:
diff --git a/src/qml/qml/qqmltypedata.cpp b/src/qml/qml/qqmltypedata.cpp
new file mode 100644
index 0000000000..12d4d8cbad
--- /dev/null
+++ b/src/qml/qml/qqmltypedata.cpp
@@ -0,0 +1,844 @@
+/****************************************************************************
+**
+** 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/qqmltypedata_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/qqmlscriptblob_p.h>
+#include <private/qqmlscriptdata_p.h>
+#include <private/qqmltypecompiler_p.h>
+
+#include <QtCore/qloggingcategory.h>
+#include <QtCore/qcryptographichash.h>
+
+Q_DECLARE_LOGGING_CATEGORY(DBG_DISK_CACHE)
+
+QT_BEGIN_NAMESPACE
+
+QQmlTypeData::TypeDataCallback::~TypeDataCallback()
+{
+}
+
+QString QQmlTypeData::TypeReference::qualifiedName() const
+{
+ QString result;
+ if (!prefix.isEmpty()) {
+ result = prefix + QLatin1Char('.');
+ }
+ result.append(type.qmlTypeName());
+ return result;
+}
+
+QQmlTypeData::QQmlTypeData(const QUrl &url, QQmlTypeLoader *manager)
+ : QQmlTypeLoader::Blob(url, QmlFile, manager),
+ m_typesResolved(false), m_implicitImportLoaded(false)
+{
+
+}
+
+QQmlTypeData::~QQmlTypeData()
+{
+ m_scripts.clear();
+ m_compositeSingletons.clear();
+ m_resolvedTypes.clear();
+}
+
+const QList<QQmlTypeData::ScriptReference> &QQmlTypeData::resolvedScripts() const
+{
+ return m_scripts;
+}
+
+QV4::ExecutableCompilationUnit *QQmlTypeData::compilationUnit() const
+{
+ return m_compiledData.data();
+}
+
+void QQmlTypeData::registerCallback(TypeDataCallback *callback)
+{
+ Q_ASSERT(!m_callbacks.contains(callback));
+ m_callbacks.append(callback);
+}
+
+void QQmlTypeData::unregisterCallback(TypeDataCallback *callback)
+{
+ Q_ASSERT(m_callbacks.contains(callback));
+ m_callbacks.removeOne(callback);
+ Q_ASSERT(!m_callbacks.contains(callback));
+}
+
+bool QQmlTypeData::tryLoadFromDiskCache()
+{
+ if (diskCacheDisabled() && !diskCacheForced())
+ return false;
+
+ if (isDebugging())
+ return false;
+
+ QV4::ExecutionEngine *v4 = typeLoader()->engine()->handle();
+ if (!v4)
+ return false;
+
+ QQmlRefPointer<QV4::ExecutableCompilationUnit> unit = QV4::ExecutableCompilationUnit::create();
+ {
+ QString error;
+ if (!unit->loadFromDisk(url(), m_backupSourceCode.sourceTimeStamp(), &error)) {
+ qCDebug(DBG_DISK_CACHE) << "Error loading" << urlString() << "from disk cache:" << error;
+ return false;
+ }
+ }
+
+ if (unit->unitData()->flags & QV4::CompiledData::Unit::PendingTypeCompilation) {
+ restoreIR(std::move(*unit));
+ return true;
+ }
+
+ m_compiledData = unit;
+
+ for (int i = 0, count = m_compiledData->objectCount(); i < count; ++i)
+ m_typeReferences.collectFromObject(m_compiledData->objectAt(i));
+
+ 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
+ // qmldir (so we can't load it just in time).
+ if (!finalUrl().scheme().isEmpty()) {
+ QUrl qmldirUrl = finalUrl().resolved(QUrl(QLatin1String("qmldir")));
+ if (!QQmlImports::isLocal(qmldirUrl)) {
+ if (!loadImplicitImport())
+ return false;
+
+ // find the implicit import
+ for (quint32 i = 0, count = m_compiledData->importCount(); i < count; ++i) {
+ 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) {
+ QList<QQmlError> errors;
+ if (!fetchQmldir(qmldirUrl, import, 1, &errors)) {
+ setError(errors);
+ return false;
+ }
+ break;
+ }
+ }
+ }
+ }
+
+ 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)) {
+ 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);
+ return false;
+ }
+ }
+
+ return true;
+}
+
+void QQmlTypeData::createTypeAndPropertyCaches(
+ const QQmlRefPointer<QQmlTypeNameCache> &typeNameCache,
+ const QV4::ResolvedTypeReferenceMap &resolvedTypeCache)
+{
+ Q_ASSERT(m_compiledData);
+ m_compiledData->typeNameCache = typeNameCache;
+ m_compiledData->resolvedTypes = resolvedTypeCache;
+
+ QQmlEnginePrivate * const engine = QQmlEnginePrivate::get(typeLoader()->engine());
+
+ QQmlPendingGroupPropertyBindings pendingGroupPropertyBindings;
+
+ {
+ QQmlPropertyCacheCreator<QV4::ExecutableCompilationUnit> propertyCacheCreator(
+ &m_compiledData->propertyCaches, &pendingGroupPropertyBindings, engine,
+ m_compiledData.data(), &m_importCache);
+ QQmlJS::DiagnosticMessage error = propertyCacheCreator.buildMetaObjects();
+ if (error.isValid()) {
+ setError(error);
+ return;
+ }
+ }
+
+ QQmlPropertyCacheAliasCreator<QV4::ExecutableCompilationUnit> aliasCreator(
+ &m_compiledData->propertyCaches, m_compiledData.data());
+ aliasCreator.appendAliasPropertiesToMetaObjects();
+
+ pendingGroupPropertyBindings.resolveMissingPropertyCaches(engine, &m_compiledData->propertyCaches);
+}
+
+static bool addTypeReferenceChecksumsToHash(const QList<QQmlTypeData::TypeReference> &typeRefs, QCryptographicHash *hash, QQmlEngine *engine)
+{
+ 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());
+ bool ok = false;
+ hash->addData(propertyCache->checksum(&ok));
+ if (!ok)
+ return false;
+ }
+ }
+ return true;
+}
+
+void QQmlTypeData::done()
+{
+ auto cleanup = qScopeGuard([this]{
+ m_document.reset();
+ m_typeReferences.clear();
+ if (isError())
+ m_compiledData = nullptr;
+ });
+
+ if (isError())
+ return;
+
+ // Check all script dependencies for errors
+ for (int ii = 0; ii < m_scripts.count(); ++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.setDescription(QQmlTypeLoader::tr("Script %1 unavailable").arg(script.script->urlString()));
+ errors.prepend(error);
+ setError(errors);
+ return;
+ }
+ }
+
+ // Check all type dependencies for errors
+ for (auto it = m_resolvedTypes.constBegin(), end = m_resolvedTypes.constEnd(); it != end;
+ ++it) {
+ const TypeReference &type = *it;
+ Q_ASSERT(!type.typeData || type.typeData->isCompleteOrError());
+ 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);
+ return;
+ }
+ }
+
+ // Check all composite singleton type dependencies for errors
+ for (int ii = 0; ii < m_compositeSingletons.count(); ++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);
+ return;
+ }
+ }
+
+ QQmlRefPointer<QQmlTypeNameCache> typeNameCache;
+ QV4::ResolvedTypeReferenceMap resolvedTypeCache;
+ {
+ QQmlJS::DiagnosticMessage error = buildTypeResolutionCaches(&typeNameCache, &resolvedTypeCache);
+ if (error.isValid()) {
+ setError(error);
+ return;
+ }
+ }
+
+ QQmlEngine *const engine = typeLoader()->engine();
+
+ const auto dependencyHasher = [engine, &resolvedTypeCache, this]() {
+ QCryptographicHash hash(QCryptographicHash::Md5);
+ return (resolvedTypeCache.addToHash(&hash, engine)
+ && ::addTypeReferenceChecksumsToHash(m_compositeSingletons, &hash, engine))
+ ? 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()) {
+ // Compile component
+ compile(typeNameCache, &resolvedTypeCache, dependencyHasher);
+ } else {
+ createTypeAndPropertyCaches(typeNameCache, resolvedTypeCache);
+ }
+
+ if (isError())
+ return;
+
+ {
+ QQmlEnginePrivate *const enginePrivate = QQmlEnginePrivate::get(engine);
+ {
+ // Sanity check property bindings
+ QQmlPropertyValidator validator(enginePrivate, m_importCache, m_compiledData);
+ QVector<QQmlJS::DiagnosticMessage> errors = validator.validate();
+ if (!errors.isEmpty()) {
+ setError(errors);
+ return;
+ }
+ }
+
+ m_compiledData->finalizeCompositeType(enginePrivate);
+ }
+
+ {
+ QQmlType type = QQmlMetaType::qmlType(finalUrl(), true);
+ if (m_compiledData && m_compiledData->unitData()->flags & QV4::CompiledData::Unit::IsSingleton) {
+ if (!type.isValid()) {
+ QQmlError error;
+ error.setDescription(QQmlTypeLoader::tr("No matching type found, pragma Singleton files cannot be used by QQmlComponent."));
+ setError(error);
+ return;
+ } else if (!type.isCompositeSingleton()) {
+ QQmlError error;
+ error.setDescription(QQmlTypeLoader::tr("pragma Singleton used with a non composite singleton type %1").arg(type.qmlTypeName()));
+ setError(error);
+ return;
+ }
+ } else {
+ // If the type is CompositeSingleton but there was no pragma Singleton in the
+ // QML file, lets report an error.
+ if (type.isValid() && type.isCompositeSingleton()) {
+ QString typeName = type.qmlTypeName();
+ setError(QQmlTypeLoader::tr("qmldir defines type as singleton, but no pragma Singleton found in type %1.").arg(typeName));
+ return;
+ }
+ }
+ }
+
+ {
+ // Collect imported scripts
+ m_compiledData->dependentScripts.reserve(m_scripts.count());
+ for (int scriptIndex = 0; scriptIndex < m_scripts.count(); ++scriptIndex) {
+ const QQmlTypeData::ScriptReference &script = m_scripts.at(scriptIndex);
+
+ QStringRef qualifier(&script.qualifier);
+ QString enclosingNamespace;
+
+ const int lastDotIndex = qualifier.lastIndexOf(QLatin1Char('.'));
+ if (lastDotIndex != -1) {
+ enclosingNamespace = qualifier.left(lastDotIndex).toString();
+ qualifier = qualifier.mid(lastDotIndex+1);
+ }
+
+ m_compiledData->typeNameCache->add(qualifier.toString(), scriptIndex, enclosingNamespace);
+ QQmlRefPointer<QQmlScriptData> scriptData = script.script->scriptData();
+ m_compiledData->dependentScripts << scriptData;
+ }
+ }
+}
+
+void QQmlTypeData::completed()
+{
+ // Notify callbacks
+ while (!m_callbacks.isEmpty()) {
+ TypeDataCallback *callback = m_callbacks.takeFirst();
+ callback->typeDataReady(this);
+ }
+}
+
+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());
+
+ 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);
+
+ if (!implicitImportErrors.isEmpty()) {
+ setError(implicitImportErrors);
+ return false;
+ }
+
+ return true;
+}
+
+void QQmlTypeData::dataReceived(const SourceCodeData &data)
+{
+ m_backupSourceCode = data;
+
+ if (tryLoadFromDiskCache())
+ return;
+
+ if (isError())
+ return;
+
+ if (!m_backupSourceCode.exists() || m_backupSourceCode.isEmpty()) {
+ if (m_cachedUnitStatus == QQmlMetaType::CachedUnitLookupError::VersionMismatch)
+ setError(QQmlTypeLoader::tr("File was compiled ahead of time with an incompatible version of Qt and the original file cannot be found. Please recompile"));
+ else if (!m_backupSourceCode.exists())
+ setError(QQmlTypeLoader::tr("No such file or directory"));
+ else
+ setError(QQmlTypeLoader::tr("File is empty"));
+ return;
+ }
+
+ if (!loadFromSource())
+ return;
+
+ continueLoadFromIR();
+}
+
+void QQmlTypeData::initializeFromCachedUnit(const QV4::CompiledData::Unit *unit)
+{
+ m_document.reset(new QmlIR::Document(isDebugging()));
+ QQmlIRLoader loader(unit, m_document.data());
+ loader.load();
+ m_document->jsModule.fileName = urlString();
+ m_document->jsModule.finalUrl = finalUrlString();
+ m_document->javaScriptCompilationUnit = QV4::CompiledData::CompilationUnit(unit);
+ continueLoadFromIR();
+}
+
+bool QQmlTypeData::loadFromSource()
+{
+ m_document.reset(new QmlIR::Document(isDebugging()));
+ m_document->jsModule.sourceTimeStamp = m_backupSourceCode.sourceTimeStamp();
+ QQmlEngine *qmlEngine = typeLoader()->engine();
+ QmlIR::IRBuilder compiler(qmlEngine->handle()->illegalNames());
+
+ QString sourceError;
+ const QString source = m_backupSourceCode.readAll(&sourceError);
+ if (!sourceError.isEmpty()) {
+ setError(sourceError);
+ return false;
+ }
+
+ if (!compiler.generateFromQml(source, finalUrlString(), m_document.data())) {
+ QList<QQmlError> errors;
+ errors.reserve(compiler.errors.count());
+ for (const QQmlJS::DiagnosticMessage &msg : qAsConst(compiler.errors)) {
+ QQmlError e;
+ e.setUrl(url());
+ e.setLine(msg.line);
+ e.setColumn(msg.column);
+ e.setDescription(msg.message);
+ errors << e;
+ }
+ setError(errors);
+ return false;
+ }
+ return true;
+}
+
+void QQmlTypeData::restoreIR(QV4::CompiledData::CompilationUnit &&unit)
+{
+ m_document.reset(new QmlIR::Document(isDebugging()));
+ 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);
+ continueLoadFromIR();
+}
+
+void QQmlTypeData::continueLoadFromIR()
+{
+ m_typeReferences.collectFromObjects(m_document->objects.constBegin(), m_document->objects.constEnd());
+ 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
+ // qmldir (so we can't load it just in time).
+ if (!finalUrl().scheme().isEmpty()) {
+ QUrl qmldirUrl = finalUrl().resolved(QUrl(QLatin1String("qmldir")));
+ if (!QQmlImports::isLocal(qmldirUrl)) {
+ if (!loadImplicitImport())
+ return;
+ // This qmldir is for the implicit import
+ QQmlJS::MemoryPool *pool = m_document->jsParserEngine.pool();
+ auto implicitImport = pool->New<QV4::CompiledData::Import>();
+ implicitImport->uriIndex = m_document->registerString(QLatin1String("."));
+ implicitImport->qualifierIndex = 0; // empty string
+ implicitImport->majorVersion = -1;
+ implicitImport->minorVersion = -1;
+ QList<QQmlError> errors;
+
+ if (!fetchQmldir(qmldirUrl, implicitImport, 1, &errors)) {
+ setError(errors);
+ return;
+ }
+ }
+ }
+
+ QList<QQmlError> errors;
+
+ for (const QV4::CompiledData::Import *import : qAsConst(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);
+ return;
+ }
+ }
+}
+
+void QQmlTypeData::allDependenciesDone()
+{
+ QQmlTypeLoader::Blob::allDependenciesDone();
+
+ if (!m_typesResolved) {
+ // Check that all imports were resolved
+ QList<QQmlError> errors;
+ QHash<const QV4::CompiledData::Import *, int>::const_iterator it = m_unresolvedImports.constBegin(), end = m_unresolvedImports.constEnd();
+ for ( ; it != end; ++it) {
+ if (*it == 0) {
+ // This import was not resolved
+ for (auto keyIt = m_unresolvedImports.keyBegin(),
+ keyEnd = m_unresolvedImports.keyEnd();
+ keyIt != keyEnd; ++keyIt) {
+ const QV4::CompiledData::Import *import = *keyIt;
+ QQmlError error;
+ error.setDescription(QQmlTypeLoader::tr("module \"%1\" is not installed").arg(stringAt(import->uriIndex)));
+ error.setUrl(m_importCache.baseUrl());
+ error.setLine(import->location.line);
+ error.setColumn(import->location.column);
+ errors.prepend(error);
+ }
+ }
+ }
+ if (errors.size()) {
+ setError(errors);
+ return;
+ }
+
+ resolveTypes();
+ m_typesResolved = true;
+ }
+}
+
+void QQmlTypeData::downloadProgressChanged(qreal p)
+{
+ for (int ii = 0; ii < m_callbacks.count(); ++ii) {
+ TypeDataCallback *callback = m_callbacks.at(ii);
+ callback->typeDataProgress(this, p);
+ }
+}
+
+QString QQmlTypeData::stringAt(int index) const
+{
+ if (m_compiledData)
+ return m_compiledData->stringAt(index);
+ return m_document->jsGenerator.stringTable.stringForIndex(index);
+}
+
+void QQmlTypeData::compile(const QQmlRefPointer<QQmlTypeNameCache> &typeNameCache,
+ QV4::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);
+
+ QQmlEnginePrivate * const enginePrivate = QQmlEnginePrivate::get(typeLoader()->engine());
+ QQmlTypeCompiler compiler(enginePrivate, this, m_document.data(), typeNameCache, resolvedTypeCache, dependencyHasher);
+ m_compiledData = compiler.compile();
+ if (!m_compiledData) {
+ setError(compiler.compilationErrors());
+ return;
+ }
+
+ const bool trySaveToDisk = (!diskCacheDisabled() || diskCacheForced())
+ && !m_document->jsModule.debugMode && !typeRecompilation;
+ if (trySaveToDisk) {
+ QString errorString;
+ if (m_compiledData->saveToDisk(url(), &errorString)) {
+ QString error;
+ if (!m_compiledData->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;
+ }
+ }
+}
+
+void QQmlTypeData::resolveTypes()
+{
+ // Add any imported scripts to our resolved set
+ const auto resolvedScripts = m_importCache.resolvedScripts();
+ for (const QQmlImports::ScriptReference &script : resolvedScripts) {
+ QQmlRefPointer<QQmlScriptBlob> blob = typeLoader()->getScript(script.location);
+ addDependency(blob.data());
+
+ ScriptReference ref;
+ //ref.location = ...
+ if (!script.qualifier.isEmpty())
+ {
+ ref.qualifier = script.qualifier + QLatin1Char('.') + script.nameSpace;
+ // Add a reference to the enclosing namespace
+ m_namespaces.insert(script.qualifier);
+ } else {
+ ref.qualifier = script.nameSpace;
+ }
+
+ ref.script = blob;
+ m_scripts << ref;
+ }
+
+ // Lets handle resolved composite singleton types
+ const auto resolvedCompositeSingletons = m_importCache.resolvedCompositeSingletons();
+ for (const QQmlImports::CompositeSingletonReference &csRef : resolvedCompositeSingletons) {
+ TypeReference ref;
+ QString typeName;
+ if (!csRef.prefix.isEmpty()) {
+ typeName = csRef.prefix + QLatin1Char('.') + csRef.typeName;
+ // Add a reference to the enclosing namespace
+ m_namespaces.insert(csRef.prefix);
+ } else {
+ 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))
+ return;
+
+ if (ref.type.isCompositeSingleton()) {
+ ref.typeData = typeLoader()->getType(ref.type.sourceUrl());
+ if (ref.typeData->status() == QQmlDataBlob::ResolvingDependencies) {
+ // TODO: give an error message? If so, we should record and show the path of the cycle.
+ continue;
+ }
+ addDependency(ref.typeData.data());
+ ref.prefix = csRef.prefix;
+
+ m_compositeSingletons << ref;
+ }
+ }
+
+ for (QV4::CompiledData::TypeReferenceMap::ConstIterator unresolvedRef = m_typeReferences.constBegin(), end = m_typeReferences.constEnd();
+ unresolvedRef != end; ++unresolvedRef) {
+
+ TypeReference ref; // resolved reference
+
+ const bool reportErrors = unresolvedRef->errorWhenNotFound;
+
+ int majorVersion = -1;
+ int minorVersion = -1;
+
+ const QString name = stringAt(unresolvedRef.key());
+
+ if (!resolveType(name, majorVersion, minorVersion, ref, unresolvedRef->location.line,
+ unresolvedRef->location.column, reportErrors,
+ QQmlType::AnyRegistrationType) && reportErrors)
+ return;
+
+ if (ref.type.isComposite()) {
+ 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;
+
+ ref.needsCreation = unresolvedRef->needsCreation;
+
+ m_resolvedTypes.insert(unresolvedRef.key(), ref);
+ }
+
+ // ### this allows enums to work without explicit import or instantiation of the type
+ if (!m_implicitImportLoaded)
+ loadImplicitImport();
+}
+
+QQmlJS::DiagnosticMessage QQmlTypeData::buildTypeResolutionCaches(
+ QQmlRefPointer<QQmlTypeNameCache> *typeNameCache,
+ QV4::ResolvedTypeReferenceMap *resolvedTypeCache
+ ) const
+{
+ typeNameCache->adopt(new QQmlTypeNameCache(m_importCache));
+
+ for (const QString &ns: m_namespaces)
+ (*typeNameCache)->add(ns);
+
+ // Add any Composite Singletons that were used to the import cache
+ 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());
+
+ for (auto resolvedType = m_resolvedTypes.constBegin(), end = m_resolvedTypes.constEnd(); resolvedType != end; ++resolvedType) {
+ QScopedPointer<QV4::ResolvedTypeReference> ref(new 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());
+
+ if (resolvedType->needsCreation && !ref->type.isCreatable()) {
+ QString reason = ref->type.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);
+ }
+ }
+ ref->majorVersion = resolvedType->majorVersion;
+ ref->minorVersion = resolvedType->minorVersion;
+ ref->doDynamicTypeCheck();
+ resolvedTypeCache->insert(resolvedType.key(), ref.take());
+ }
+ QQmlJS::DiagnosticMessage noError;
+ return noError;
+}
+
+bool QQmlTypeData::resolveType(const QString &typeName, int &majorVersion, int &minorVersion,
+ TypeReference &ref, int lineNumber, int columnNumber,
+ bool reportErrors, QQmlType::RegistrationType registrationType)
+{
+ QQmlImportNamespace *typeNamespace = nullptr;
+ QList<QQmlError> errors;
+
+ bool typeFound = m_importCache.resolveType(typeName, &ref.type, &majorVersion, &minorVersion,
+ &typeNamespace, &errors, registrationType);
+ 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);
+ } else {
+ return false; //loadImplicitImport() hit an error, and called setError already
+ }
+ }
+
+ if ((!typeFound || typeNamespace) && reportErrors) {
+ // Known to not be a type:
+ // - known to be a namespace (Namespace {})
+ // - type with unknown namespace (UnknownNamespace.SomeType {})
+ QQmlError error;
+ if (typeNamespace) {
+ error.setDescription(QQmlTypeLoader::tr("Namespace %1 cannot be used as a type").arg(typeName));
+ } else {
+ if (errors.size()) {
+ error = errors.takeFirst();
+ } else {
+ // this should not be possible!
+ // 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.setDescription(QQmlTypeLoader::tr("%1 %2").arg(typeName).arg(error.description()));
+ }
+
+ if (lineNumber != -1)
+ error.setLine(lineNumber);
+ if (columnNumber != -1)
+ error.setColumn(columnNumber);
+
+ errors.prepend(error);
+ setError(errors);
+ return false;
+ }
+
+ return true;
+}
+
+void QQmlTypeData::scriptImported(const QQmlRefPointer<QQmlScriptBlob> &blob, const QV4::CompiledData::Location &location, const QString &qualifier, const QString &/*nameSpace*/)
+{
+ ScriptReference ref;
+ ref.script = blob;
+ ref.location = location;
+ ref.qualifier = qualifier;
+
+ m_scripts << ref;
+}
+
+QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmltypedata_p.h b/src/qml/qml/qqmltypedata_p.h
new file mode 100644
index 0000000000..e1d0c900ea
--- /dev/null
+++ b/src/qml/qml/qqmltypedata_p.h
@@ -0,0 +1,163 @@
+/****************************************************************************
+**
+** 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 QQMLTYPEDATA_P_H
+#define QQMLTYPEDATA_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/qqmltypeloader_p.h>
+#include <private/qv4executablecompilationunit_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class Q_AUTOTEST_EXPORT QQmlTypeData : public QQmlTypeLoader::Blob
+{
+ Q_DECLARE_TR_FUNCTIONS(QQmlTypeData)
+public:
+ struct TypeReference
+ {
+ TypeReference() : majorVersion(0), minorVersion(0), needsCreation(true) {}
+
+ QV4::CompiledData::Location location;
+ QQmlType type;
+ int majorVersion;
+ int minorVersion;
+ QQmlRefPointer<QQmlTypeData> typeData;
+ QString prefix; // used by CompositeSingleton types
+ QString qualifiedName() const;
+ bool needsCreation;
+ };
+
+ struct ScriptReference
+ {
+ QV4::CompiledData::Location location;
+ QString qualifier;
+ QQmlRefPointer<QQmlScriptBlob> script;
+ };
+
+private:
+ friend class QQmlTypeLoader;
+
+ QQmlTypeData(const QUrl &, QQmlTypeLoader *);
+
+public:
+ ~QQmlTypeData() override;
+
+ const QList<ScriptReference> &resolvedScripts() const;
+
+ QV4::ExecutableCompilationUnit *compilationUnit() const;
+
+ // Used by QQmlComponent to get notifications
+ struct TypeDataCallback {
+ virtual ~TypeDataCallback();
+ virtual void typeDataProgress(QQmlTypeData *, qreal) {}
+ virtual void typeDataReady(QQmlTypeData *) {}
+ };
+ void registerCallback(TypeDataCallback *);
+ void unregisterCallback(TypeDataCallback *);
+
+protected:
+ void done() override;
+ void completed() override;
+ void dataReceived(const SourceCodeData &) override;
+ void initializeFromCachedUnit(const QV4::CompiledData::Unit *unit) override;
+ void allDependenciesDone() override;
+ void downloadProgressChanged(qreal) override;
+
+ QString stringAt(int index) const override;
+
+private:
+ bool tryLoadFromDiskCache();
+ bool loadFromSource();
+ void restoreIR(QV4::CompiledData::CompilationUnit &&unit);
+ void continueLoadFromIR();
+ void resolveTypes();
+ QQmlJS::DiagnosticMessage buildTypeResolutionCaches(
+ QQmlRefPointer<QQmlTypeNameCache> *typeNameCache,
+ QV4::ResolvedTypeReferenceMap *resolvedTypeCache
+ ) const;
+ void compile(const QQmlRefPointer<QQmlTypeNameCache> &typeNameCache,
+ QV4::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,
+ 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;
+
+
+ SourceCodeData m_backupSourceCode; // used when cache verification fails.
+ QScopedPointer<QmlIR::Document> m_document;
+ QV4::CompiledData::TypeReferenceMap m_typeReferences;
+
+ QList<ScriptReference> m_scripts;
+
+ QSet<QString> m_namespaces;
+ QList<TypeReference> m_compositeSingletons;
+
+ // map from name index to resolved type
+ // While this could be a hash, a map is chosen here to provide a stable
+ // order, which is used to calculating a check-sum on dependent meta-objects.
+ QMap<int, TypeReference> m_resolvedTypes;
+ bool m_typesResolved:1;
+
+ QQmlRefPointer<QV4::ExecutableCompilationUnit> m_compiledData;
+
+ QList<TypeDataCallback *> m_callbacks;
+
+ bool m_implicitImportLoaded;
+ bool loadImplicitImport();
+};
+
+QT_END_NAMESPACE
+
+#endif // QQMLTYPEDATA_P_H
diff --git a/src/qml/qml/qqmltypeloader.cpp b/src/qml/qml/qqmltypeloader.cpp
index 0bfdbdd2fa..4b6c09769a 100644
--- a/src/qml/qml/qqmltypeloader.cpp
+++ b/src/qml/qml/qqmltypeloader.cpp
@@ -37,77 +37,37 @@
**
****************************************************************************/
-#include "qqmltypeloader_p.h"
-#include "qqmlabstracturlinterceptor.h"
-#include "qqmlexpression_p.h"
-
-#include <private/qqmlengine_p.h>
-#include <private/qqmlglobal_p.h>
-#include <private/qqmlthread_p.h>
-#include <private/qv4codegen_p.h>
-#include <private/qqmlcomponent_p.h>
+#include <private/qqmltypeloader_p.h>
+
+#include <private/qqmldirdata_p.h>
#include <private/qqmlprofiler_p.h>
-#include <private/qqmltypecompiler_p.h>
-#include <private/qqmlpropertyvalidator_p.h>
-#include <private/qqmlpropertycachecreator_p.h>
-#include <private/qv4module_p.h>
-#include <private/qqmlirloader_p.h>
+#include <private/qqmlscriptblob_p.h>
+#include <private/qqmltypedata_p.h>
+#include <private/qqmltypeloaderqmldircontent_p.h>
+#include <private/qqmltypeloaderthread_p.h>
+
+#include <QtQml/qqmlabstracturlinterceptor.h>
+#include <QtQml/qqmlengine.h>
+#include <QtQml/qqmlextensioninterface.h>
+#include <QtQml/qqmlfile.h>
#include <QtCore/qdir.h>
+#include <QtCore/qdiriterator.h>
#include <QtCore/qfile.h>
-#include <QtCore/qdatetime.h>
-#include <QtCore/qdebug.h>
-#include <QtCore/qmutex.h>
#include <QtCore/qthread.h>
-#include <QtQml/qqmlfile.h>
-#include <QtCore/qdiriterator.h>
-#include <QtQml/qqmlcomponent.h>
-#include <QtCore/qwaitcondition.h>
-#include <QtCore/qloggingcategory.h>
-#include <QtQml/qqmlextensioninterface.h>
-#include <QtCore/qcryptographichash.h>
-#include <QtCore/qscopeguard.h>
#include <functional>
-#if defined (Q_OS_UNIX)
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unistd.h>
-#endif
-
-#if defined (QT_LINUXBASE)
-// LSB doesn't declare NAME_MAX. Use SYMLINK_MAX instead, which seems to
-// always be identical to NAME_MAX
-#ifndef NAME_MAX
-# define NAME_MAX _POSIX_SYMLINK_MAX
-#endif
-
-#endif
-
// #define DATABLOB_DEBUG
-
#ifdef DATABLOB_DEBUG
-
-#define ASSERT_MAINTHREAD() do { if (m_thread->isThisThread()) qFatal("QQmlTypeLoader: Caller not in main thread"); } while (false)
#define ASSERT_LOADTHREAD() do { if (!m_thread->isThisThread()) qFatal("QQmlTypeLoader: Caller not in load thread"); } while (false)
-#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
-
-#define ASSERT_MAINTHREAD()
#define ASSERT_LOADTHREAD()
-#define ASSERT_CALLBACK()
-
#endif
-DEFINE_BOOL_CONFIG_OPTION(dumpErrors, QML_DUMP_ERRORS);
DEFINE_BOOL_CONFIG_OPTION(disableDiskCache, QML_DISABLE_DISK_CACHE);
DEFINE_BOOL_CONFIG_OPTION(forceDiskCache, QML_FORCE_DISK_CACHE);
-Q_DECLARE_LOGGING_CATEGORY(DBG_DISK_CACHE)
-Q_LOGGING_CATEGORY(DBG_DISK_CACHE, "qt.qml.diskcache")
-
QT_BEGIN_NAMESPACE
namespace {
@@ -121,829 +81,6 @@ namespace {
};
}
-#if QT_CONFIG(qml_network)
-// This is a lame object that we need to ensure that slots connected to
-// QNetworkReply get called in the correct thread (the loader thread).
-// As QQmlTypeLoader lives in the main thread, and we can't use
-// Qt::DirectConnection connections from a QNetworkReply (because then
-// sender() wont work), we need to insert this object in the middle.
-class QQmlTypeLoaderNetworkReplyProxy : public QObject
-{
- Q_OBJECT
-public:
- QQmlTypeLoaderNetworkReplyProxy(QQmlTypeLoader *l);
-
-public slots:
- void finished();
- void downloadProgress(qint64, qint64);
- void manualFinished(QNetworkReply*);
-
-private:
- QQmlTypeLoader *l;
-};
-#endif // qml_network
-
-class QQmlTypeLoaderThread : public QQmlThread
-{
- typedef QQmlTypeLoaderThread This;
-
-public:
- QQmlTypeLoaderThread(QQmlTypeLoader *loader);
-#if QT_CONFIG(qml_network)
- 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 initializeEngine(QQmlExtensionInterface *, 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 initializeEngineMain(QQmlExtensionInterface *iface, const char *uri);
-
- QQmlTypeLoader *m_loader;
-#if QT_CONFIG(qml_network)
- mutable QNetworkAccessManager *m_networkAccessManager;
- mutable QQmlTypeLoaderNetworkReplyProxy *m_networkReplyProxy;
-#endif // qml_network
-};
-
-#if QT_CONFIG(qml_network)
-QQmlTypeLoaderNetworkReplyProxy::QQmlTypeLoaderNetworkReplyProxy(QQmlTypeLoader *l)
-: l(l)
-{
-}
-
-void QQmlTypeLoaderNetworkReplyProxy::finished()
-{
- Q_ASSERT(sender());
- Q_ASSERT(qobject_cast<QNetworkReply *>(sender()));
- QNetworkReply *reply = static_cast<QNetworkReply *>(sender());
- l->networkReplyFinished(reply);
-}
-
-void QQmlTypeLoaderNetworkReplyProxy::downloadProgress(qint64 bytesReceived, qint64 bytesTotal)
-{
- Q_ASSERT(sender());
- Q_ASSERT(qobject_cast<QNetworkReply *>(sender()));
- QNetworkReply *reply = static_cast<QNetworkReply *>(sender());
- l->networkReplyProgress(reply, bytesReceived, bytesTotal);
-}
-
-// This function is for when you want to shortcut the signals and call directly
-void QQmlTypeLoaderNetworkReplyProxy::manualFinished(QNetworkReply *reply)
-{
- qint64 replySize = reply->size();
- l->networkReplyProgress(reply, replySize, replySize);
- l->networkReplyFinished(reply);
-}
-#endif // qml_network
-
-/*!
-\class QQmlDataBlob
-\brief The QQmlDataBlob encapsulates a data request that can be issued to a QQmlTypeLoader.
-\internal
-
-QQmlDataBlob's are loaded by a QQmlTypeLoader. The user creates the QQmlDataBlob
-and then calls QQmlTypeLoader::load() or QQmlTypeLoader::loadWithStaticData() to load it.
-The QQmlTypeLoader invokes callbacks on the QQmlDataBlob as data becomes available.
-*/
-
-/*!
-\enum QQmlDataBlob::Status
-
-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 continueing. 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
-*/
-
-/*!
-\enum QQmlDataBlob::Type
-
-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
-*/
-
-/*!
-Create a new QQmlDataBlob for \a url and of the provided \a type.
-*/
-QQmlDataBlob::QQmlDataBlob(const QUrl &url, Type type, QQmlTypeLoader *manager)
-: m_typeLoader(manager), m_type(type), m_url(url), m_finalUrl(url), m_redirectCount(0),
- 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);
-}
-
-/*! \internal */
-QQmlDataBlob::~QQmlDataBlob()
-{
- Q_ASSERT(m_waitingOnMe.isEmpty());
-
- cancelAllWaitingFor();
-}
-
-/*!
- Must be called before loading can occur.
-*/
-void QQmlDataBlob::startLoading()
-{
- Q_ASSERT(status() == QQmlDataBlob::Null);
- m_data.setStatus(QQmlDataBlob::Loading);
-}
-
-/*!
-Returns the type provided to the constructor.
-*/
-QQmlDataBlob::Type QQmlDataBlob::type() const
-{
- return m_type;
-}
-
-/*!
-Returns the blob's status.
-*/
-QQmlDataBlob::Status QQmlDataBlob::status() const
-{
- return m_data.status();
-}
-
-/*!
-Returns true if the status is Null.
-*/
-bool QQmlDataBlob::isNull() const
-{
- return status() == Null;
-}
-
-/*!
-Returns true if the status is Loading.
-*/
-bool QQmlDataBlob::isLoading() const
-{
- return status() == Loading;
-}
-
-/*!
-Returns true if the status is WaitingForDependencies.
-*/
-bool QQmlDataBlob::isWaiting() const
-{
- return status() == WaitingForDependencies ||
- status() == ResolvingDependencies;
-}
-
-/*!
-Returns true if the status is Complete.
-*/
-bool QQmlDataBlob::isComplete() const
-{
- return status() == Complete;
-}
-
-/*!
-Returns true if the status is Error.
-*/
-bool QQmlDataBlob::isError() const
-{
- return status() == Error;
-}
-
-/*!
-Returns true if the status is Complete or Error.
-*/
-bool QQmlDataBlob::isCompleteOrError() const
-{
- Status s = status();
- return s == Error || s == Complete;
-}
-
-/*!
-Returns the data download progress from 0 to 1.
-*/
-qreal QQmlDataBlob::progress() const
-{
- quint8 p = m_data.progress();
- if (p == 0xFF) return 1.;
- else return qreal(p) / qreal(0xFF);
-}
-
-/*!
-Returns the physical url of the data. Initially this is the same as
-finalUrl(), but if a URL interceptor is set, it will work on this URL
-and leave finalUrl() alone.
-
-\sa finalUrl()
-*/
-QUrl QQmlDataBlob::url() const
-{
- return m_url;
-}
-
-QString QQmlDataBlob::urlString() const
-{
- if (m_urlString.isEmpty())
- m_urlString = m_url.toString();
-
- return m_urlString;
-}
-
-/*!
-Returns the logical URL to be used for resolving further URLs referred to in
-the code.
-
-This is the blob url passed to the constructor. If a URL interceptor rewrites
-the URL, this one stays the same. If a network redirect happens while fetching
-the data, this url is updated to reflect the new location. Therefore, if both
-an interception and a redirection happen, the final url will indirectly
-incorporate the result of the interception, potentially breaking further
-lookups.
-
-\sa url()
-*/
-QUrl QQmlDataBlob::finalUrl() const
-{
- return m_finalUrl;
-}
-
-/*!
-Returns the finalUrl() as a string.
-*/
-QString QQmlDataBlob::finalUrlString() const
-{
- if (m_finalUrlString.isEmpty())
- m_finalUrlString = m_finalUrl.toString();
-
- return m_finalUrlString;
-}
-
-/*!
-Return the errors on this blob.
-
-May only be called from the load thread, or after the blob isCompleteOrError().
-*/
-QList<QQmlError> QQmlDataBlob::errors() const
-{
- Q_ASSERT(isCompleteOrError() || (m_typeLoader && m_typeLoader->m_thread->isThisThread()));
- return m_errors;
-}
-
-/*!
-Mark this blob as having \a errors.
-
-All outstanding dependencies will be cancelled. Requests to add new dependencies
-will be ignored. Entry into the Error state is irreversable.
-
-The setError() method may only be called from within a QQmlDataBlob callback.
-*/
-void QQmlDataBlob::setError(const QQmlError &errors)
-{
- ASSERT_CALLBACK();
-
- QList<QQmlError> l;
- l << errors;
- setError(l);
-}
-
-/*!
-\overload
-*/
-void QQmlDataBlob::setError(const QList<QQmlError> &errors)
-{
- ASSERT_CALLBACK();
-
- Q_ASSERT(status() != Error);
- Q_ASSERT(m_errors.isEmpty());
-
- m_errors = errors; // Must be set before the m_data fence
- m_data.setStatus(Error);
-
- if (dumpErrors()) {
- qWarning().nospace() << "Errors for " << urlString();
- for (int ii = 0; ii < errors.count(); ++ii)
- qWarning().nospace() << " " << qPrintable(errors.at(ii).toString());
- }
- cancelAllWaitingFor();
-
- if (!m_inCallback)
- tryDone();
-}
-
-void QQmlDataBlob::setError(const QQmlJS::DiagnosticMessage &error)
-{
- QQmlError e;
- e.setColumn(error.column);
- e.setLine(error.line);
- 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;
- e.setDescription(description);
- e.setUrl(url());
- setError(e);
-}
-
-/*!
-Wait for \a blob to become complete or to error. If \a blob is already
-complete or in error, or this blob is already complete, this has no effect.
-
-The setError() method may only be called from within a QQmlDataBlob callback.
-*/
-void QQmlDataBlob::addDependency(QQmlDataBlob *blob)
-{
- ASSERT_CALLBACK();
-
- Q_ASSERT(status() != Null);
-
- if (!blob ||
- blob->status() == Error || blob->status() == Complete ||
- status() == Error || status() == Complete || m_isDone)
- return;
-
- for (auto existingDep: qAsConst(m_waitingFor))
- if (existingDep.data() == blob)
- return;
-
- m_data.setStatus(WaitingForDependencies);
-
- m_waitingFor.append(blob);
- blob->m_waitingOnMe.append(this);
-}
-
-/*!
-\fn void QQmlDataBlob::dataReceived(const Data &data)
-
-Invoked when data for the blob is received. Implementors should use this callback
-to determine a blob's dependencies. Within this callback you may call setError()
-or addDependency().
-*/
-
-/*!
-Invoked once data has either been received or a network error occurred, and all
-dependencies are complete.
-
-You can set an error in this method, but you cannot add new dependencies. Implementors
-should use this callback to finalize processing of data.
-
-The default implementation does nothing.
-
-XXX Rename processData() or some such to avoid confusion between done() (processing thread)
-and completed() (main thread)
-*/
-void QQmlDataBlob::done()
-{
-}
-
-#if QT_CONFIG(qml_network)
-/*!
-Invoked if there is a network error while fetching this blob.
-
-The default implementation sets an appropriate QQmlError.
-*/
-void QQmlDataBlob::networkError(QNetworkReply::NetworkError networkError)
-{
- Q_UNUSED(networkError);
-
- QQmlError error;
- error.setUrl(m_url);
-
- const char *errorString = nullptr;
- switch (networkError) {
- default:
- errorString = "Network error";
- break;
- case QNetworkReply::ConnectionRefusedError:
- errorString = "Connection refused";
- break;
- case QNetworkReply::RemoteHostClosedError:
- errorString = "Remote host closed the connection";
- break;
- case QNetworkReply::HostNotFoundError:
- errorString = "Host not found";
- break;
- case QNetworkReply::TimeoutError:
- errorString = "Timeout";
- break;
- case QNetworkReply::ProxyConnectionRefusedError:
- case QNetworkReply::ProxyConnectionClosedError:
- case QNetworkReply::ProxyNotFoundError:
- case QNetworkReply::ProxyTimeoutError:
- case QNetworkReply::ProxyAuthenticationRequiredError:
- case QNetworkReply::UnknownProxyError:
- errorString = "Proxy error";
- break;
- case QNetworkReply::ContentAccessDenied:
- errorString = "Access denied";
- break;
- case QNetworkReply::ContentNotFoundError:
- errorString = "File not found";
- break;
- case QNetworkReply::AuthenticationRequiredError:
- errorString = "Authentication required";
- break;
- };
-
- error.setDescription(QLatin1String(errorString));
-
- setError(error);
-}
-#endif // qml_network
-
-/*!
-Called if \a blob, which was previously waited for, has an error.
-
-The default implementation does nothing.
-*/
-void QQmlDataBlob::dependencyError(QQmlDataBlob *blob)
-{
- Q_UNUSED(blob);
-}
-
-/*!
-Called if \a blob, which was previously waited for, has completed.
-
-The default implementation does nothing.
-*/
-void QQmlDataBlob::dependencyComplete(QQmlDataBlob *blob)
-{
- Q_UNUSED(blob);
-}
-
-/*!
-Called when all blobs waited for have completed. This occurs regardless of
-whether they are in error, or complete state.
-
-The default implementation does nothing.
-*/
-void QQmlDataBlob::allDependenciesDone()
-{
- m_data.setStatus(QQmlDataBlob::ResolvingDependencies);
-}
-
-/*!
-Called when the download progress of this blob changes. \a progress goes
-from 0 to 1.
-
-This callback is only invoked if an asynchronous load for this blob is
-made. An asynchronous load is one in which the Asynchronous mode is
-specified explicitly, or one that is implicitly delayed due to a network
-operation.
-
-The default implementation does nothing.
-*/
-void QQmlDataBlob::downloadProgressChanged(qreal progress)
-{
- Q_UNUSED(progress);
-}
-
-/*!
-Invoked on the main thread sometime after done() was called on the load thread.
-
-You cannot modify the blobs state at all in this callback and cannot depend on the
-order or timeliness of these callbacks. Implementors should use this callback to notify
-dependencies on the main thread that the blob is done and not a lot else.
-
-This callback is only invoked if an asynchronous load for this blob is
-made. An asynchronous load is one in which the Asynchronous mode is
-specified explicitly, or one that is implicitly delayed due to a network
-operation.
-
-The default implementation does nothing.
-*/
-void QQmlDataBlob::completed()
-{
-}
-
-
-void QQmlDataBlob::tryDone()
-{
- if (status() != Loading && m_waitingFor.isEmpty() && !m_isDone) {
- m_isDone = true;
- addref();
-
-#ifdef DATABLOB_DEBUG
- qWarning("QQmlDataBlob::done() %s", qPrintable(urlString()));
-#endif
- done();
-
- if (status() != Error)
- m_data.setStatus(Complete);
-
- notifyAllWaitingOnMe();
-
- // Locking is not required here, as anyone expecting callbacks must
- // already be protected against the blob being completed (as set above);
-#ifdef DATABLOB_DEBUG
- qWarning("QQmlDataBlob: Dispatching completed");
-#endif
- m_typeLoader->m_thread->callCompleted(this);
-
- release();
- }
-}
-
-void QQmlDataBlob::cancelAllWaitingFor()
-{
- while (m_waitingFor.count()) {
- QQmlRefPointer<QQmlDataBlob> blob = m_waitingFor.takeLast();
-
- Q_ASSERT(blob->m_waitingOnMe.contains(this));
-
- blob->m_waitingOnMe.removeOne(this);
- }
-}
-
-void QQmlDataBlob::notifyAllWaitingOnMe()
-{
- while (m_waitingOnMe.count()) {
- QQmlDataBlob *blob = m_waitingOnMe.takeLast();
-
- Q_ASSERT(std::any_of(blob->m_waitingFor.constBegin(), blob->m_waitingFor.constEnd(),
- [this](const QQmlRefPointer<QQmlDataBlob> &waiting) { return waiting.data() == this; }));
-
- blob->notifyComplete(this);
- }
-}
-
-void QQmlDataBlob::notifyComplete(QQmlDataBlob *blob)
-{
- Q_ASSERT(blob->status() == Error || blob->status() == Complete);
- QQmlCompilingProfiler prof(typeLoader()->profiler(), blob);
-
- m_inCallback = true;
-
- QQmlRefPointer<QQmlDataBlob> blobRef;
- for (int i = 0; i < m_waitingFor.count(); ++i) {
- if (m_waitingFor.at(i).data() == blob) {
- blobRef = m_waitingFor.takeAt(i);
- break;
- }
- }
- Q_ASSERT(blobRef);
-
- if (blob->status() == Error) {
- dependencyError(blob);
- } else if (blob->status() == Complete) {
- dependencyComplete(blob);
- }
-
- if (!isError() && m_waitingFor.isEmpty())
- allDependenciesDone();
-
- m_inCallback = false;
-
- tryDone();
-}
-
-#define TD_STATUS_MASK 0x0000FFFF
-#define TD_STATUS_SHIFT 0
-#define TD_PROGRESS_MASK 0x00FF0000
-#define TD_PROGRESS_SHIFT 16
-#define TD_ASYNC_MASK 0x80000000
-
-QQmlDataBlob::ThreadData::ThreadData()
-: _p(0)
-{
-}
-
-QQmlDataBlob::Status QQmlDataBlob::ThreadData::status() const
-{
- return QQmlDataBlob::Status((_p.loadRelaxed() & TD_STATUS_MASK) >> TD_STATUS_SHIFT);
-}
-
-void QQmlDataBlob::ThreadData::setStatus(QQmlDataBlob::Status status)
-{
- while (true) {
- int d = _p.loadRelaxed();
- int nd = (d & ~TD_STATUS_MASK) | ((status << TD_STATUS_SHIFT) & TD_STATUS_MASK);
- if (d == nd || _p.testAndSetOrdered(d, nd)) return;
- }
-}
-
-bool QQmlDataBlob::ThreadData::isAsync() const
-{
- return _p.loadRelaxed() & TD_ASYNC_MASK;
-}
-
-void QQmlDataBlob::ThreadData::setIsAsync(bool v)
-{
- while (true) {
- int d = _p.loadRelaxed();
- int nd = (d & ~TD_ASYNC_MASK) | (v?TD_ASYNC_MASK:0);
- if (d == nd || _p.testAndSetOrdered(d, nd)) return;
- }
-}
-
-quint8 QQmlDataBlob::ThreadData::progress() const
-{
- return quint8((_p.loadRelaxed() & TD_PROGRESS_MASK) >> TD_PROGRESS_SHIFT);
-}
-
-void QQmlDataBlob::ThreadData::setProgress(quint8 v)
-{
- while (true) {
- int d = _p.loadRelaxed();
- int nd = (d & ~TD_PROGRESS_MASK) | ((v << TD_PROGRESS_SHIFT) & TD_PROGRESS_MASK);
- if (d == nd || _p.testAndSetOrdered(d, nd)) return;
- }
-}
-
-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();
-}
-
-#if QT_CONFIG(qml_network)
-QNetworkAccessManager *QQmlTypeLoaderThread::networkAccessManager() const
-{
- Q_ASSERT(isThisThread());
- if (!m_networkAccessManager) {
- m_networkAccessManager = QQmlEnginePrivate::get(m_loader->engine())->createNetworkAccessManager(nullptr);
- m_networkReplyProxy = new QQmlTypeLoaderNetworkReplyProxy(m_loader);
- }
-
- return m_networkAccessManager;
-}
-
-QQmlTypeLoaderNetworkReplyProxy *QQmlTypeLoaderThread::networkReplyProxy() const
-{
- Q_ASSERT(isThisThread());
- Q_ASSERT(m_networkReplyProxy); // Must call networkAccessManager() first
- return m_networkReplyProxy;
-}
-#endif // qml_network
-
-void QQmlTypeLoaderThread::load(QQmlDataBlob *b)
-{
- b->addref();
- callMethodInThread(&This::loadThread, b);
-}
-
-void QQmlTypeLoaderThread::loadAsync(QQmlDataBlob *b)
-{
- b->addref();
- postMethodToThread(&This::loadThread, b);
-}
-
-void QQmlTypeLoaderThread::loadWithStaticData(QQmlDataBlob *b, const QByteArray &d)
-{
- b->addref();
- callMethodInThread(&This::loadWithStaticDataThread, b, d);
-}
-
-void QQmlTypeLoaderThread::loadWithStaticDataAsync(QQmlDataBlob *b, const QByteArray &d)
-{
- b->addref();
- postMethodToThread(&This::loadWithStaticDataThread, b, d);
-}
-
-void QQmlTypeLoaderThread::loadWithCachedUnit(QQmlDataBlob *b, const QV4::CompiledData::Unit *unit)
-{
- b->addref();
- callMethodInThread(&This::loadWithCachedUnitThread, b, unit);
-}
-
-void QQmlTypeLoaderThread::loadWithCachedUnitAsync(QQmlDataBlob *b, const QV4::CompiledData::Unit *unit)
-{
- b->addref();
- postMethodToThread(&This::loadWithCachedUnitThread, b, unit);
-}
-
-void QQmlTypeLoaderThread::callCompleted(QQmlDataBlob *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)
-{
- 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,
- const char *uri)
-{
- callMethodInMain(&This::initializeEngineMain, 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)
-{
- m_loader->loadThread(b);
- b->release();
-}
-
-void QQmlTypeLoaderThread::loadWithStaticDataThread(QQmlDataBlob *b, const QByteArray &d)
-{
- m_loader->loadWithStaticDataThread(b, d);
- b->release();
-}
-
-void QQmlTypeLoaderThread::loadWithCachedUnitThread(QQmlDataBlob *b, const QV4::CompiledData::Unit *unit)
-{
- m_loader->loadWithCachedUnitThread(b, unit);
- b->release();
-}
-
-void QQmlTypeLoaderThread::callCompletedMain(QQmlDataBlob *b)
-{
-#ifdef DATABLOB_DEBUG
- qWarning("QQmlTypeLoaderThread: %s completed() callback", qPrintable(b->urlString()));
-#endif
- b->completed();
- b->release();
-}
-
-void QQmlTypeLoaderThread::callDownloadProgressChangedMain(QQmlDataBlob *b, qreal p)
-{
-#ifdef DATABLOB_DEBUG
- qWarning("QQmlTypeLoaderThread: %s downloadProgressChanged(%f) callback",
- qPrintable(b->urlString()), p);
-#endif
- b->downloadProgressChanged(p);
- b->release();
-}
-
-void QQmlTypeLoaderThread::initializeEngineMain(QQmlExtensionInterface *iface,
- const char *uri)
-{
- Q_ASSERT(m_loader->engine()->thread() == QThread::currentThread());
- iface->initializeEngine(m_loader->engine(), uri);
-}
-
/*!
\class QQmlTypeLoader
\brief The QQmlTypeLoader class abstracts loading files and their dependencies over the network.
@@ -1488,7 +625,11 @@ bool QQmlTypeLoader::Blob::addImport(const QV4::CompiledData::Import *import, QL
bool incomplete = false;
- QUrl qmldirUrl = finalUrl().resolved(QUrl(importUri + QLatin1String("/qmldir")));
+ QUrl importUrl(importUri);
+ 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;
@@ -1532,6 +673,16 @@ bool QQmlTypeLoader::Blob::isDebugging() const
return typeLoader()->engine()->handle()->debugger() != nullptr;
}
+bool QQmlTypeLoader::Blob::diskCacheDisabled()
+{
+ return disableDiskCache();
+}
+
+bool QQmlTypeLoader::Blob::diskCacheForced()
+{
+ return forceDiskCache();
+}
+
bool QQmlTypeLoader::Blob::qmldirDataAvailable(const QQmlRefPointer<QQmlQmldirData> &data, QList<QQmlError> *errors)
{
bool resolve = true;
@@ -1564,77 +715,6 @@ bool QQmlTypeLoader::Blob::qmldirDataAvailable(const QQmlRefPointer<QQmlQmldirDa
return true;
}
-
-QQmlTypeLoaderQmldirContent::QQmlTypeLoaderQmldirContent()
-{
-}
-
-bool QQmlTypeLoaderQmldirContent::hasError() const
-{
- return m_parser.hasError();
-}
-
-QList<QQmlError> QQmlTypeLoaderQmldirContent::errors(const QString &uri) const
-{
- QList<QQmlError> errors;
- const QUrl url(uri);
- for (const auto parseError : m_parser.errors(uri)) {
- QQmlError error;
- error.setUrl(url);
- error.setLine(parseError.line);
- error.setColumn(parseError.column);
- error.setDescription(parseError.message);
- errors.append(error);
- }
- return errors;
-}
-
-QString QQmlTypeLoaderQmldirContent::typeNamespace() const
-{
- return m_parser.typeNamespace();
-}
-
-void QQmlTypeLoaderQmldirContent::setContent(const QString &location, const QString &content)
-{
- m_hasContent = true;
- m_location = location;
- m_parser.parse(content);
-}
-
-void QQmlTypeLoaderQmldirContent::setError(const QQmlError &error)
-{
- QQmlJS::DiagnosticMessage parseError;
- parseError.line = error.line();
- parseError.column = 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();
-}
-
-QString QQmlTypeLoaderQmldirContent::pluginLocation() const
-{
- return m_location;
-}
-
-bool QQmlTypeLoaderQmldirContent::designerSupported() const
-{
- return m_parser.designerSupported();
-}
-
/*!
Constructs a new type loader that uses the given \a engine.
*/
@@ -1788,17 +868,6 @@ QQmlRefPointer<QQmlQmldirData> QQmlTypeLoader::getQmldir(const QUrl &url)
return qmldirData;
}
-// #### 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;
-}
-
/*!
Returns the absolute filename of path via a directory cache.
Returns a empty string if the path does not exist.
@@ -2109,1221 +1178,4 @@ bool QQmlTypeLoader::isScriptLoaded(const QUrl &url) const
return m_scriptCache.contains(url);
}
-QQmlTypeData::TypeDataCallback::~TypeDataCallback()
-{
-}
-
-QString QQmlTypeData::TypeReference::qualifiedName() const
-{
- QString result;
- if (!prefix.isEmpty()) {
- result = prefix + QLatin1Char('.');
- }
- result.append(type.qmlTypeName());
- return result;
-}
-
-QQmlTypeData::QQmlTypeData(const QUrl &url, QQmlTypeLoader *manager)
-: QQmlTypeLoader::Blob(url, QmlFile, manager),
- m_typesResolved(false), m_implicitImportLoaded(false)
-{
-
-}
-
-QQmlTypeData::~QQmlTypeData()
-{
- m_scripts.clear();
- m_compositeSingletons.clear();
- m_resolvedTypes.clear();
-}
-
-const QList<QQmlTypeData::ScriptReference> &QQmlTypeData::resolvedScripts() const
-{
- return m_scripts;
-}
-
-QV4::ExecutableCompilationUnit *QQmlTypeData::compilationUnit() const
-{
- return m_compiledData.data();
-}
-
-void QQmlTypeData::registerCallback(TypeDataCallback *callback)
-{
- Q_ASSERT(!m_callbacks.contains(callback));
- m_callbacks.append(callback);
-}
-
-void QQmlTypeData::unregisterCallback(TypeDataCallback *callback)
-{
- Q_ASSERT(m_callbacks.contains(callback));
- m_callbacks.removeOne(callback);
- Q_ASSERT(!m_callbacks.contains(callback));
-}
-
-bool QQmlTypeData::tryLoadFromDiskCache()
-{
- if (disableDiskCache() && !forceDiskCache())
- return false;
-
- if (isDebugging())
- return false;
-
- QV4::ExecutionEngine *v4 = typeLoader()->engine()->handle();
- if (!v4)
- return false;
-
- QQmlRefPointer<QV4::ExecutableCompilationUnit> unit = QV4::ExecutableCompilationUnit::create();
- {
- QString error;
- if (!unit->loadFromDisk(url(), m_backupSourceCode.sourceTimeStamp(), &error)) {
- qCDebug(DBG_DISK_CACHE) << "Error loading" << urlString() << "from disk cache:" << error;
- return false;
- }
- }
-
- if (unit->unitData()->flags & QV4::CompiledData::Unit::PendingTypeCompilation) {
- restoreIR(std::move(*unit));
- return true;
- }
-
- m_compiledData = unit;
-
- for (int i = 0, count = m_compiledData->objectCount(); i < count; ++i)
- m_typeReferences.collectFromObject(m_compiledData->objectAt(i));
-
- 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
- // qmldir (so we can't load it just in time).
- if (!finalUrl().scheme().isEmpty()) {
- QUrl qmldirUrl = finalUrl().resolved(QUrl(QLatin1String("qmldir")));
- if (!QQmlImports::isLocal(qmldirUrl)) {
- if (!loadImplicitImport())
- return false;
-
- // find the implicit import
- for (quint32 i = 0, count = m_compiledData->importCount(); i < count; ++i) {
- 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) {
- QList<QQmlError> errors;
- if (!fetchQmldir(qmldirUrl, import, 1, &errors)) {
- setError(errors);
- return false;
- }
- break;
- }
- }
- }
- }
-
- 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)) {
- 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);
- return false;
- }
- }
-
- return true;
-}
-
-void QQmlTypeData::createTypeAndPropertyCaches(
- const QQmlRefPointer<QQmlTypeNameCache> &typeNameCache,
- const QV4::ResolvedTypeReferenceMap &resolvedTypeCache)
-{
- Q_ASSERT(m_compiledData);
- m_compiledData->typeNameCache = typeNameCache;
- m_compiledData->resolvedTypes = resolvedTypeCache;
-
- QQmlEnginePrivate * const engine = QQmlEnginePrivate::get(typeLoader()->engine());
-
- QQmlPendingGroupPropertyBindings pendingGroupPropertyBindings;
-
- {
- QQmlPropertyCacheCreator<QV4::ExecutableCompilationUnit> propertyCacheCreator(
- &m_compiledData->propertyCaches, &pendingGroupPropertyBindings, engine,
- m_compiledData.data(), &m_importCache);
- QQmlJS::DiagnosticMessage error = propertyCacheCreator.buildMetaObjects();
- if (error.isValid()) {
- setError(error);
- return;
- }
- }
-
- QQmlPropertyCacheAliasCreator<QV4::ExecutableCompilationUnit> aliasCreator(
- &m_compiledData->propertyCaches, m_compiledData.data());
- aliasCreator.appendAliasPropertiesToMetaObjects();
-
- pendingGroupPropertyBindings.resolveMissingPropertyCaches(engine, &m_compiledData->propertyCaches);
-}
-
-static bool addTypeReferenceChecksumsToHash(const QList<QQmlTypeData::TypeReference> &typeRefs, QCryptographicHash *hash, QQmlEngine *engine)
-{
- 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());
- bool ok = false;
- hash->addData(propertyCache->checksum(&ok));
- if (!ok)
- return false;
- }
- }
- return true;
-}
-
-void QQmlTypeData::done()
-{
- auto cleanup = qScopeGuard([this]{
- m_document.reset();
- m_typeReferences.clear();
- if (isError())
- m_compiledData = nullptr;
- });
-
- if (isError())
- return;
-
- // Check all script dependencies for errors
- for (int ii = 0; ii < m_scripts.count(); ++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.setDescription(QQmlTypeLoader::tr("Script %1 unavailable").arg(script.script->urlString()));
- errors.prepend(error);
- setError(errors);
- return;
- }
- }
-
- // Check all type dependencies for errors
- for (auto it = m_resolvedTypes.constBegin(), end = m_resolvedTypes.constEnd(); it != end;
- ++it) {
- const TypeReference &type = *it;
- Q_ASSERT(!type.typeData || type.typeData->isCompleteOrError());
- 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);
- return;
- }
- }
-
- // Check all composite singleton type dependencies for errors
- for (int ii = 0; ii < m_compositeSingletons.count(); ++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);
- return;
- }
- }
-
- QQmlRefPointer<QQmlTypeNameCache> typeNameCache;
- QV4::ResolvedTypeReferenceMap resolvedTypeCache;
- {
- QQmlJS::DiagnosticMessage error = buildTypeResolutionCaches(&typeNameCache, &resolvedTypeCache);
- if (error.isValid()) {
- setError(error);
- return;
- }
- }
-
- QQmlEngine *const engine = typeLoader()->engine();
-
- const auto dependencyHasher = [engine, &resolvedTypeCache, this]() {
- QCryptographicHash hash(QCryptographicHash::Md5);
- return (resolvedTypeCache.addToHash(&hash, engine)
- && ::addTypeReferenceChecksumsToHash(m_compositeSingletons, &hash, engine))
- ? 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()) {
- // Compile component
- compile(typeNameCache, &resolvedTypeCache, dependencyHasher);
- } else {
- createTypeAndPropertyCaches(typeNameCache, resolvedTypeCache);
- }
-
- if (isError())
- return;
-
- {
- QQmlEnginePrivate *const enginePrivate = QQmlEnginePrivate::get(engine);
- {
- // Sanity check property bindings
- QQmlPropertyValidator validator(enginePrivate, m_importCache, m_compiledData);
- QVector<QQmlJS::DiagnosticMessage> errors = validator.validate();
- if (!errors.isEmpty()) {
- setError(errors);
- return;
- }
- }
-
- m_compiledData->finalizeCompositeType(enginePrivate);
- }
-
- {
- QQmlType type = QQmlMetaType::qmlType(finalUrl(), true);
- if (m_compiledData && m_compiledData->unitData()->flags & QV4::CompiledData::Unit::IsSingleton) {
- if (!type.isValid()) {
- QQmlError error;
- error.setDescription(QQmlTypeLoader::tr("No matching type found, pragma Singleton files cannot be used by QQmlComponent."));
- setError(error);
- return;
- } else if (!type.isCompositeSingleton()) {
- QQmlError error;
- error.setDescription(QQmlTypeLoader::tr("pragma Singleton used with a non composite singleton type %1").arg(type.qmlTypeName()));
- setError(error);
- return;
- }
- } else {
- // If the type is CompositeSingleton but there was no pragma Singleton in the
- // QML file, lets report an error.
- if (type.isValid() && type.isCompositeSingleton()) {
- QString typeName = type.qmlTypeName();
- setError(QQmlTypeLoader::tr("qmldir defines type as singleton, but no pragma Singleton found in type %1.").arg(typeName));
- return;
- }
- }
- }
-
- {
- // Collect imported scripts
- m_compiledData->dependentScripts.reserve(m_scripts.count());
- for (int scriptIndex = 0; scriptIndex < m_scripts.count(); ++scriptIndex) {
- const QQmlTypeData::ScriptReference &script = m_scripts.at(scriptIndex);
-
- QStringRef qualifier(&script.qualifier);
- QString enclosingNamespace;
-
- const int lastDotIndex = qualifier.lastIndexOf(QLatin1Char('.'));
- if (lastDotIndex != -1) {
- enclosingNamespace = qualifier.left(lastDotIndex).toString();
- qualifier = qualifier.mid(lastDotIndex+1);
- }
-
- m_compiledData->typeNameCache->add(qualifier.toString(), scriptIndex, enclosingNamespace);
- QQmlRefPointer<QQmlScriptData> scriptData = script.script->scriptData();
- m_compiledData->dependentScripts << scriptData;
- }
- }
-}
-
-void QQmlTypeData::completed()
-{
- // Notify callbacks
- while (!m_callbacks.isEmpty()) {
- TypeDataCallback *callback = m_callbacks.takeFirst();
- callback->typeDataReady(this);
- }
-}
-
-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());
-
- 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);
-
- if (!implicitImportErrors.isEmpty()) {
- setError(implicitImportErrors);
- return false;
- }
-
- return true;
-}
-
-void QQmlTypeData::dataReceived(const SourceCodeData &data)
-{
- m_backupSourceCode = data;
-
- if (tryLoadFromDiskCache())
- return;
-
- if (isError())
- return;
-
- if (!m_backupSourceCode.exists() || m_backupSourceCode.isEmpty()) {
- if (m_cachedUnitStatus == QQmlMetaType::CachedUnitLookupError::VersionMismatch)
- setError(QQmlTypeLoader::tr("File was compiled ahead of time with an incompatible version of Qt and the original file cannot be found. Please recompile"));
- else if (!m_backupSourceCode.exists())
- setError(QQmlTypeLoader::tr("No such file or directory"));
- else
- setError(QQmlTypeLoader::tr("File is empty"));
- return;
- }
-
- if (!loadFromSource())
- return;
-
- continueLoadFromIR();
-}
-
-void QQmlTypeData::initializeFromCachedUnit(const QV4::CompiledData::Unit *unit)
-{
- m_document.reset(new QmlIR::Document(isDebugging()));
- QQmlIRLoader loader(unit, m_document.data());
- loader.load();
- m_document->jsModule.fileName = urlString();
- m_document->jsModule.finalUrl = finalUrlString();
- m_document->javaScriptCompilationUnit = QV4::CompiledData::CompilationUnit(unit);
- continueLoadFromIR();
-}
-
-bool QQmlTypeData::loadFromSource()
-{
- m_document.reset(new QmlIR::Document(isDebugging()));
- m_document->jsModule.sourceTimeStamp = m_backupSourceCode.sourceTimeStamp();
- QQmlEngine *qmlEngine = typeLoader()->engine();
- QmlIR::IRBuilder compiler(qmlEngine->handle()->illegalNames());
-
- QString sourceError;
- const QString source = m_backupSourceCode.readAll(&sourceError);
- if (!sourceError.isEmpty()) {
- setError(sourceError);
- return false;
- }
-
- if (!compiler.generateFromQml(source, finalUrlString(), m_document.data())) {
- QList<QQmlError> errors;
- errors.reserve(compiler.errors.count());
- for (const QQmlJS::DiagnosticMessage &msg : qAsConst(compiler.errors)) {
- QQmlError e;
- e.setUrl(url());
- e.setLine(msg.line);
- e.setColumn(msg.column);
- e.setDescription(msg.message);
- errors << e;
- }
- setError(errors);
- return false;
- }
- return true;
-}
-
-void QQmlTypeData::restoreIR(QV4::CompiledData::CompilationUnit &&unit)
-{
- m_document.reset(new QmlIR::Document(isDebugging()));
- 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);
- continueLoadFromIR();
-}
-
-void QQmlTypeData::continueLoadFromIR()
-{
- m_typeReferences.collectFromObjects(m_document->objects.constBegin(), m_document->objects.constEnd());
- 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
- // qmldir (so we can't load it just in time).
- if (!finalUrl().scheme().isEmpty()) {
- QUrl qmldirUrl = finalUrl().resolved(QUrl(QLatin1String("qmldir")));
- if (!QQmlImports::isLocal(qmldirUrl)) {
- if (!loadImplicitImport())
- return;
- // This qmldir is for the implicit import
- QQmlJS::MemoryPool *pool = m_document->jsParserEngine.pool();
- auto implicitImport = pool->New<QV4::CompiledData::Import>();
- implicitImport->uriIndex = m_document->registerString(QLatin1String("."));
- implicitImport->qualifierIndex = 0; // empty string
- implicitImport->majorVersion = -1;
- implicitImport->minorVersion = -1;
- QList<QQmlError> errors;
-
- if (!fetchQmldir(qmldirUrl, implicitImport, 1, &errors)) {
- setError(errors);
- return;
- }
- }
- }
-
- QList<QQmlError> errors;
-
- for (const QV4::CompiledData::Import *import : qAsConst(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);
- return;
- }
- }
-}
-
-void QQmlTypeData::allDependenciesDone()
-{
- QQmlTypeLoader::Blob::allDependenciesDone();
-
- if (!m_typesResolved) {
- // Check that all imports were resolved
- QList<QQmlError> errors;
- QHash<const QV4::CompiledData::Import *, int>::const_iterator it = m_unresolvedImports.constBegin(), end = m_unresolvedImports.constEnd();
- for ( ; it != end; ++it) {
- if (*it == 0) {
- // This import was not resolved
- for (auto keyIt = m_unresolvedImports.keyBegin(),
- keyEnd = m_unresolvedImports.keyEnd();
- keyIt != keyEnd; ++keyIt) {
- const QV4::CompiledData::Import *import = *keyIt;
- QQmlError error;
- error.setDescription(QQmlTypeLoader::tr("module \"%1\" is not installed").arg(stringAt(import->uriIndex)));
- error.setUrl(m_importCache.baseUrl());
- error.setLine(import->location.line);
- error.setColumn(import->location.column);
- errors.prepend(error);
- }
- }
- }
- if (errors.size()) {
- setError(errors);
- return;
- }
-
- resolveTypes();
- m_typesResolved = true;
- }
-}
-
-void QQmlTypeData::downloadProgressChanged(qreal p)
-{
- for (int ii = 0; ii < m_callbacks.count(); ++ii) {
- TypeDataCallback *callback = m_callbacks.at(ii);
- callback->typeDataProgress(this, p);
- }
-}
-
-QString QQmlTypeData::stringAt(int index) const
-{
- if (m_compiledData)
- return m_compiledData->stringAt(index);
- return m_document->jsGenerator.stringTable.stringForIndex(index);
-}
-
-void QQmlTypeData::compile(const QQmlRefPointer<QQmlTypeNameCache> &typeNameCache,
- QV4::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);
-
- QQmlEnginePrivate * const enginePrivate = QQmlEnginePrivate::get(typeLoader()->engine());
- QQmlTypeCompiler compiler(enginePrivate, this, m_document.data(), typeNameCache, resolvedTypeCache, dependencyHasher);
- m_compiledData = compiler.compile();
- if (!m_compiledData) {
- setError(compiler.compilationErrors());
- return;
- }
-
- const bool trySaveToDisk = (!disableDiskCache() || forceDiskCache()) && !m_document->jsModule.debugMode && !typeRecompilation;
- if (trySaveToDisk) {
- QString errorString;
- if (m_compiledData->saveToDisk(url(), &errorString)) {
- QString error;
- if (!m_compiledData->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;
- }
- }
-}
-
-void QQmlTypeData::resolveTypes()
-{
- // Add any imported scripts to our resolved set
- const auto resolvedScripts = m_importCache.resolvedScripts();
- for (const QQmlImports::ScriptReference &script : resolvedScripts) {
- QQmlRefPointer<QQmlScriptBlob> blob = typeLoader()->getScript(script.location);
- addDependency(blob.data());
-
- ScriptReference ref;
- //ref.location = ...
- if (!script.qualifier.isEmpty())
- {
- ref.qualifier = script.qualifier + QLatin1Char('.') + script.nameSpace;
- // Add a reference to the enclosing namespace
- m_namespaces.insert(script.qualifier);
- } else {
- ref.qualifier = script.nameSpace;
- }
-
- ref.script = blob;
- m_scripts << ref;
- }
-
- // Lets handle resolved composite singleton types
- const auto resolvedCompositeSingletons = m_importCache.resolvedCompositeSingletons();
- for (const QQmlImports::CompositeSingletonReference &csRef : resolvedCompositeSingletons) {
- TypeReference ref;
- QString typeName;
- if (!csRef.prefix.isEmpty()) {
- typeName = csRef.prefix + QLatin1Char('.') + csRef.typeName;
- // Add a reference to the enclosing namespace
- m_namespaces.insert(csRef.prefix);
- } else {
- 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))
- return;
-
- if (ref.type.isCompositeSingleton()) {
- ref.typeData = typeLoader()->getType(ref.type.sourceUrl());
- if (ref.typeData->status() == QQmlDataBlob::ResolvingDependencies) {
- // TODO: give an error message? If so, we should record and show the path of the cycle.
- continue;
- }
- addDependency(ref.typeData.data());
- ref.prefix = csRef.prefix;
-
- m_compositeSingletons << ref;
- }
- }
-
- for (QV4::CompiledData::TypeReferenceMap::ConstIterator unresolvedRef = m_typeReferences.constBegin(), end = m_typeReferences.constEnd();
- unresolvedRef != end; ++unresolvedRef) {
-
- TypeReference ref; // resolved reference
-
- const bool reportErrors = unresolvedRef->errorWhenNotFound;
-
- int majorVersion = -1;
- int minorVersion = -1;
-
- const QString name = stringAt(unresolvedRef.key());
-
- if (!resolveType(name, majorVersion, minorVersion, ref, unresolvedRef->location.line,
- unresolvedRef->location.column, reportErrors,
- QQmlType::AnyRegistrationType) && reportErrors)
- return;
-
- if (ref.type.isComposite()) {
- 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;
-
- ref.needsCreation = unresolvedRef->needsCreation;
-
- m_resolvedTypes.insert(unresolvedRef.key(), ref);
- }
-
- // ### this allows enums to work without explicit import or instantiation of the type
- if (!m_implicitImportLoaded)
- loadImplicitImport();
-}
-
-QQmlJS::DiagnosticMessage QQmlTypeData::buildTypeResolutionCaches(
- QQmlRefPointer<QQmlTypeNameCache> *typeNameCache,
- QV4::ResolvedTypeReferenceMap *resolvedTypeCache
- ) const
-{
- typeNameCache->adopt(new QQmlTypeNameCache(m_importCache));
-
- for (const QString &ns: m_namespaces)
- (*typeNameCache)->add(ns);
-
- // Add any Composite Singletons that were used to the import cache
- 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());
-
- for (auto resolvedType = m_resolvedTypes.constBegin(), end = m_resolvedTypes.constEnd(); resolvedType != end; ++resolvedType) {
- QScopedPointer<QV4::ResolvedTypeReference> ref(new 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());
-
- if (resolvedType->needsCreation && !ref->type.isCreatable()) {
- QString reason = ref->type.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);
- }
- }
- ref->majorVersion = resolvedType->majorVersion;
- ref->minorVersion = resolvedType->minorVersion;
- ref->doDynamicTypeCheck();
- resolvedTypeCache->insert(resolvedType.key(), ref.take());
- }
- QQmlJS::DiagnosticMessage noError;
- return noError;
-}
-
-bool QQmlTypeData::resolveType(const QString &typeName, int &majorVersion, int &minorVersion,
- TypeReference &ref, int lineNumber, int columnNumber,
- bool reportErrors, QQmlType::RegistrationType registrationType)
-{
- QQmlImportNamespace *typeNamespace = nullptr;
- QList<QQmlError> errors;
-
- bool typeFound = m_importCache.resolveType(typeName, &ref.type, &majorVersion, &minorVersion,
- &typeNamespace, &errors, registrationType);
- 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);
- } else {
- return false; //loadImplicitImport() hit an error, and called setError already
- }
- }
-
- if ((!typeFound || typeNamespace) && reportErrors) {
- // Known to not be a type:
- // - known to be a namespace (Namespace {})
- // - type with unknown namespace (UnknownNamespace.SomeType {})
- QQmlError error;
- if (typeNamespace) {
- error.setDescription(QQmlTypeLoader::tr("Namespace %1 cannot be used as a type").arg(typeName));
- } else {
- if (errors.size()) {
- error = errors.takeFirst();
- } else {
- // this should not be possible!
- // 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.setDescription(QQmlTypeLoader::tr("%1 %2").arg(typeName).arg(error.description()));
- }
-
- if (lineNumber != -1)
- error.setLine(lineNumber);
- if (columnNumber != -1)
- error.setColumn(columnNumber);
-
- errors.prepend(error);
- setError(errors);
- return false;
- }
-
- return true;
-}
-
-void QQmlTypeData::scriptImported(const QQmlRefPointer<QQmlScriptBlob> &blob, const QV4::CompiledData::Location &location, const QString &qualifier, const QString &/*nameSpace*/)
-{
- ScriptReference ref;
- ref.script = blob;
- ref.location = location;
- ref.qualifier = qualifier;
-
- m_scripts << ref;
-}
-
-QQmlScriptData::QQmlScriptData()
- : typeNameCache(nullptr)
- , m_loaded(false)
-{
-}
-
-QQmlContextData *QQmlScriptData::qmlContextDataForContext(QQmlContextData *parentQmlContextData)
-{
- Q_ASSERT(parentQmlContextData && parentQmlContextData->engine);
-
- if (m_precompiledScript->isESModule())
- return nullptr;
-
- auto qmlContextData = new QQmlContextData();
-
- qmlContextData->isInternal = true;
- qmlContextData->isJSContext = true;
- if (m_precompiledScript->isSharedLibrary())
- qmlContextData->isPragmaLibraryContext = true;
- else
- qmlContextData->isPragmaLibraryContext = parentQmlContextData->isPragmaLibraryContext;
- qmlContextData->baseUrl = url;
- qmlContextData->baseUrlString = 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;
- } else if (!m_precompiledScript->isSharedLibrary()) {
- qmlContextData->imports = parentQmlContextData->imports;
- qmlContextData->importedScripts = parentQmlContextData->importedScripts;
- }
-
- if (!m_precompiledScript->isSharedLibrary()) {
- qmlContextData->setParent(parentQmlContextData);
- } else {
- qmlContextData->engine = parentQmlContextData->engine; // Fix for QTBUG-21620
- }
-
- 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);
- } else {
- 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)));
-
- return qmlContextData;
-}
-
-QV4::ReturnedValue QQmlScriptData::scriptValueForContext(QQmlContextData *parentQmlContextData)
-{
- if (m_loaded)
- return m_value.value();
-
- Q_ASSERT(parentQmlContextData && parentQmlContextData->engine);
- QV4::ExecutionEngine *v4 = parentQmlContextData->engine->handle();
- QV4::Scope scope(v4);
-
- if (!hasEngine()) {
- addToEngine(parentQmlContextData->engine);
- addref();
- }
-
- 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, m_precompiledScript->instantiate(v4));
- if (module) {
- if (qmlContextData) {
- module->d()->scope->outer.set(v4, qmlExecutionContext->d());
- qmlExecutionContext->d()->qml()->module.set(v4, module->d());
- }
-
- module->evaluate();
- }
-
- if (v4->hasException) {
- QQmlError error = v4->catchExceptionAsQmlError();
- if (error.isValid())
- QQmlEnginePrivate::get(v4)->warning(error);
- }
-
- QV4::ScopedValue value(scope);
- if (qmlContextData)
- value = qmlExecutionContext->d()->qml();
- else if (module)
- value = module->d();
-
- if (m_precompiledScript->isSharedLibrary() || m_precompiledScript->isESModule()) {
- m_loaded = true;
- m_value.set(v4, value);
- }
-
- return value->asReturnedValue();
-}
-
-void QQmlScriptData::clear()
-{
- if (typeNameCache) {
- typeNameCache->release();
- typeNameCache = nullptr;
- }
-
- scripts.clear();
-
- // An addref() was made when the QQmlCleanup was added to the engine.
- release();
-}
-
-QQmlScriptBlob::QQmlScriptBlob(const QUrl &url, QQmlTypeLoader *loader)
- : QQmlTypeLoader::Blob(url, JavaScriptFile, loader)
- , m_isModule(url.path().endsWith(QLatin1String(".mjs")))
-{
-}
-
-QQmlScriptBlob::~QQmlScriptBlob()
-{
-}
-
-QQmlRefPointer<QQmlScriptData> QQmlScriptBlob::scriptData() const
-{
- return m_scriptData;
-}
-
-void QQmlScriptBlob::dataReceived(const SourceCodeData &data)
-{
- if (!disableDiskCache() || forceDiskCache()) {
- QQmlRefPointer<QV4::ExecutableCompilationUnit> unit
- = QV4::ExecutableCompilationUnit::create();
- QString error;
- if (unit->loadFromDisk(url(), data.sourceTimeStamp(), &error)) {
- initializeFromCompilationUnit(unit);
- return;
- } else {
- qCDebug(DBG_DISK_CACHE()) << "Error loading" << urlString() << "from disk cache:" << error;
- }
- }
-
- if (!data.exists()) {
- if (m_cachedUnitStatus == QQmlMetaType::CachedUnitLookupError::VersionMismatch)
- setError(QQmlTypeLoader::tr("File was compiled ahead of time with an incompatible version of Qt and the original file cannot be found. Please recompile"));
- else
- setError(QQmlTypeLoader::tr("No such file or directory"));
- return;
- }
-
- QString error;
- QString source = data.readAll(&error);
- if (!error.isEmpty()) {
- setError(error);
- return;
- }
-
- QV4::CompiledData::CompilationUnit unit;
-
- if (m_isModule) {
- QList<QQmlJS::DiagnosticMessage> diagnostics;
- unit = QV4::Compiler::Codegen::compileModule(isDebugging(), urlString(), source,
- data.sourceTimeStamp(), &diagnostics);
- QList<QQmlError> errors = QQmlEnginePrivate::qmlErrorFromDiagnostics(urlString(), diagnostics);
- if (!errors.isEmpty()) {
- setError(errors);
- return;
- }
- } else {
- QmlIR::Document irUnit(isDebugging());
-
- irUnit.jsModule.sourceTimeStamp = data.sourceTimeStamp();
-
- QmlIR::ScriptDirectivesCollector collector(&irUnit);
- irUnit.jsParserEngine.setDirectives(&collector);
-
- QList<QQmlError> errors;
- irUnit.javaScriptCompilationUnit = QV4::Script::precompile(
- &irUnit.jsModule, &irUnit.jsParserEngine, &irUnit.jsGenerator, urlString(), finalUrlString(),
- source, &errors, QV4::Compiler::ContextType::ScriptImportedByQML);
-
- source.clear();
- if (!errors.isEmpty()) {
- setError(errors);
- return;
- }
-
- QmlIR::QmlUnitGenerator qmlGenerator;
- qmlGenerator.generate(irUnit);
- unit = std::move(irUnit.javaScriptCompilationUnit);
- }
-
- auto executableUnit = QV4::ExecutableCompilationUnit::create(std::move(unit));
-
- if ((!disableDiskCache() || forceDiskCache()) && !isDebugging()) {
- QString errorString;
- if (executableUnit->saveToDisk(url(), &errorString)) {
- QString error;
- if (!executableUnit->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;
- }
- }
-
- initializeFromCompilationUnit(executableUnit);
-}
-
-void QQmlScriptBlob::initializeFromCachedUnit(const QV4::CompiledData::Unit *unit)
-{
- initializeFromCompilationUnit(QV4::ExecutableCompilationUnit::create(
- QV4::CompiledData::CompilationUnit(unit, urlString(), finalUrlString())));
-}
-
-void QQmlScriptBlob::done()
-{
- if (isError())
- return;
-
- // Check all script dependencies for errors
- for (int ii = 0; ii < m_scripts.count(); ++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.setDescription(QQmlTypeLoader::tr("Script %1 unavailable").arg(script.script->urlString()));
- errors.prepend(error);
- setError(errors);
- return;
- }
- }
-
- if (!m_isModule) {
- m_scriptData->typeNameCache = new QQmlTypeNameCache(m_importCache);
-
- QSet<QString> ns;
-
- for (int scriptIndex = 0; scriptIndex < m_scripts.count(); ++scriptIndex) {
- const ScriptReference &script = m_scripts.at(scriptIndex);
-
- m_scriptData->scripts.append(script.script);
-
- if (!script.nameSpace.isNull()) {
- if (!ns.contains(script.nameSpace)) {
- ns.insert(script.nameSpace);
- m_scriptData->typeNameCache->add(script.nameSpace);
- }
- }
- m_scriptData->typeNameCache->add(script.qualifier, scriptIndex, script.nameSpace);
- }
-
- m_importCache.populateCache(m_scriptData->typeNameCache);
- }
- m_scripts.clear();
-}
-
-QString QQmlScriptBlob::stringAt(int index) const
-{
- return m_scriptData->m_precompiledScript->stringAt(index);
-}
-
-void QQmlScriptBlob::scriptImported(const QQmlRefPointer<QQmlScriptBlob> &blob, const QV4::CompiledData::Location &location, const QString &qualifier, const QString &nameSpace)
-{
- ScriptReference ref;
- ref.script = blob;
- ref.location = location;
- ref.qualifier = qualifier;
- ref.nameSpace = nameSpace;
-
- m_scripts << ref;
-}
-
-void QQmlScriptBlob::initializeFromCompilationUnit(const QQmlRefPointer<QV4::ExecutableCompilationUnit> &unit)
-{
- Q_ASSERT(!m_scriptData);
- 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;
-
- 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)) {
- 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);
- return;
- }
- }
- }
-
- auto *v4 = QQmlEnginePrivate::getV4Engine(typeLoader()->engine());
-
- v4->injectModule(unit);
-
- for (const QString &request: unit->moduleRequests()) {
- if (v4->moduleForUrl(QUrl(request), unit.data()))
- 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());
- }
-}
-
-QQmlQmldirData::QQmlQmldirData(const QUrl &url, QQmlTypeLoader *loader)
-: QQmlTypeLoader::Blob(url, QmldirFile, loader)
-{
-}
-
-const QString &QQmlQmldirData::content() const
-{
- return m_content;
-}
-
-const QV4::CompiledData::Import *QQmlQmldirData::import(QQmlTypeLoader::Blob *blob) const
-{
- QHash<QQmlTypeLoader::Blob *, const QV4::CompiledData::Import *>::const_iterator it =
- m_imports.find(blob);
- if (it == m_imports.end())
- return nullptr;
- return *it;
-}
-
-void QQmlQmldirData::setImport(QQmlTypeLoader::Blob *blob, const QV4::CompiledData::Import *import)
-{
- m_imports[blob] = 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;
-}
-
-void QQmlQmldirData::dataReceived(const SourceCodeData &data)
-{
- QString error;
- m_content = data.readAll(&error);
- if (!error.isEmpty()) {
- setError(error);
- return;
- }
-}
-
-void QQmlQmldirData::initializeFromCachedUnit(const QV4::CompiledData::Unit *)
-{
- Q_UNIMPLEMENTED();
-}
-
-QString QQmlDataBlob::SourceCodeData::readAll(QString *error) const
-{
- error->clear();
- if (hasInlineSourceCode)
- return inlineSourceCode;
-
- QFile f(fileInfo.absoluteFilePath());
- if (!f.open(QIODevice::ReadOnly)) {
- *error = f.errorString();
- return QString();
- }
-
- const qint64 fileSize = fileInfo.size();
-
- if (uchar *mappedData = f.map(0, fileSize)) {
- QString source = QString::fromUtf8(reinterpret_cast<const char *>(mappedData), fileSize);
- f.unmap(mappedData);
- return source;
- }
-
- QByteArray data(fileSize, Qt::Uninitialized);
- if (f.read(data.data(), data.length()) != data.length()) {
- *error = f.errorString();
- return QString();
- }
- return QString::fromUtf8(data);
-}
-
-QDateTime QQmlDataBlob::SourceCodeData::sourceTimeStamp() const
-{
- if (hasInlineSourceCode)
- return QDateTime();
-
- return fileInfo.lastModified();
-}
-
-bool QQmlDataBlob::SourceCodeData::exists() const
-{
- if (hasInlineSourceCode)
- return true;
- return fileInfo.exists();
-}
-
-bool QQmlDataBlob::SourceCodeData::isEmpty() const
-{
- if (hasInlineSourceCode)
- return inlineSourceCode.isEmpty();
- return fileInfo.size() == 0;
-}
-
QT_END_NAMESPACE
-
-#include "qqmltypeloader.moc"
diff --git a/src/qml/qml/qqmltypeloader_p.h b/src/qml/qml/qqmltypeloader_p.h
index 3330d52e56..5710bdba56 100644
--- a/src/qml/qml/qqmltypeloader_p.h
+++ b/src/qml/qml/qqmltypeloader_p.h
@@ -51,213 +51,25 @@
// We mean it.
//
+#include <private/qqmldatablob_p.h>
+#include <private/qqmlimport_p.h>
+#include <private/qqmlmetatype_p.h>
+
#include <QtQml/qtqmlglobal.h>
-#include <QtCore/qobject.h>
-#include <QtCore/qatomic.h>
-#include <QtCore/qfileinfo.h>
-#include <QtCore/qcache.h>
-#if QT_CONFIG(qml_network)
-#include <QtNetwork/qnetworkreply.h>
-#endif
#include <QtQml/qqmlerror.h>
-#include <QtQml/qqmlengine.h>
-#include <QtQml/qqmlfile.h>
-#include <QtQml/qqmlabstracturlinterceptor.h>
-
-#include <private/qhashedstring_p.h>
-#include <private/qqmlimport_p.h>
-#include <private/qqmlcleanup_p.h>
-#include <private/qqmldirparser_p.h>
-#include <private/qflagpointer_p.h>
-#include <private/qqmlirbuilder_p.h>
-#include <private/qv4executablecompilationunit_p.h>
-#include <private/qv4value_p.h>
-#include <private/qv4script_p.h>
+#include <QtCore/qcache.h>
+#include <QtCore/qmutex.h>
QT_BEGIN_NAMESPACE
-class QQmlScriptData;
class QQmlScriptBlob;
class QQmlQmldirData;
-class QQmlTypeLoader;
-class QQmlComponentPrivate;
class QQmlTypeData;
-class QQmlTypeLoader;
class QQmlExtensionInterface;
class QQmlProfiler;
-
-namespace QmlIR {
-struct Document;
-}
-
-class Q_QML_PRIVATE_EXPORT QQmlDataBlob : public QQmlRefCount
-{
-public:
- enum Status {
- Null, // Prior to QQmlTypeLoader::load()
- Loading, // Prior to data being received and dataReceived() being called
- WaitingForDependencies, // While there are outstanding addDependency()s
- ResolvingDependencies, // While resolving outstanding dependencies, to detect cycles
- Complete, // Finished
- Error // Error
- };
-
- enum Type { //Matched in QQmlAbstractUrlInterceptor
- QmlFile = QQmlAbstractUrlInterceptor::QmlFile,
- JavaScriptFile = QQmlAbstractUrlInterceptor::JavaScriptFile,
- QmldirFile = QQmlAbstractUrlInterceptor::QmldirFile
- };
-
- QQmlDataBlob(const QUrl &, Type, QQmlTypeLoader* manager);
- ~QQmlDataBlob() override;
-
- void startLoading();
-
- QQmlTypeLoader *typeLoader() const { return m_typeLoader; }
-
- Type type() const;
-
- Status status() const;
- bool isNull() const;
- bool isLoading() const;
- bool isWaiting() const;
- bool isComplete() const;
- bool isError() const;
- bool isCompleteOrError() const;
-
- qreal progress() const;
-
- QUrl url() const;
- QString urlString() const;
- QUrl finalUrl() const;
- QString finalUrlString() const;
-
- QList<QQmlError> errors() const;
-
- class SourceCodeData {
- public:
- QString readAll(QString *error) const;
- QDateTime sourceTimeStamp() const;
- bool exists() const;
- bool isEmpty() const;
- private:
- friend class QQmlDataBlob;
- friend class QQmlTypeLoader;
- QString inlineSourceCode;
- QFileInfo fileInfo;
- bool hasInlineSourceCode = false;
- };
-
-protected:
- // Can be called from within callbacks
- 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 done();
-#if QT_CONFIG(qml_network)
- virtual void networkError(QNetworkReply::NetworkError);
-#endif
- virtual void dependencyError(QQmlDataBlob *);
- virtual void dependencyComplete(QQmlDataBlob *);
- virtual void allDependenciesDone();
-
- // Callbacks made in main thread
- virtual void downloadProgressChanged(qreal);
- virtual void completed();
-
-protected:
- // Manager that is currently fetching data for me
- QQmlTypeLoader *m_typeLoader;
-
-private:
- friend class QQmlTypeLoader;
- friend class QQmlTypeLoaderThread;
-
- void tryDone();
- void cancelAllWaitingFor();
- void notifyAllWaitingOnMe();
- void notifyComplete(QQmlDataBlob *);
-
- struct ThreadData {
- inline ThreadData();
- inline QQmlDataBlob::Status status() const;
- inline void setStatus(QQmlDataBlob::Status);
- inline bool isAsync() const;
- inline void setIsAsync(bool);
- inline quint8 progress() const;
- inline void setProgress(quint8);
-
- private:
- QAtomicInt _p;
- };
- ThreadData m_data;
-
- // m_errors should *always* be written before the status is set to Error.
- // We use the status change as a memory fence around m_errors so that locking
- // isn't required. Once the status is set to Error (or Complete), m_errors
- // cannot be changed.
- QList<QQmlError> m_errors;
-
- Type m_type;
-
- QUrl m_url;
- QUrl m_finalUrl;
- mutable QString m_urlString;
- mutable QString m_finalUrlString;
-
- // List of QQmlDataBlob's that are waiting for me to complete.
- QList<QQmlDataBlob *> m_waitingOnMe;
-
- // List of QQmlDataBlob's that I am waiting for to complete.
- QVector<QQmlRefPointer<QQmlDataBlob>> m_waitingFor;
-
- int m_redirectCount:30;
- bool m_inCallback:1;
- bool m_isDone:1;
-};
-
class QQmlTypeLoaderThread;
-
-class QQmlTypeLoaderQmldirContent
-{
-private:
- friend class QQmlTypeLoader;
-
- void setContent(const QString &location, const QString &content);
- void setError(const QQmlError &);
-
-public:
- QQmlTypeLoaderQmldirContent();
- 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;
-
- QString typeNamespace() const;
-
- QQmlDirComponents components() const;
- QQmlDirScripts scripts() const;
- QQmlDirPlugins plugins() const;
-
- QString pluginLocation() const;
-
- bool designerSupported() const;
-
-private:
- QQmlDirParser m_parser;
- QString m_location;
- bool m_hasContent = false;
-};
+class QQmlEngine;
class Q_QML_PRIVATE_EXPORT QQmlTypeLoader
{
@@ -293,6 +105,9 @@ public:
bool isDebugging() const;
+ static bool diskCacheDisabled();
+ static bool diskCacheForced();
+
QQmlImports m_importCache;
QHash<const QV4::CompiledData::Import*, int> m_unresolvedImports;
QVector<QQmlRefPointer<QQmlQmldirData>> m_qmldirs;
@@ -418,209 +233,6 @@ private:
friend struct StaticLoader;
};
-class Q_AUTOTEST_EXPORT QQmlTypeData : public QQmlTypeLoader::Blob
-{
- Q_DECLARE_TR_FUNCTIONS(QQmlTypeData)
-public:
- struct TypeReference
- {
- TypeReference() : majorVersion(0), minorVersion(0), needsCreation(true) {}
-
- QV4::CompiledData::Location location;
- QQmlType type;
- int majorVersion;
- int minorVersion;
- QQmlRefPointer<QQmlTypeData> typeData;
- QString prefix; // used by CompositeSingleton types
- QString qualifiedName() const;
- bool needsCreation;
- };
-
- struct ScriptReference
- {
- QV4::CompiledData::Location location;
- QString qualifier;
- QQmlRefPointer<QQmlScriptBlob> script;
- };
-
-private:
- friend class QQmlTypeLoader;
-
- QQmlTypeData(const QUrl &, QQmlTypeLoader *);
-
-public:
- ~QQmlTypeData() override;
-
- const QList<ScriptReference> &resolvedScripts() const;
-
- QV4::ExecutableCompilationUnit *compilationUnit() const;
-
- // Used by QQmlComponent to get notifications
- struct TypeDataCallback {
- virtual ~TypeDataCallback();
- virtual void typeDataProgress(QQmlTypeData *, qreal) {}
- virtual void typeDataReady(QQmlTypeData *) {}
- };
- void registerCallback(TypeDataCallback *);
- void unregisterCallback(TypeDataCallback *);
-
-protected:
- void done() override;
- void completed() override;
- void dataReceived(const SourceCodeData &) override;
- void initializeFromCachedUnit(const QV4::CompiledData::Unit *unit) override;
- void allDependenciesDone() override;
- void downloadProgressChanged(qreal) override;
-
- QString stringAt(int index) const override;
-
-private:
- bool tryLoadFromDiskCache();
- bool loadFromSource();
- void restoreIR(QV4::CompiledData::CompilationUnit &&unit);
- void continueLoadFromIR();
- void resolveTypes();
- QQmlJS::DiagnosticMessage buildTypeResolutionCaches(
- QQmlRefPointer<QQmlTypeNameCache> *typeNameCache,
- QV4::ResolvedTypeReferenceMap *resolvedTypeCache
- ) const;
- void compile(const QQmlRefPointer<QQmlTypeNameCache> &typeNameCache,
- QV4::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,
- 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;
-
-
- SourceCodeData m_backupSourceCode; // used when cache verification fails.
- QScopedPointer<QmlIR::Document> m_document;
- QV4::CompiledData::TypeReferenceMap m_typeReferences;
-
- QList<ScriptReference> m_scripts;
-
- QSet<QString> m_namespaces;
- QList<TypeReference> m_compositeSingletons;
-
- // map from name index to resolved type
- // While this could be a hash, a map is chosen here to provide a stable
- // order, which is used to calculating a check-sum on dependent meta-objects.
- QMap<int, TypeReference> m_resolvedTypes;
- bool m_typesResolved:1;
-
- QQmlRefPointer<QV4::ExecutableCompilationUnit> m_compiledData;
-
- QList<TypeDataCallback *> m_callbacks;
-
- bool m_implicitImportLoaded;
- bool loadImplicitImport();
-};
-
-// 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
-{
-private:
- friend class QQmlTypeLoader;
-
- QQmlScriptData();
-
-public:
- QUrl url;
- QString urlString;
- QQmlTypeNameCache *typeNameCache;
- QVector<QQmlRefPointer<QQmlScriptBlob>> scripts;
-
- QV4::ReturnedValue scriptValueForContext(QQmlContextData *parentCtxt);
-
- QQmlRefPointer<QV4::ExecutableCompilationUnit> compilationUnit() const { return m_precompiledScript; }
-
-protected:
- void clear() override; // From QQmlCleanup
-
-private:
- friend class QQmlScriptBlob;
-
- void initialize(QQmlEngine *);
- QQmlContextData *qmlContextDataForContext(QQmlContextData *parentQmlContextData);
-
- bool m_loaded;
- QQmlRefPointer<QV4::ExecutableCompilationUnit> m_precompiledScript;
- QV4::PersistentValue m_value;
-};
-
-class Q_AUTOTEST_EXPORT QQmlScriptBlob : public QQmlTypeLoader::Blob
-{
-private:
- friend class QQmlTypeLoader;
-
- QQmlScriptBlob(const QUrl &, QQmlTypeLoader *);
-
-public:
- ~QQmlScriptBlob() override;
-
- struct ScriptReference
- {
- QV4::CompiledData::Location location;
- QString qualifier;
- QString nameSpace;
- QQmlRefPointer<QQmlScriptBlob> script;
- };
-
- QQmlRefPointer<QQmlScriptData> scriptData() const;
-
-protected:
- void dataReceived(const SourceCodeData &) override;
- void initializeFromCachedUnit(const QV4::CompiledData::Unit *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);
-
- QList<ScriptReference> m_scripts;
- QQmlRefPointer<QQmlScriptData> m_scriptData;
- const bool m_isModule;
-};
-
-class Q_AUTOTEST_EXPORT QQmlQmldirData : public QQmlTypeLoader::Blob
-{
-private:
- friend class QQmlTypeLoader;
-
- QQmlQmldirData(const QUrl &, QQmlTypeLoader *);
-
-public:
- const QString &content() const;
-
- const QV4::CompiledData::Import *import(QQmlTypeLoader::Blob *) const;
- void setImport(QQmlTypeLoader::Blob *, const QV4::CompiledData::Import *);
-
- int priority(QQmlTypeLoader::Blob *) const;
- void setPriority(QQmlTypeLoader::Blob *, int);
-
-protected:
- void dataReceived(const SourceCodeData &) override;
- void initializeFromCachedUnit(const QV4::CompiledData::Unit *) override;
-
-private:
- QString m_content;
- QHash<QQmlTypeLoader::Blob *, const QV4::CompiledData::Import *> m_imports;
- QHash<QQmlTypeLoader::Blob *, int> m_priorities;
-};
-
-
QT_END_NAMESPACE
#endif // QQMLTYPELOADER_P_H
diff --git a/src/qml/qml/qqmltypeloadernetworkreplyproxy.cpp b/src/qml/qml/qqmltypeloadernetworkreplyproxy.cpp
new file mode 100644
index 0000000000..af97643163
--- /dev/null
+++ b/src/qml/qml/qqmltypeloadernetworkreplyproxy.cpp
@@ -0,0 +1,74 @@
+/****************************************************************************
+**
+** 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 <private/qqmltypeloadernetworkreplyproxy_p.h>
+#include <private/qqmltypeloader_p.h>
+
+QT_BEGIN_NAMESPACE
+
+QQmlTypeLoaderNetworkReplyProxy::QQmlTypeLoaderNetworkReplyProxy(QQmlTypeLoader *l)
+ : l(l)
+{
+}
+
+void QQmlTypeLoaderNetworkReplyProxy::finished()
+{
+ Q_ASSERT(sender());
+ Q_ASSERT(qobject_cast<QNetworkReply *>(sender()));
+ QNetworkReply *reply = static_cast<QNetworkReply *>(sender());
+ l->networkReplyFinished(reply);
+}
+
+void QQmlTypeLoaderNetworkReplyProxy::downloadProgress(qint64 bytesReceived, qint64 bytesTotal)
+{
+ Q_ASSERT(sender());
+ Q_ASSERT(qobject_cast<QNetworkReply *>(sender()));
+ QNetworkReply *reply = static_cast<QNetworkReply *>(sender());
+ l->networkReplyProgress(reply, bytesReceived, bytesTotal);
+}
+
+// This function is for when you want to shortcut the signals and call directly
+void QQmlTypeLoaderNetworkReplyProxy::manualFinished(QNetworkReply *reply)
+{
+ qint64 replySize = reply->size();
+ l->networkReplyProgress(reply, replySize, replySize);
+ l->networkReplyFinished(reply);
+}
+
+QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmltypeloadernetworkreplyproxy_p.h b/src/qml/qml/qqmltypeloadernetworkreplyproxy_p.h
new file mode 100644
index 0000000000..ed87a2b508
--- /dev/null
+++ b/src/qml/qml/qqmltypeloadernetworkreplyproxy_p.h
@@ -0,0 +1,86 @@
+/****************************************************************************
+**
+** 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 QQMLTYPELOADERNETWORKREPLYPROXY_P_H
+#define QQMLTYPELOADERNETWORKREPLYPROXY_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>
+#include <QtCore/qobject.h>
+
+QT_REQUIRE_CONFIG(qml_network);
+
+QT_BEGIN_NAMESPACE
+
+class QNetworkReply;
+class QQmlTypeLoader;
+
+// This is a lame object that we need to ensure that slots connected to
+// QNetworkReply get called in the correct thread (the loader thread).
+// As QQmlTypeLoader lives in the main thread, and we can't use
+// Qt::DirectConnection connections from a QNetworkReply (because then
+// sender() wont work), we need to insert this object in the middle.
+class QQmlTypeLoaderNetworkReplyProxy : public QObject
+{
+ Q_OBJECT
+public:
+ QQmlTypeLoaderNetworkReplyProxy(QQmlTypeLoader *l);
+
+public slots:
+ void finished();
+ void downloadProgress(qint64, qint64);
+ void manualFinished(QNetworkReply*);
+
+private:
+ QQmlTypeLoader *l;
+};
+
+QT_END_NAMESPACE
+
+#endif // QQMLTYPELOADERNETWORKREPLYPROXY_P_H
diff --git a/src/qml/qml/qqmltypeloaderqmldircontent.cpp b/src/qml/qml/qqmltypeloaderqmldircontent.cpp
new file mode 100644
index 0000000000..4aaa60f496
--- /dev/null
+++ b/src/qml/qml/qqmltypeloaderqmldircontent.cpp
@@ -0,0 +1,115 @@
+/****************************************************************************
+**
+** 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 <private/qqmltypeloaderqmldircontent_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> errors;
+ const QUrl url(uri);
+ for (const auto parseError : m_parser.errors(uri)) {
+ QQmlError error;
+ error.setUrl(url);
+ error.setLine(parseError.line);
+ error.setColumn(parseError.column);
+ error.setDescription(parseError.message);
+ errors.append(error);
+ }
+ return errors;
+}
+
+QString QQmlTypeLoaderQmldirContent::typeNamespace() const
+{
+ return m_parser.typeNamespace();
+}
+
+void QQmlTypeLoaderQmldirContent::setContent(const QString &location, const QString &content)
+{
+ m_hasContent = true;
+ m_location = location;
+ m_parser.parse(content);
+}
+
+void QQmlTypeLoaderQmldirContent::setError(const QQmlError &error)
+{
+ QQmlJS::DiagnosticMessage parseError;
+ parseError.line = error.line();
+ parseError.column = 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();
+}
+
+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
new file mode 100644
index 0000000000..9e0a80cea8
--- /dev/null
+++ b/src/qml/qml/qqmltypeloaderqmldircontent_p.h
@@ -0,0 +1,94 @@
+/****************************************************************************
+**
+** 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 QQMLTYPELOADERQMLDIRCONTENT_P_H
+#define QQMLTYPELOADERQMLDIRCONTENT_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/qqmldirparser_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQmlError;
+class QQmlTypeLoaderQmldirContent
+{
+private:
+ friend class QQmlTypeLoader;
+
+ void setContent(const QString &location, const QString &content);
+ void setError(const QQmlError &);
+
+public:
+ QQmlTypeLoaderQmldirContent();
+ 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;
+
+ QString typeNamespace() const;
+
+ QQmlDirComponents components() const;
+ QQmlDirScripts scripts() const;
+ QQmlDirPlugins plugins() const;
+
+ QString pluginLocation() const;
+
+ bool designerSupported() const;
+
+private:
+ QQmlDirParser m_parser;
+ QString m_location;
+ bool m_hasContent = false;
+};
+
+QT_END_NAMESPACE
+
+#endif // QQMLTYPELOADERQMLDIRCONTENT_P_H
diff --git a/src/qml/qml/qqmltypeloaderthread.cpp b/src/qml/qml/qqmltypeloaderthread.cpp
new file mode 100644
index 0000000000..0e1cecd1e5
--- /dev/null
+++ b/src/qml/qml/qqmltypeloaderthread.cpp
@@ -0,0 +1,198 @@
+/****************************************************************************
+**
+** 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 <private/qqmlengine_p.h>
+#include <private/qqmlextensionplugin_p.h>
+#include <private/qqmltypeloaderthread_p.h>
+
+#if QT_CONFIG(qml_network)
+#include <private/qqmltypeloadernetworkreplyproxy_p.h>
+#endif
+
+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();
+}
+
+#if QT_CONFIG(qml_network)
+QNetworkAccessManager *QQmlTypeLoaderThread::networkAccessManager() const
+{
+ Q_ASSERT(isThisThread());
+ if (!m_networkAccessManager) {
+ m_networkAccessManager = QQmlEnginePrivate::get(m_loader->engine())->createNetworkAccessManager(nullptr);
+ m_networkReplyProxy = new QQmlTypeLoaderNetworkReplyProxy(m_loader);
+ }
+
+ return m_networkAccessManager;
+}
+
+QQmlTypeLoaderNetworkReplyProxy *QQmlTypeLoaderThread::networkReplyProxy() const
+{
+ Q_ASSERT(isThisThread());
+ Q_ASSERT(m_networkReplyProxy); // Must call networkAccessManager() first
+ return m_networkReplyProxy;
+}
+#endif // qml_network
+
+void QQmlTypeLoaderThread::load(QQmlDataBlob *b)
+{
+ b->addref();
+ callMethodInThread(&This::loadThread, b);
+}
+
+void QQmlTypeLoaderThread::loadAsync(QQmlDataBlob *b)
+{
+ b->addref();
+ postMethodToThread(&This::loadThread, b);
+}
+
+void QQmlTypeLoaderThread::loadWithStaticData(QQmlDataBlob *b, const QByteArray &d)
+{
+ b->addref();
+ callMethodInThread(&This::loadWithStaticDataThread, b, d);
+}
+
+void QQmlTypeLoaderThread::loadWithStaticDataAsync(QQmlDataBlob *b, const QByteArray &d)
+{
+ b->addref();
+ postMethodToThread(&This::loadWithStaticDataThread, b, d);
+}
+
+void QQmlTypeLoaderThread::loadWithCachedUnit(QQmlDataBlob *b, const QV4::CompiledData::Unit *unit)
+{
+ b->addref();
+ callMethodInThread(&This::loadWithCachedUnitThread, b, unit);
+}
+
+void QQmlTypeLoaderThread::loadWithCachedUnitAsync(QQmlDataBlob *b, const QV4::CompiledData::Unit *unit)
+{
+ b->addref();
+ postMethodToThread(&This::loadWithCachedUnitThread, b, unit);
+}
+
+void QQmlTypeLoaderThread::callCompleted(QQmlDataBlob *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)
+{
+ 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,
+ const char *uri)
+{
+ callMethodInMain(&This::initializeEngineMain, 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)
+{
+ m_loader->loadThread(b);
+ b->release();
+}
+
+void QQmlTypeLoaderThread::loadWithStaticDataThread(QQmlDataBlob *b, const QByteArray &d)
+{
+ m_loader->loadWithStaticDataThread(b, d);
+ b->release();
+}
+
+void QQmlTypeLoaderThread::loadWithCachedUnitThread(QQmlDataBlob *b, const QV4::CompiledData::Unit *unit)
+{
+ m_loader->loadWithCachedUnitThread(b, unit);
+ b->release();
+}
+
+void QQmlTypeLoaderThread::callCompletedMain(QQmlDataBlob *b)
+{
+#ifdef DATABLOB_DEBUG
+ qWarning("QQmlTypeLoaderThread: %s completed() callback", qPrintable(b->urlString()));
+#endif
+ b->completed();
+ b->release();
+}
+
+void QQmlTypeLoaderThread::callDownloadProgressChangedMain(QQmlDataBlob *b, qreal p)
+{
+#ifdef DATABLOB_DEBUG
+ qWarning("QQmlTypeLoaderThread: %s downloadProgressChanged(%f) callback",
+ qPrintable(b->urlString()), p);
+#endif
+ b->downloadProgressChanged(p);
+ b->release();
+}
+
+void QQmlTypeLoaderThread::initializeEngineMain(QQmlExtensionInterface *iface,
+ const char *uri)
+{
+ Q_ASSERT(m_loader->engine()->thread() == QThread::currentThread());
+ iface->initializeEngine(m_loader->engine(), uri);
+}
+
+QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmltypeloaderthread_p.h b/src/qml/qml/qqmltypeloaderthread_p.h
new file mode 100644
index 0000000000..67e47e86de
--- /dev/null
+++ b/src/qml/qml/qqmltypeloaderthread_p.h
@@ -0,0 +1,110 @@
+/****************************************************************************
+**
+** 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 QQMLTYPELOADERTHREAD_P_H
+#define QQMLTYPELOADERTHREAD_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/qqmlthread_p.h>
+#include <private/qv4compileddata_p.h>
+
+#include <QtQml/qtqmlglobal.h>
+
+#if QT_CONFIG(qml_network)
+#include <private/qqmltypeloadernetworkreplyproxy_p.h>
+#include <QtNetwork/qnetworkaccessmanager.h>
+#endif
+
+QT_BEGIN_NAMESPACE
+
+class QQmlDataBlob;
+class QQmlTypeLoader;
+class QQmlExtensionInterface;
+
+class QQmlTypeLoaderThread : public QQmlThread
+{
+ typedef QQmlTypeLoaderThread This;
+
+public:
+ QQmlTypeLoaderThread(QQmlTypeLoader *loader);
+#if QT_CONFIG(qml_network)
+ 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 initializeEngine(QQmlExtensionInterface *, 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 initializeEngineMain(QQmlExtensionInterface *iface, const char *uri);
+
+ QQmlTypeLoader *m_loader;
+#if QT_CONFIG(qml_network)
+ mutable QNetworkAccessManager *m_networkAccessManager;
+ mutable QQmlTypeLoaderNetworkReplyProxy *m_networkReplyProxy;
+#endif // qml_network
+};
+
+QT_END_NAMESPACE
+
+#endif // QQMLTYPELOADERTHREAD_P_H
diff --git a/src/qml/qml/qqmltypewrapper.cpp b/src/qml/qml/qqmltypewrapper.cpp
index 57c4eec879..931f37b35a 100644
--- a/src/qml/qml/qqmltypewrapper.cpp
+++ b/src/qml/qml/qqmltypewrapper.cpp
@@ -42,6 +42,7 @@
#include <private/qqmlengine_p.h>
#include <private/qqmlcontext_p.h>
#include <private/qqmlmetaobject_p.h>
+#include <private/qqmltypedata_p.h>
#include <private/qjsvalue_p.h>
#include <private/qv4functionobject_p.h>
diff --git a/src/qml/qml/qqmlvaluetype.cpp b/src/qml/qml/qqmlvaluetype.cpp
index fce753cd26..88f7b69dc2 100644
--- a/src/qml/qml/qqmlvaluetype.cpp
+++ b/src/qml/qml/qqmlvaluetype.cpp
@@ -43,7 +43,9 @@
#include <private/qqmlglobal_p.h>
#include <QtCore/qdebug.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
@@ -69,8 +71,10 @@ QQmlValueTypeFactoryImpl::QQmlValueTypeFactoryImpl()
{
std::fill_n(valueTypes, int(QVariant::UserType), nullptr);
+#if QT_CONFIG(qml_itemmodel)
// See types wrapped in qqmlmodelindexvaluetype_p.h
qRegisterMetaType<QItemSelectionRange>();
+#endif
}
QQmlValueTypeFactoryImpl::~QQmlValueTypeFactoryImpl()
@@ -120,13 +124,17 @@ const QMetaObject *QQmlValueTypeFactoryImpl::metaObjectForMetaType(int t)
return &QQmlRectFValueType::staticMetaObject;
case QVariant::EasingCurve:
return &QQmlEasingValueType::staticMetaObject;
+#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;
diff --git a/src/qml/qml/qqmlvmemetaobject.cpp b/src/qml/qml/qqmlvmemetaobject.cpp
index 458f26b465..b9d8fed243 100644
--- a/src/qml/qml/qqmlvmemetaobject.cpp
+++ b/src/qml/qml/qqmlvmemetaobject.cpp
@@ -58,6 +58,7 @@
#include <private/qv4jscall_p.h>
#include <private/qv4qobjectwrapper_p.h>
#include <private/qqmlpropertycachecreator_p.h>
+#include <private/qqmlpropertycachemethodarguments_p.h>
QT_BEGIN_NAMESPACE
@@ -917,21 +918,38 @@ int QQmlVMEMetaObject::metaCall(QObject *o, QMetaObject::Call c, int _id, void *
return -1; // The dynamic method with that id is not available.
}
- const unsigned int parameterCount = function->formalParameterCount();
+ 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->fromVariant(*(QVariant *)a[ii + 1]);
+ for (uint ii = 0; ii < parameterCount; ++ii) {
+ jsCallData->args[ii] = scope.engine->metaTypeToJS(arguments->arguments[ii + 1], a[ii + 1]);
+ }
+ 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]) *(QVariant *)a[0] = QVariant();
+ if (a[0]) {
+ QMetaType::destruct(returnType, a[0]);
+ QMetaType::construct(returnType, a[0], nullptr);
+ }
} else {
- if (a[0]) *(QVariant *)a[0] = scope.engine->toVariant(result, 0);
+ 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.
diff --git a/src/qml/qml/v8/qqmlbuiltinfunctions.cpp b/src/qml/qml/v8/qqmlbuiltinfunctions.cpp
index 4838ef3814..2e213e7dc3 100644
--- a/src/qml/qml/v8/qqmlbuiltinfunctions.cpp
+++ b/src/qml/qml/v8/qqmlbuiltinfunctions.cpp
@@ -40,6 +40,7 @@
#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>
diff --git a/src/qml/qmldirparser/qqmldirparser_p.h b/src/qml/qmldirparser/qqmldirparser_p.h
index 0957c8373a..20b92ab3c6 100644
--- a/src/qml/qmldirparser/qqmldirparser_p.h
+++ b/src/qml/qmldirparser/qqmldirparser_p.h
@@ -54,14 +54,14 @@
#include <QtCore/QUrl>
#include <QtCore/QHash>
#include <QtCore/QDebug>
+#include <private/qtqmlcompilerglobal_p.h>
#include <private/qqmljsengine_p.h>
-#include <private/qv4global_p.h>
#include <private/qqmljsdiagnosticmessage_p.h>
QT_BEGIN_NAMESPACE
class QQmlEngine;
-class Q_QML_PRIVATE_EXPORT QQmlDirParser
+class Q_QMLCOMPILER_PRIVATE_EXPORT QQmlDirParser
{
public:
QQmlDirParser();
diff --git a/src/qml/qtqmlcompilerglobal.h b/src/qml/qtqmlcompilerglobal.h
new file mode 100644
index 0000000000..850d413372
--- /dev/null
+++ b/src/qml/qtqmlcompilerglobal.h
@@ -0,0 +1,58 @@
+/****************************************************************************
+**
+** 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 QTQMLCOMPILERGLOBAL_H
+#define QTQMLCOMPILERGLOBAL_H
+
+#include <QtCore/qglobal.h>
+
+QT_BEGIN_NAMESPACE
+
+#if defined(QT_BUILD_QMLDEVTOOLS_LIB) || defined(QT_QMLDEVTOOLS_LIB) || defined(QT_STATIC)
+# define Q_QMLCOMPILER_EXPORT
+#else
+# if defined(QT_BUILD_QML_LIB)
+# define Q_QMLCOMPILER_EXPORT Q_DECL_EXPORT
+# else
+# define Q_QMLCOMPILER_EXPORT Q_DECL_IMPORT
+# endif
+#endif
+
+QT_END_NAMESPACE
+#endif // QTQMLCOMPILERGLOBAL_H
diff --git a/src/qml/qtqmlcompilerglobal_p.h b/src/qml/qtqmlcompilerglobal_p.h
new file mode 100644
index 0000000000..9c8bce23d3
--- /dev/null
+++ b/src/qml/qtqmlcompilerglobal_p.h
@@ -0,0 +1,59 @@
+/****************************************************************************
+**
+** 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 QTQMLCOMPILERGLOBAL_P_H
+#define QTQMLCOMPILERGLOBAL_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 <qtqmlcompilerglobal.h>
+
+#define Q_QMLCOMPILER_PRIVATE_EXPORT Q_QMLCOMPILER_EXPORT
+
+#endif // QTQMLCOMPILERGLOBAL_P_H
diff --git a/src/qml/types/types.pri b/src/qml/types/types.pri
index c50273071b..54cd8710b6 100644
--- a/src/qml/types/types.pri
+++ b/src/qml/types/types.pri
@@ -1,12 +1,17 @@
SOURCES += \
$$PWD/qqmlbind.cpp \
- $$PWD/qqmlconnections.cpp \
- $$PWD/qqmlmodelindexvaluetype.cpp
+ $$PWD/qqmlconnections.cpp
HEADERS += \
$$PWD/qqmlbind_p.h \
- $$PWD/qqmlconnections_p.h \
- $$PWD/qqmlmodelindexvaluetype_p.h
+ $$PWD/qqmlconnections_p.h
+
+qtConfig(qml-itemmodel) {
+ SOURCES += \
+ $$PWD/qqmlmodelindexvaluetype.cpp
+ HEADERS += \
+ $$PWD/qqmlmodelindexvaluetype_p.h
+}
qtConfig(qml-animation) {
SOURCES += \
diff --git a/src/qmlmodels/configure.json b/src/qmlmodels/configure.json
index bfe7d538ec..2b4fa4f6e2 100644
--- a/src/qmlmodels/configure.json
+++ b/src/qmlmodels/configure.json
@@ -16,19 +16,21 @@
"label": "QML list model",
"purpose": "Provides the ListModel QML type.",
"section": "QML",
+ "condition": "features.qml-itemmodel",
"output": [ "privateFeature" ]
},
"qml-delegate-model": {
"label": "QML delegate model",
"purpose": "Provides the DelegateModel QML type.",
"section": "QML",
- "condition": "features.qml-object-model",
+ "condition": "features.qml-object-model && features.qml-itemmodel",
"output": [ "privateFeature" ]
},
"qml-table-model": {
"label": "QML table model",
"purpose": "Provides the TableModel QML type.",
"section": "QML",
+ "condition": "features.qml-itemmodel",
"output": [ "privateFeature" ]
}
},
diff --git a/src/qmlmodels/qqmladaptormodel.cpp b/src/qmlmodels/qqmladaptormodel.cpp
index 0bc67e1aad..48ff4e7d5b 100644
--- a/src/qmlmodels/qqmladaptormodel.cpp
+++ b/src/qmlmodels/qqmladaptormodel.cpp
@@ -161,8 +161,14 @@ public:
signalIndexes.append(propertyId + signalOffset);
}
- for (int i = 0, c = items.count(); i < c; ++i) {
- QQmlDelegateModelItem *item = items.at(i);
+ QVarLengthArray<QQmlGuard<QQmlDelegateModelItem>> guardedItems;
+ for (const auto item : items)
+ guardedItems.append(item);
+
+ for (const auto &item : qAsConst(guardedItems)) {
+ if (item.isNull())
+ continue;
+
const int idx = item->modelIndex();
if (idx >= index && idx < index + count) {
for (int i = 0; i < signalIndexes.count(); ++i)
diff --git a/src/qmlmodels/qqmllistmodel.cpp b/src/qmlmodels/qqmllistmodel.cpp
index c1684d955c..1cd089f454 100644
--- a/src/qmlmodels/qqmllistmodel.cpp
+++ b/src/qmlmodels/qqmllistmodel.cpp
@@ -53,6 +53,7 @@
#include <private/qv4objectiterator_p.h>
#include <private/qv4alloca_p.h>
#include <private/qv4lookup_p.h>
+#include <private/qv4qmlcontext_p.h>
#include <qqmlcontext.h>
#include <qqmlinfo.h>
diff --git a/src/qmltest/doc/qtqmltest.qdocconf b/src/qmltest/doc/qtqmltest.qdocconf
index 9a3e16b64d..25a7ae5f9b 100644
--- a/src/qmltest/doc/qtqmltest.qdocconf
+++ b/src/qmltest/doc/qtqmltest.qdocconf
@@ -1,4 +1,5 @@
include($QT_INSTALL_DOCS/global/qt-module-defaults.qdocconf)
+include($QT_INSTALL_DOCS/config/exampleurl-qtdeclarative.qdocconf)
project = QtQmlTest
description = Qt Quick Test Reference Documentation
diff --git a/src/quick/doc/qtquick.qdocconf b/src/quick/doc/qtquick.qdocconf
index 6620650d4a..13746b13de 100644
--- a/src/quick/doc/qtquick.qdocconf
+++ b/src/quick/doc/qtquick.qdocconf
@@ -1,4 +1,5 @@
include($QT_INSTALL_DOCS/global/qt-module-defaults.qdocconf)
+include($QT_INSTALL_DOCS/config/exampleurl-qtdeclarative.qdocconf)
project = QtQuick
description = Qt Quick Reference Documentation
diff --git a/src/quick/doc/snippets/qml/qml-extending-types/signals/Button.qml b/src/quick/doc/snippets/qml/qml-extending-types/signals/Button.qml
index b40f517234..96f7fc1c7c 100644
--- a/src/quick/doc/snippets/qml/qml-extending-types/signals/Button.qml
+++ b/src/quick/doc/snippets/qml/qml-extending-types/signals/Button.qml
@@ -55,7 +55,7 @@ Rectangle {
id: rect
width: 100; height: 100
- signal buttonClicked(int xPos, int yPos)
+ signal buttonClicked(xPos: int, yPos: int)
MouseArea {
anchors.fill: parent
diff --git a/src/quick/doc/src/concepts/effects/sprites.qdoc b/src/quick/doc/src/concepts/effects/sprites.qdoc
index 004db90eb3..159d9ca8a9 100644
--- a/src/quick/doc/src/concepts/effects/sprites.qdoc
+++ b/src/quick/doc/src/concepts/effects/sprites.qdoc
@@ -144,7 +144,7 @@ these situations, a warning will be output to the console containing the maximum
There are several tools to help turn a set of images into sprite sheets. Here are some examples:
\list
\li Photoshop plugin: \l http://www.johnwordsworth.com/projects/photoshop-sprite-sheet-generator-script
- \li Gimp plugin: \l http://registry.gimp.org/node/20943
+ \li Gimp's SpriteSheet plugin
\li Cmd-line tool: \l http://www.imagemagick.org/script/montage.php
\endlist
diff --git a/src/quick/items/qquickitemsmodule.cpp b/src/quick/items/qquickitemsmodule.cpp
index bc87b2c43f..15a417a8b4 100644
--- a/src/quick/items/qquickitemsmodule.cpp
+++ b/src/quick/items/qquickitemsmodule.cpp
@@ -477,9 +477,11 @@ static void qt_quickitems_defineModule(const char *uri, int major, int minor)
qmlRegisterType<QQuickTableView>(uri, 2, 12, "TableView");
#endif
+#if QT_CONFIG(quick_itemview)
qmlRegisterUncreatableType<QQuickItemView, 13>(uri, 2, 13, itemViewName, itemViewMessage);
qmlRegisterType<QQuickPathView, 13>(uri, 2, 13, "PathView");
qmlRegisterType<QQuickGridView, 13>(uri, 2, 13, "GridView");
+#endif
#if QT_CONFIG(quick_tableview)
qmlRegisterType<QQuickTableView, 14>(uri, 2, 14, "TableView");
#endif
diff --git a/src/quick/scenegraph/qsgopengldistancefieldglyphcache.cpp b/src/quick/scenegraph/qsgopengldistancefieldglyphcache.cpp
index 0f9ca66ad7..b6b6f3b057 100644
--- a/src/quick/scenegraph/qsgopengldistancefieldglyphcache.cpp
+++ b/src/quick/scenegraph/qsgopengldistancefieldglyphcache.cpp
@@ -69,7 +69,8 @@ DEFINE_BOOL_CONFIG_OPTION(qsgPreferFullSizeGlyphCacheTextures, QSG_PREFER_FULLSI
QSGOpenGLDistanceFieldGlyphCache::QSGOpenGLDistanceFieldGlyphCache(QOpenGLContext *c,
const QRawFont &font)
: QSGDistanceFieldGlyphCache(font)
- , m_maxTextureSize(0)
+ , m_maxTextureWidth(0)
+ , m_maxTextureHeight(0)
, m_maxTextureCount(3)
, m_areaAllocator(nullptr)
, m_blitProgram(nullptr)
@@ -113,13 +114,23 @@ void QSGOpenGLDistanceFieldGlyphCache::requestGlyphs(const QSet<glyph_t> &glyphs
QList<GlyphPosition> glyphPositions;
QVector<glyph_t> glyphsToRender;
+ const int padding = QSG_OPENGL_DISTANCEFIELD_GLYPH_CACHE_PADDING;
+ const qreal scaleFactor = qreal(1) / QT_DISTANCEFIELD_SCALE(m_doubleGlyphResolution);
+
+ if (m_maxTextureHeight == 0) {
+ m_funcs->glGetIntegerv(GL_MAX_TEXTURE_SIZE, &m_maxTextureWidth);
+
+ // We need to add a buffer to avoid glyphs that overlap the border between two
+ // textures causing the height of the textures to extend beyond the limit.
+ m_maxTextureHeight = m_maxTextureWidth - (qCeil(m_referenceFont.pixelSize() * scaleFactor) + distanceFieldRadius() * 2 + padding * 2);
+ }
+
if (m_areaAllocator == nullptr)
- m_areaAllocator = new QSGAreaAllocator(QSize(maxTextureSize(), m_maxTextureCount * maxTextureSize()));
+ m_areaAllocator = new QSGAreaAllocator(QSize(m_maxTextureWidth, m_maxTextureCount * m_maxTextureHeight));
for (QSet<glyph_t>::const_iterator it = glyphs.constBegin(); it != glyphs.constEnd() ; ++it) {
glyph_t glyphIndex = *it;
- int padding = QSG_OPENGL_DISTANCEFIELD_GLYPH_CACHE_PADDING;
QRectF boundingRect = glyphData(glyphIndex).boundingRect;
int glyphWidth = qCeil(boundingRect.width()) + distanceFieldRadius() * 2;
int glyphHeight = qCeil(boundingRect.height()) + distanceFieldRadius() * 2;
@@ -152,8 +163,8 @@ void QSGOpenGLDistanceFieldGlyphCache::requestGlyphs(const QSet<glyph_t> &glyphs
continue;
}
- TextureInfo *tex = textureInfo(alloc.y() / maxTextureSize());
- alloc = QRect(alloc.x(), alloc.y() % maxTextureSize(), alloc.width(), alloc.height());
+ TextureInfo *tex = textureInfo(alloc.y() / m_maxTextureHeight);
+ alloc = QRect(alloc.x(), alloc.y() % m_maxTextureHeight, alloc.width(), alloc.height());
tex->allocatedArea |= alloc;
Q_ASSERT(tex->padding == padding || tex->padding < 0);
@@ -541,13 +552,6 @@ bool QSGOpenGLDistanceFieldGlyphCache::createFullSizeTextures() const
return qsgPreferFullSizeGlyphCacheTextures() && glyphCount() > QT_DISTANCEFIELD_HIGHGLYPHCOUNT();
}
-int QSGOpenGLDistanceFieldGlyphCache::maxTextureSize() const
-{
- if (!m_maxTextureSize)
- m_funcs->glGetIntegerv(GL_MAX_TEXTURE_SIZE, &m_maxTextureSize);
- return m_maxTextureSize;
-}
-
namespace {
struct Qtdf {
// We need these structs to be tightly packed, but some compilers we use do not
@@ -646,7 +650,7 @@ bool QSGOpenGLDistanceFieldGlyphCache::loadPregeneratedCache(const QRawFont &fon
}
qreal pixelSize = qreal(Qtdf::fetch<quint16>(qtdfTableStart, Qtdf::pixelSize));
- m_maxTextureSize = Qtdf::fetch<quint32>(qtdfTableStart, Qtdf::textureSize);
+ m_maxTextureWidth = m_maxTextureHeight = Qtdf::fetch<quint32>(qtdfTableStart, Qtdf::textureSize);
m_doubleGlyphResolution = Qtdf::fetch<quint8>(qtdfTableStart, Qtdf::flags) == 1;
padding = Qtdf::fetch<quint8>(qtdfTableStart, Qtdf::headerPadding);
@@ -655,7 +659,7 @@ bool QSGOpenGLDistanceFieldGlyphCache::loadPregeneratedCache(const QRawFont &fon
return false;
}
- if (m_maxTextureSize <= 0) {
+ if (m_maxTextureWidth <= 0) {
qWarning("Invalid texture size in '%s'", qPrintable(font.familyName()));
return false;
}
@@ -663,11 +667,11 @@ bool QSGOpenGLDistanceFieldGlyphCache::loadPregeneratedCache(const QRawFont &fon
int systemMaxTextureSize;
m_funcs->glGetIntegerv(GL_MAX_TEXTURE_SIZE, &systemMaxTextureSize);
- if (m_maxTextureSize > systemMaxTextureSize) {
+ if (m_maxTextureWidth > systemMaxTextureSize) {
qWarning("System maximum texture size is %d. This is lower than the value in '%s', which is %d",
systemMaxTextureSize,
qPrintable(font.familyName()),
- m_maxTextureSize);
+ m_maxTextureWidth);
}
if (padding != QSG_OPENGL_DISTANCEFIELD_GLYPH_CACHE_PADDING) {
@@ -690,12 +694,12 @@ bool QSGOpenGLDistanceFieldGlyphCache::loadPregeneratedCache(const QRawFont &fon
return false;
}
- if (m_areaAllocator->size().height() % m_maxTextureSize != 0) {
+ if (m_areaAllocator->size().height() % m_maxTextureHeight != 0) {
qWarning("Area allocator size mismatch in '%s'", qPrintable(font.familyName()));
return false;
}
- textureCount = m_areaAllocator->size().height() / m_maxTextureSize;
+ textureCount = m_areaAllocator->size().height() / m_maxTextureHeight;
m_maxTextureCount = qMax(m_maxTextureCount, textureCount);
const char *textureRecord = allocatorData;
diff --git a/src/quick/scenegraph/qsgopengldistancefieldglyphcache_p.h b/src/quick/scenegraph/qsgopengldistancefieldglyphcache_p.h
index 99cfe27b9c..66d1b52f86 100644
--- a/src/quick/scenegraph/qsgopengldistancefieldglyphcache_p.h
+++ b/src/quick/scenegraph/qsgopengldistancefieldglyphcache_p.h
@@ -80,7 +80,6 @@ public:
bool useTextureResizeWorkaround() const;
bool useTextureUploadWorkaround() const;
bool createFullSizeTextures() const;
- int maxTextureSize() const;
void setMaxTextureCount(int max) { m_maxTextureCount = max; }
int maxTextureCount() const { return m_maxTextureCount; }
@@ -98,7 +97,7 @@ private:
QDistanceField image;
int padding = -1;
- TextureInfo(const QRect &preallocRect = QRect()) : texture(0), allocatedArea(preallocRect) { }
+ TextureInfo(const QRect &preallocRect = QRect(0, 0, 1, 1)) : texture(0), allocatedArea(preallocRect) { }
};
void createTexture(TextureInfo * texInfo, int width, int height, const void *pixels);
@@ -107,9 +106,10 @@ private:
TextureInfo *textureInfo(int index)
{
+ Q_ASSERT(m_maxTextureWidth > 0 && m_maxTextureHeight > 0);
for (int i = m_textures.count(); i <= index; ++i) {
if (createFullSizeTextures())
- m_textures.append(QRect(0, 0, maxTextureSize(), maxTextureSize()));
+ m_textures.append(QRect(0, 0, m_maxTextureWidth, m_maxTextureWidth));
else
m_textures.append(TextureInfo());
}
@@ -137,7 +137,8 @@ private:
m_blitProgram->link();
}
- mutable int m_maxTextureSize;
+ int m_maxTextureWidth;
+ int m_maxTextureHeight;
int m_maxTextureCount;
bool m_coreProfile;
diff --git a/src/quick/util/qquickpropertychanges.cpp b/src/quick/util/qquickpropertychanges.cpp
index d7c0157eee..1cb30f5a8d 100644
--- a/src/quick/util/qquickpropertychanges.cpp
+++ b/src/quick/util/qquickpropertychanges.cpp
@@ -51,6 +51,7 @@
#include <private/qqmlcontext_p.h>
#include <private/qquickstate_p_p.h>
#include <private/qqmlboundsignal_p.h>
+#include <private/qv4qmlcontext_p.h>
#include <QtCore/qdebug.h>