aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--dependencies.yaml7
-rw-r--r--examples/quick/tutorials/helloworld/Cell.qml2
-rw-r--r--src/imports/CMakeLists.txt5
-rw-r--r--src/imports/folderlistmodel/plugin.cpp3
-rw-r--r--src/imports/imports.pro4
-rw-r--r--src/imports/layouts/plugin.cpp3
-rw-r--r--src/imports/localstorage/plugin.cpp3
-rw-r--r--src/imports/models/plugin.cpp3
-rw-r--r--src/imports/particles/plugin.cpp3
-rw-r--r--src/imports/qtqml/plugin.cpp11
-rw-r--r--src/imports/qtqml/qmldir3
-rw-r--r--src/imports/qtquick2/plugin.cpp18
-rw-r--r--src/imports/qtquick2/qmldir1
-rw-r--r--src/imports/shapes/plugin.cpp3
-rw-r--r--src/imports/statemachine/plugin.cpp3
-rw-r--r--src/imports/testlib/main.cpp4
-rw-r--r--src/imports/wavefrontmesh/plugin.cpp3
-rw-r--r--src/imports/window/plugin.cpp3
-rw-r--r--src/imports/workerscript/plugin.cpp3
-rw-r--r--src/imports/workerscript/qmldir3
-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/.prev_CMakeLists.txt78
-rw-r--r--src/qml/CMakeLists.txt78
-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.cmake6
-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.g326
-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.cpp95
-rw-r--r--src/qml/qml/qqmldirdata_p.h86
-rw-r--r--src/qml/qml/qqmlengine.cpp45
-rw-r--r--src/qml/qml/qqmlengine_p.h4
-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.cpp843
-rw-r--r--src/qml/qml/qqmltypedata_p.h163
-rw-r--r--src/qml/qml/qqmltypeloader.cpp2300
-rw-r--r--src/qml/qml/qqmltypeloader_p.h436
-rw-r--r--src/qml/qml/qqmltypeloadernetworkreplyproxy.cpp74
-rw-r--r--src/qml/qml/qqmltypeloadernetworkreplyproxy_p.h86
-rw-r--r--src/qml/qml/qqmltypeloaderqmldircontent.cpp120
-rw-r--r--src/qml/qml/qqmltypeloaderqmldircontent_p.h95
-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.cpp12
-rw-r--r--src/qml/qmldirparser/qqmldirparser_p.h6
-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/qmldevtools/.prev_CMakeLists.txt32
-rw-r--r--src/qmldevtools/CMakeLists.txt32
-rw-r--r--src/qmlmodels/configure.cmake4
-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/qmlmodels/qqmlmodelsmodule.cpp43
-rw-r--r--src/qmlmodels/qqmlmodelsmodule_p.h5
-rw-r--r--src/qmltest/doc/qtqmltest.qdocconf1
-rw-r--r--src/qmlworkerscript/qqmlworkerscriptmodule.cpp11
-rw-r--r--src/qmlworkerscript/qqmlworkerscriptmodule_p.h3
-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.cpp5
-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
-rw-r--r--tests/auto/qml/qmlcachegen/tst_qmlcachegen.cpp1
-rw-r--r--tests/auto/qml/qmldiskcache/tst_qmldiskcache.cpp1
-rw-r--r--tests/auto/qml/qmllint/data/FromRoot.qml17
-rw-r--r--tests/auto/qml/qmllint/data/FromRootDirectParent.qml14
-rw-r--r--tests/auto/qml/qmllint/data/IdFromOuterSpace.qml9
-rw-r--r--tests/auto/qml/qmllint/data/SignalHandler.qml5
-rw-r--r--tests/auto/qml/qmllint/data/WithStatement.qml13
-rw-r--r--tests/auto/qml/qmllint/main.cpp45
-rw-r--r--tests/auto/qml/qqmlcomponent/tst_qqmlcomponent.cpp12
-rw-r--r--tests/auto/qml/qqmlconnections/tst_qqmlconnections.cpp2
-rw-r--r--tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp1
-rw-r--r--tests/auto/qml/qqmlengine/tst_qqmlengine.cpp1
-rw-r--r--tests/auto/qml/qqmllanguage/data/functionParameterTypes.qml7
-rw-r--r--tests/auto/qml/qqmllanguage/data/signalParameterTypes.3.qml19
-rw-r--r--tests/auto/qml/qqmllanguage/data/typeAnnotations.2.errors.txt1
-rw-r--r--tests/auto/qml/qqmllanguage/data/typeAnnotations.2.qml8
-rw-r--r--tests/auto/qml/qqmllanguage/testtypes.cpp2
-rw-r--r--tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp35
-rw-r--r--tests/auto/qml/qqmlmoduleplugin/tst_qqmlmoduleplugin.cpp2
-rw-r--r--tests/auto/qml/qqmlparser/data/disallowedtypeannotations/anonfunctionexpr.js3
-rw-r--r--tests/auto/qml/qqmlparser/data/disallowedtypeannotations/classmemberparam.js6
-rw-r--r--tests/auto/qml/qqmlparser/data/disallowedtypeannotations/classreturnvalue.js6
-rw-r--r--tests/auto/qml/qqmlparser/data/disallowedtypeannotations/function.js4
-rw-r--r--tests/auto/qml/qqmlparser/data/disallowedtypeannotations/functionexpr.js3
-rw-r--r--tests/auto/qml/qqmlparser/data/disallowedtypeannotations/functionparams.js3
-rw-r--r--tests/auto/qml/qqmlparser/data/disallowedtypeannotations/iteration.js3
-rw-r--r--tests/auto/qml/qqmlparser/data/disallowedtypeannotations/iteration2.js5
-rw-r--r--tests/auto/qml/qqmlparser/data/disallowedtypeannotations/qmlnestedfunction.qml9
-rw-r--r--tests/auto/qml/qqmlparser/data/disallowedtypeannotations/variables.js2
-rw-r--r--tests/auto/qml/qqmlparser/data/typeannotations/basic_qmltypes_bool.qml4
-rw-r--r--tests/auto/qml/qqmlparser/data/typeannotations/basic_qmltypes_double.qml4
-rw-r--r--tests/auto/qml/qqmlparser/data/typeannotations/basic_qmltypes_int.qml4
-rw-r--r--tests/auto/qml/qqmlparser/data/typeannotations/basic_qmltypes_real.qml4
-rw-r--r--tests/auto/qml/qqmlparser/data/typeannotations/basic_qmltypes_string.qml4
-rw-r--r--tests/auto/qml/qqmlparser/data/typeannotations/basic_qmltypes_url.qml4
-rw-r--r--tests/auto/qml/qqmlparser/data/typeannotations/parametrized.qml5
-rw-r--r--tests/auto/qml/qqmlparser/data/typeannotations/qmlfunction.qml6
-rw-r--r--tests/auto/qml/qqmlparser/qqmlparser.pro4
-rw-r--r--tests/auto/qml/qqmlparser/tst_qqmlparser.cpp108
-rw-r--r--tests/auto/qml/qqmltranslation/tst_qqmltranslation.cpp1
-rw-r--r--tests/auto/qml/qqmltypeloader/data/implicitimporttest.qml5
-rw-r--r--tests/auto/qml/qqmltypeloader/data/imports/modulewithimplicitimport/Test.qml3
-rw-r--r--tests/auto/qml/qqmltypeloader/data/imports/modulewithimplicitimport/qmldir2
-rw-r--r--tests/auto/qml/qqmltypeloader/data/qrcRootPath.qml4
-rw-r--r--tests/auto/qml/qqmltypeloader/tst_qqmltypeloader.cpp21
-rw-r--r--tests/auto/quick/drawingmodes/tst_drawingmodes.cpp7
-rw-r--r--tests/auto/quick/pointerhandlers/multipointtoucharea_interop/tst_multipointtoucharea_interop.cpp1
-rw-r--r--tests/auto/quick/qquickaccessible/tst_qquickaccessible.cpp2
-rw-r--r--tests/auto/quick/qquickfontloader_static/tst_qquickfontloader_static.cpp4
-rw-r--r--tests/auto/quick/qquickimage/tst_qquickimage.cpp2
-rw-r--r--tests/auto/quick/qquickimageprovider/tst_qquickimageprovider.cpp4
-rw-r--r--tests/auto/quick/qquicktableview/tst_qquicktableview.cpp1
-rw-r--r--tests/auto/quick/rendernode/tst_rendernode.cpp14
-rw-r--r--tests/auto/quick/scenegraph/tst_scenegraph.cpp8
-rw-r--r--tools/qmlcachegen/qmlcachegen.cpp11
-rw-r--r--tools/qmlcachegen/qtquickcompiler.prf10
-rw-r--r--tools/qmllint/.prev_CMakeLists.txt6
-rw-r--r--tools/qmllint/CMakeLists.txt6
-rw-r--r--tools/qmllint/componentversion.cpp123
-rw-r--r--tools/qmllint/componentversion.h73
-rw-r--r--tools/qmllint/fakemetaobject.cpp600
-rw-r--r--tools/qmllint/fakemetaobject.h236
-rw-r--r--tools/qmllint/findunqualified.cpp772
-rw-r--r--tools/qmllint/findunqualified.h129
-rw-r--r--tools/qmllint/main.cpp42
-rw-r--r--tools/qmllint/qcoloroutput.cpp342
-rw-r--r--tools/qmllint/qcoloroutput_p.h110
-rw-r--r--tools/qmllint/qmljstypedescriptionreader.cpp704
-rw-r--r--tools/qmllint/qmljstypedescriptionreader.h103
-rw-r--r--tools/qmllint/qmllint.pro16
-rw-r--r--tools/qmllint/scopetree.cpp255
-rw-r--r--tools/qmllint/scopetree.h105
241 files changed, 9569 insertions, 3868 deletions
diff --git a/dependencies.yaml b/dependencies.yaml
new file mode 100644
index 0000000000..ac5797762b
--- /dev/null
+++ b/dependencies.yaml
@@ -0,0 +1,7 @@
+dependencies:
+- ../qtbase.git:
+ ref: f955bd8ced8b93d142b7f755665946424c6d3644
+ required: true
+- ../qtsvg.git:
+ ref: 4b186657ef09634c082b03570624288cf7c1baba
+ required: false
diff --git a/examples/quick/tutorials/helloworld/Cell.qml b/examples/quick/tutorials/helloworld/Cell.qml
index 33b9bf9935..7462a5ceb1 100644
--- a/examples/quick/tutorials/helloworld/Cell.qml
+++ b/examples/quick/tutorials/helloworld/Cell.qml
@@ -58,7 +58,7 @@ Item {
property alias cellColor: rectangle.color
//![4]
//![5]
- signal clicked(color cellColor)
+ signal clicked(cellColor: color)
//![5]
width: 40; height: 25
diff --git a/src/imports/CMakeLists.txt b/src/imports/CMakeLists.txt
index 24f4494bd4..107bbdb139 100644
--- a/src/imports/CMakeLists.txt
+++ b/src/imports/CMakeLists.txt
@@ -4,7 +4,10 @@ add_subdirectory(builtins)
add_subdirectory(qtqml)
add_subdirectory(models)
add_subdirectory(labsmodels)
-add_subdirectory(folderlistmodel)
+
+if(QT_FEATURE_qml_itemmodel)
+ add_subdirectory(folderlistmodel)
+endif()
if(QT_FEATURE_qml_worker_script)
add_subdirectory(workerscript)
diff --git a/src/imports/folderlistmodel/plugin.cpp b/src/imports/folderlistmodel/plugin.cpp
index 31cd793737..40968d5e1d 100644
--- a/src/imports/folderlistmodel/plugin.cpp
+++ b/src/imports/folderlistmodel/plugin.cpp
@@ -60,8 +60,7 @@ public:
qmlRegisterType<QQuickFolderListModel,1>(uri,2,1,"FolderListModel");
qmlRegisterType<QQuickFolderListModel,2>(uri,2,2,"FolderListModel");
- // Auto-increment the import to stay in sync with ALL future QtQuick minor versions from 5.11 onward
- qmlRegisterModule(uri, 2, QT_VERSION_MINOR);
+ qmlRegisterModule(uri, 2, 15);
// revision in Qt 5.11: added status property
qmlRegisterType<QQuickFolderListModel,11>(uri, 2, 11, "FolderListModel");
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/layouts/plugin.cpp b/src/imports/layouts/plugin.cpp
index d28109c3cf..03a2c8fd00 100644
--- a/src/imports/layouts/plugin.cpp
+++ b/src/imports/layouts/plugin.cpp
@@ -67,8 +67,7 @@ public:
QStringLiteral("Do not create objects of type Layout"));
qmlRegisterRevision<QQuickGridLayoutBase, 1>(uri, 1, 1);
- // Auto-increment the import to stay in sync with ALL future QtQuick minor versions from 5.11 onward
- qmlRegisterModule(uri, 1, QT_VERSION_MINOR);
+ qmlRegisterModule(uri, 1, 15);
}
};
//![class decl]
diff --git a/src/imports/localstorage/plugin.cpp b/src/imports/localstorage/plugin.cpp
index 9004d1ee6f..740a394fa0 100644
--- a/src/imports/localstorage/plugin.cpp
+++ b/src/imports/localstorage/plugin.cpp
@@ -825,8 +825,7 @@ public:
Q_ASSERT(QLatin1String(uri) == QLatin1String("QtQuick.LocalStorage"));
qmlRegisterSingletonType<QQuickLocalStorage>(uri, 2, 0, "LocalStorage", module_api_factory);
- // Auto-increment the import to stay in sync with ALL future QtQuick minor versions from 5.11 onward
- qmlRegisterModule(uri, 2, QT_VERSION_MINOR);
+ qmlRegisterModule(uri, 2, 15);
}
};
diff --git a/src/imports/models/plugin.cpp b/src/imports/models/plugin.cpp
index 9fe63412f3..fd99f243b0 100644
--- a/src/imports/models/plugin.cpp
+++ b/src/imports/models/plugin.cpp
@@ -77,8 +77,7 @@ public:
Q_ASSERT(QLatin1String(uri) == QLatin1String("QtQml.Models"));
QQmlModelsModule::defineModule();
- // Auto-increment the import to stay in sync with ALL future QtQuick minor versions from 5.11 onward
- qmlRegisterModule(uri, 2, QT_VERSION_MINOR);
+ qmlRegisterModule(uri, 2, 15);
}
};
//![class decl]
diff --git a/src/imports/particles/plugin.cpp b/src/imports/particles/plugin.cpp
index 26fd979133..704eb0ffbe 100644
--- a/src/imports/particles/plugin.cpp
+++ b/src/imports/particles/plugin.cpp
@@ -56,8 +56,7 @@ public:
Q_ASSERT(QLatin1String(uri) == QLatin1String("QtQuick.Particles"));
QQuickParticlesModule::defineModule();
- // Auto-increment the import to stay in sync with ALL future QtQuick minor versions from 5.11 onward
- qmlRegisterModule(uri, 2, QT_VERSION_MINOR);
+ qmlRegisterModule(uri, 2, 15);
}
};
//![class decl]
diff --git a/src/imports/qtqml/plugin.cpp b/src/imports/qtqml/plugin.cpp
index 7595d6d65b..f63e04c3b9 100644
--- a/src/imports/qtqml/plugin.cpp
+++ b/src/imports/qtqml/plugin.cpp
@@ -42,10 +42,6 @@
#include <QtQml/private/qqmlcomponentattached_p.h>
#include <QtQml/private/qqmlbind_p.h>
-#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
-#include <QtQmlModels/private/qqmlmodelsmodule_p.h>
-#endif
-
QT_BEGIN_NAMESPACE
/*!
@@ -76,12 +72,7 @@ public:
Q_ASSERT(QLatin1String(uri) == QLatin1String("QtQml"));
QQmlEnginePrivate::defineModule();
-#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
- QQmlModelsModule::registerQmlTypes();
-#endif
-
- // Auto-increment the import to stay in sync with ALL future QtQml minor versions from 5.11 onward
- qmlRegisterModule(uri, 2, QT_VERSION_MINOR);
+ qmlRegisterModule(uri, 2, 15);
}
};
//![class decl]
diff --git a/src/imports/qtqml/qmldir b/src/imports/qtqml/qmldir
index f6b51c7970..a8adb2010d 100644
--- a/src/imports/qtqml/qmldir
+++ b/src/imports/qtqml/qmldir
@@ -2,3 +2,6 @@ module QtQml
plugin qmlplugin
classname QtQmlPlugin
typeinfo plugins.qmltypes
+import QtQml.Models
+import QtQml.WorkerScript
+designersupported
diff --git a/src/imports/qtquick2/plugin.cpp b/src/imports/qtquick2/plugin.cpp
index 6b44f782bd..1b14e9f0e5 100644
--- a/src/imports/qtquick2/plugin.cpp
+++ b/src/imports/qtquick2/plugin.cpp
@@ -40,14 +40,6 @@
#include <QtQml/qqmlextensionplugin.h>
#include <QtQml/QQmlEngine>
-#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
-#include <QtQml/private/qqmlengine_p.h>
-#include <QtQmlModels/private/qqmlmodelsmodule_p.h>
-#if QT_CONFIG(qml_worker_script)
-#include <QtQmlWorkerScript/private/qqmlworkerscriptmodule_p.h>
-#endif
-#endif // QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
-
#include <private/qtquick2_p.h>
QT_BEGIN_NAMESPACE
@@ -64,17 +56,9 @@ public:
Q_ASSERT(QLatin1String(uri) == QLatin1String("QtQuick"));
Q_UNUSED(uri);
moduleDefined = true;
-#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
- QQmlEnginePrivate::registerQuickTypes();
- QQmlModelsModule::registerQuickTypes();
-#if QT_CONFIG(qml_worker_script)
- QQmlWorkerScriptModule::registerQuickTypes();
-#endif
-#endif
QQmlQtQuick2Module::defineModule();
- // Auto-increment the import to stay in sync with ALL future QtQuick minor versions from 5.11 onward
- qmlRegisterModule("QtQuick", 2, QT_VERSION_MINOR);
+ qmlRegisterModule("QtQuick", 2, 15);
}
~QtQuick2Plugin() override
diff --git a/src/imports/qtquick2/qmldir b/src/imports/qtquick2/qmldir
index 8167e813df..d74aabd9e9 100644
--- a/src/imports/qtquick2/qmldir
+++ b/src/imports/qtquick2/qmldir
@@ -3,3 +3,4 @@ plugin qtquick2plugin
classname QtQuick2Plugin
typeinfo plugins.qmltypes
designersupported
+import QtQml
diff --git a/src/imports/shapes/plugin.cpp b/src/imports/shapes/plugin.cpp
index 0679a70630..6197b2fdf5 100644
--- a/src/imports/shapes/plugin.cpp
+++ b/src/imports/shapes/plugin.cpp
@@ -64,8 +64,7 @@ public:
qmlRegisterType<QQuickShapeRadialGradient>(uri, 1, 0, "RadialGradient");
qmlRegisterType<QQuickShapeConicalGradient>(uri, 1, 0, "ConicalGradient");
- // Auto-increment the import to stay in sync with ALL future QtQuick minor versions
- qmlRegisterModule(uri, 1, QT_VERSION_MINOR);
+ qmlRegisterModule(uri, 1, 15);
// revision in Qt 5.11: added containsMode property
qmlRegisterType<QQuickShape, 11>(uri, 1, 11, "Shape");
diff --git a/src/imports/statemachine/plugin.cpp b/src/imports/statemachine/plugin.cpp
index bf7499b31a..0ec2c353fc 100644
--- a/src/imports/statemachine/plugin.cpp
+++ b/src/imports/statemachine/plugin.cpp
@@ -69,8 +69,7 @@ public:
qmlRegisterType<TimeoutTransition>(uri, 1, 0, "TimeoutTransition");
qmlProtectModule(uri, 1);
- // Auto-increment the import to stay in sync with ALL future QtQuick minor versions from 5.11 onward
- qmlRegisterModule(uri, 1, QT_VERSION_MINOR);
+ qmlRegisterModule(uri, 1, 15);
}
};
diff --git a/src/imports/testlib/main.cpp b/src/imports/testlib/main.cpp
index 7b931c25d2..c5873c1058 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>
@@ -151,8 +152,7 @@ public:
qmlRegisterType<QuickTestUtil>(uri,1,0,"TestUtil");
qmlRegisterType<QQuickTouchEventSequence>();
- // Auto-increment the import to stay in sync with ALL future QtQuick minor versions from 5.11 onward
- qmlRegisterModule(uri, 1, QT_VERSION_MINOR);
+ qmlRegisterModule(uri, 1, 15);
}
};
diff --git a/src/imports/wavefrontmesh/plugin.cpp b/src/imports/wavefrontmesh/plugin.cpp
index 1a266b7e36..c695b5d19c 100644
--- a/src/imports/wavefrontmesh/plugin.cpp
+++ b/src/imports/wavefrontmesh/plugin.cpp
@@ -59,8 +59,7 @@ public:
Q_ASSERT(QLatin1String(uri) == QLatin1String("Qt.labs.wavefrontmesh"));
qmlRegisterType<QWavefrontMesh>(uri, 1, 0, "WavefrontMesh");
- // Auto-increment the import to stay in sync with ALL future QtQuick minor versions from 5.12 onward
- qmlRegisterModule(uri, 1, QT_VERSION_MINOR);
+ qmlRegisterModule(uri, 1, 15);
}
};
diff --git a/src/imports/window/plugin.cpp b/src/imports/window/plugin.cpp
index dfe1dcf62e..a331708e87 100644
--- a/src/imports/window/plugin.cpp
+++ b/src/imports/window/plugin.cpp
@@ -71,8 +71,7 @@ public:
Q_ASSERT(QLatin1String(uri) == QLatin1String("QtQuick.Window"));
QQuickWindowModule::defineModule();
- // Auto-increment the import to stay in sync with ALL future QtQuick minor versions from 5.11 onward
- qmlRegisterModule(uri, 2, QT_VERSION_MINOR);
+ qmlRegisterModule(uri, 2, 15);
}
};
//![class decl]
diff --git a/src/imports/workerscript/plugin.cpp b/src/imports/workerscript/plugin.cpp
index 5b3bff7934..2d8797db7e 100644
--- a/src/imports/workerscript/plugin.cpp
+++ b/src/imports/workerscript/plugin.cpp
@@ -71,8 +71,7 @@ public:
QQmlWorkerScriptModule::defineModule();
- // Auto-increment the import to stay in sync with ALL future QtQuick minor versions from 5.11 onward
- qmlRegisterModule(uri, 2, QT_VERSION_MINOR);
+ qmlRegisterModule(uri, 2, 15);
}
};
diff --git a/src/imports/workerscript/qmldir b/src/imports/workerscript/qmldir
index 0e811d1dbc..02ff9ea188 100644
--- a/src/imports/workerscript/qmldir
+++ b/src/imports/workerscript/qmldir
@@ -1,3 +1,4 @@
module QtQml.WorkerScript
-plugin workerscriptsplugin
+plugin workerscriptplugin
classname QtQmlWorkerScriptPlugin
+designersupported
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/.prev_CMakeLists.txt b/src/qml/.prev_CMakeLists.txt
index ca1e879b8f..dbebb9a0ba 100644
--- a/src/qml/.prev_CMakeLists.txt
+++ b/src/qml/.prev_CMakeLists.txt
@@ -67,20 +67,23 @@ add_qt_module(Qml
../3rdparty/masm/yarr/YarrUnicodeProperties.h
common/qqmlapiversion_p.h
common/qqmljsdiagnosticmessage_p.h
+ common/qqmljsfixedpoolarray_p.h
+ common/qqmljsmemorypool_p.h
+ common/qv4alloca_p.h
+ common/qv4calldata_p.h
+ common/qv4compileddata_p.h
+ common/qv4staticvalue_p.h
+ common/qv4stringtoarrayindex_p.h
compiler/qqmlirbuilder.cpp compiler/qqmlirbuilder_p.h
- compiler/qv4alloca_p.h
compiler/qv4bytecodegenerator.cpp compiler/qv4bytecodegenerator_p.h
compiler/qv4bytecodehandler.cpp compiler/qv4bytecodehandler_p.h
- compiler/qv4calldata_p.h
compiler/qv4codegen.cpp compiler/qv4codegen_p.h
- compiler/qv4compileddata_p.h
compiler/qv4compiler.cpp compiler/qv4compiler_p.h
compiler/qv4compilercontext.cpp compiler/qv4compilercontext_p.h
compiler/qv4compilercontrolflow_p.h
+ compiler/qv4compilerglobal_p.h
compiler/qv4compilerscanfunctions.cpp compiler/qv4compilerscanfunctions_p.h
compiler/qv4instr_moth.cpp compiler/qv4instr_moth_p.h
- compiler/qv4staticvalue_p.h
- compiler/qv4stringtoarrayindex_p.h
compiler/qv4util_p.h
debugger/qqmldebug.h
debugger/qqmldebugconnector_p.h
@@ -170,10 +173,9 @@ add_qt_module(Qml
parser/qqmljsastfwd_p.h
parser/qqmljsastvisitor.cpp parser/qqmljsastvisitor_p.h
parser/qqmljsengine_p.cpp parser/qqmljsengine_p.h parser/qqmljsengine_p.h
- parser/qqmljsglobal_p.h parser/qqmljsglobal_p.h
+ parser/qqmljsglobal_p.h
parser/qqmljskeywords_p.h
parser/qqmljslexer.cpp parser/qqmljslexer_p.h
- parser/qqmljsmemorypool_p.h
parser/qqmljssourcelocation_p.h
qml/ftw/qbitfield_p.h
qml/ftw/qfieldlist_p.h
@@ -204,11 +206,13 @@ add_qt_module(Qml
qml/qqmlcontext.cpp qml/qqmlcontext.h qml/qqmlcontext_p.h
qml/qqmlcustomparser.cpp qml/qqmlcustomparser_p.h
qml/qqmldata_p.h
+ qml/qqmldatablob.cpp qml/qqmldatablob_p.h
qml/qqmldelayedcallqueue.cpp qml/qqmldelayedcallqueue_p.h
+ qml/qqmldirdata.cpp qml/qqmldirdata_p.h
qml/qqmlengine.cpp qml/qqmlengine.h qml/qqmlengine_p.h
qml/qqmlenumdata_p.h
qml/qqmlenumvalue_p.h
- qml/qqmlerror.cpp
+ qml/qqmlerror.cpp qml/qqmlerror.h
qml/qqmlexpression.cpp qml/qqmlexpression.h qml/qqmlexpression_p.h
qml/qqmlextensioninterface.h
qml/qqmlextensionplugin.cpp qml/qqmlextensionplugin.h qml/qqmlextensionplugin_p.h
@@ -247,6 +251,8 @@ add_qt_module(Qml
qml/qqmlpropertyvalueinterceptor.cpp qml/qqmlpropertyvalueinterceptor_p.h
qml/qqmlpropertyvaluesource.cpp qml/qqmlpropertyvaluesource.h
qml/qqmlproxymetaobject.cpp qml/qqmlproxymetaobject_p.h
+ qml/qqmlscriptblob.cpp qml/qqmlscriptblob_p.h
+ qml/qqmlscriptdata.cpp qml/qqmlscriptdata_p.h
qml/qqmlscriptstring.cpp qml/qqmlscriptstring.h qml/qqmlscriptstring_p.h
qml/qqmlsourcecoordinate_p.h
qml/qqmlstaticmetaobject.cpp qml/qqmlstaticmetaobject_p.h
@@ -254,7 +260,10 @@ add_qt_module(Qml
qml/qqmltype.cpp qml/qqmltype_p.h
qml/qqmltype_p_p.h
qml/qqmltypecompiler.cpp qml/qqmltypecompiler_p.h
+ qml/qqmltypedata.cpp qml/qqmltypedata_p.h
qml/qqmltypeloader.cpp qml/qqmltypeloader_p.h
+ qml/qqmltypeloaderqmldircontent.cpp qml/qqmltypeloaderqmldircontent_p.h
+ qml/qqmltypeloaderthread.cpp qml/qqmltypeloaderthread_p.h
qml/qqmltypemodule.cpp qml/qqmltypemodule_p.h
qml/qqmltypemodule_p_p.h
qml/qqmltypemoduleversion.cpp qml/qqmltypemoduleversion_p.h
@@ -270,10 +279,10 @@ add_qt_module(Qml
qml/v8/qv4domerrors.cpp qml/v8/qv4domerrors_p.h
qml/v8/qv4sqlerrors.cpp qml/v8/qv4sqlerrors_p.h
qmldirparser/qqmldirparser.cpp qmldirparser/qqmldirparser_p.h
+ qtqmlcompilerglobal.h qtqmlcompilerglobal_p.h
qtqmlglobal.h qtqmlglobal_p.h
types/qqmlbind.cpp types/qqmlbind_p.h
types/qqmlconnections.cpp types/qqmlconnections_p.h
- types/qqmlmodelindexvaluetype.cpp types/qqmlmodelindexvaluetype_p.h
util/qqmlpropertymap.cpp util/qqmlpropertymap.h
DEFINES
BUILDING_QT__
@@ -328,6 +337,8 @@ add_qt_module(Qml
#####################################################################
extend_target(Qml CONDITION QT_FEATURE_qml_network
+ SOURCES
+ qml/qqmltypeloadernetworkreplyproxy.cpp qml/qqmltypeloadernetworkreplyproxy_p.h
PUBLIC_LIBRARIES
Qt::Network
)
@@ -357,22 +368,6 @@ extend_target(Qml CONDITION GCC AND (TEST_architecture_arch STREQUAL "mips")
-fno-reorder-blocks
)
-#### Keys ignored in scope 8:.:.:qml.pro:NOT build_pass:
-# 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)"
-# tag = <EMPTY>
-# tagFile = "$$PWD/../../.tag"
-
-#### Keys ignored in scope 9:.:.:qml.pro:EXISTS _ss_tagFile:
-# QMAKE_INTERNAL_INCLUDED_FILES = "$$tagFile"
-# tag = "$$cat$$tagFile,singleline"
-
-#### Keys ignored in scope 10:.:.:qml.pro:NOT tag___equals____ss_{LITERAL_DOLLAR}Format AND %H_ss_{LITERAL_DOLLAR}:
-# QML_COMPILE_HASH = "$$tag"
-
-#### Keys ignored in scope 12:.:.:qml.pro:EXISTS _ss_PWD/../../.git:
-# QML_COMPILE_HASH = "$$commit"
-# commit = "$$systemgitrev-parseHEAD"
-
extend_target(Qml CONDITION EXISTS "qqml_enable_gcov"
LIBRARIES
gcov
@@ -387,10 +382,10 @@ extend_target(Qml CONDITION release AND MSVC AND QT_CL_MAJOR_VERSION___equals___
-d2SSAOptimizer-
)
-#### Keys ignored in scope 16:.:.:qml.pro:ICC:
+#### Keys ignored in scope 10:.:.:qml.pro:ICC:
# WERROR = "-ww2415"
-#### Keys ignored in scope 17:.:.:qml.pro:greaterThan(QT_CLANG_MAJOR_VERSION,3) OR greaterThan(QT_CLANG_MINOR_VERSION,3) OR greaterThan(QT_APPLE_CLANG_MAJOR_VERSION,5) OR QT_APPLE_CLANG_MAJOR_VERSION___equals___5 AND greaterThan(QT_APPLE_CLANG_MINOR_VERSION,0):
+#### Keys ignored in scope 11:.:.:qml.pro:greaterThan(QT_CLANG_MAJOR_VERSION,3) OR greaterThan(QT_CLANG_MINOR_VERSION,3) OR greaterThan(QT_APPLE_CLANG_MAJOR_VERSION,5) OR QT_APPLE_CLANG_MAJOR_VERSION___equals___5 AND greaterThan(QT_APPLE_CLANG_MINOR_VERSION,0):
# WERROR = "-Wno-error=unused-const-variable"
extend_target(Qml CONDITION QT_FEATURE_qml_jit
@@ -417,6 +412,22 @@ extend_target(Qml CONDITION QT_FEATURE_qml_animation
animations
)
+#### Keys ignored in scope 17:.:common:common/common.pri:NOT build_pass:
+# 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)"
+# tag = <EMPTY>
+# tagFile = "$$PWD/../../.tag"
+
+#### Keys ignored in scope 18:.:common:common/common.pri:EXISTS _ss_tagFile:
+# QMAKE_INTERNAL_INCLUDED_FILES = "$$tagFile"
+# tag = "$$cat$$tagFile,singleline"
+
+#### Keys ignored in scope 19:.:common:common/common.pri:NOT tag___equals____ss_{LITERAL_DOLLAR}Format AND %H_ss_{LITERAL_DOLLAR}:
+# QML_COMPILE_HASH = "$$tag"
+
+#### Keys ignored in scope 21:.:common:common/common.pri:EXISTS _ss_PWD/../../.git:
+# QML_COMPILE_HASH = "$$commit"
+# commit = "$$systemgitrev-parseHEAD"
+
extend_target(Qml CONDITION (GCC) AND ((QT_COMPILER_VERSION_MAJOR STREQUAL 5))
COMPILE_OPTIONS
-fno-strict-aliasing
@@ -492,6 +503,11 @@ extend_target(Qml CONDITION QT_FEATURE_clock_gettime AND linux-_x_ OR hpux-_x_ O
rt
)
+extend_target(Qml CONDITION QT_FEATURE_qml_itemmodel
+ SOURCES
+ types/qqmlmodelindexvaluetype.cpp types/qqmlmodelindexvaluetype_p.h
+)
+
extend_target(Qml CONDITION (disassembler) AND ((TEST_architecture_arch STREQUAL "i386")" OR isEqual(QT_ARCH,"x86_64))
DEFINES
WTF_USE_UDIS86=1
@@ -527,7 +543,7 @@ extend_target(Qml CONDITION (NOT ICC AND NOT CLANG AND GCC) AND ((QT_COMPILER_VE
-Wno-expansion-to-defined
)
-#### Keys ignored in scope 62:.:../3rdparty/masm:../3rdparty/masm/masm-defs.pri:(QT_COMPILER_VERSION_MAJOR STRGREATER 6):
+#### Keys ignored in scope 64:.:../3rdparty/masm:../3rdparty/masm/masm-defs.pri:(QT_COMPILER_VERSION_MAJOR STRGREATER 6):
# QMAKE_CXXFLAGS_WARN_ON = "-Wno-expansion-to-defined"
extend_target(Qml CONDITION WINRT
@@ -556,7 +572,7 @@ extend_target(Qml CONDITION DEFINES___contains___WTF_USE_UDIS86=1
../3rdparty/masm/disassembler/udis86/udis86_syn-intel.c
)
-#### Keys ignored in scope 70:.:../3rdparty/masm:../3rdparty/masm/masm.pri:DEFINES___contains___WTF_USE_UDIS86=1:
+#### Keys ignored in scope 72:.:../3rdparty/masm:../3rdparty/masm/masm.pri:DEFINES___contains___WTF_USE_UDIS86=1:
# ITAB = "$$PWD/disassembler/udis86/optable.xml"
# QMAKE_EXTRA_COMPILERS = "udis86"
# QMAKE_EXTRA_TARGETS = "udis86_tab_cfile"
@@ -567,10 +583,10 @@ extend_target(Qml CONDITION DEFINES___contains___WTF_USE_UDIS86=1
# udis86_tab_cfile.depends = "udis86_itab.h"
# udis86_tab_cfile.target = "$$OUT_PWD/udis86_itab.c"
-#### Keys ignored in scope 72:.:../3rdparty/masm:../3rdparty/masm/masm.pri:(CMAKE_BUILD_TYPE STREQUAL Debug):
+#### Keys ignored in scope 74:.:../3rdparty/masm:../3rdparty/masm/masm.pri:(CMAKE_BUILD_TYPE STREQUAL Debug):
# GENERATEDDIR = "$$GENERATEDDIR/debug"
-#### Keys ignored in scope 73:.:../3rdparty/masm:../3rdparty/masm/masm.pri:else:
+#### Keys ignored in scope 75:.:../3rdparty/masm:../3rdparty/masm/masm.pri:else:
# GENERATEDDIR = "$$GENERATEDDIR/release"
extend_target(Qml CONDITION (NOT c++11 AND NOT ICC) AND (CLANG)
diff --git a/src/qml/CMakeLists.txt b/src/qml/CMakeLists.txt
index 7302099c7c..f83f98ed3a 100644
--- a/src/qml/CMakeLists.txt
+++ b/src/qml/CMakeLists.txt
@@ -67,20 +67,23 @@ add_qt_module(Qml
../3rdparty/masm/yarr/YarrUnicodeProperties.h
common/qqmlapiversion_p.h
common/qqmljsdiagnosticmessage_p.h
+ common/qqmljsfixedpoolarray_p.h
+ common/qqmljsmemorypool_p.h
+ common/qv4alloca_p.h
+ common/qv4calldata_p.h
+ common/qv4compileddata_p.h
+ common/qv4staticvalue_p.h
+ common/qv4stringtoarrayindex_p.h
compiler/qqmlirbuilder.cpp compiler/qqmlirbuilder_p.h
- compiler/qv4alloca_p.h
compiler/qv4bytecodegenerator.cpp compiler/qv4bytecodegenerator_p.h
compiler/qv4bytecodehandler.cpp compiler/qv4bytecodehandler_p.h
- compiler/qv4calldata_p.h
compiler/qv4codegen.cpp compiler/qv4codegen_p.h
- compiler/qv4compileddata_p.h
compiler/qv4compiler.cpp compiler/qv4compiler_p.h
compiler/qv4compilercontext.cpp compiler/qv4compilercontext_p.h
compiler/qv4compilercontrolflow_p.h
+ compiler/qv4compilerglobal_p.h
compiler/qv4compilerscanfunctions.cpp compiler/qv4compilerscanfunctions_p.h
compiler/qv4instr_moth.cpp compiler/qv4instr_moth_p.h
- compiler/qv4staticvalue_p.h
- compiler/qv4stringtoarrayindex_p.h
compiler/qv4util_p.h
debugger/qqmldebug.h
debugger/qqmldebugconnector_p.h
@@ -170,10 +173,9 @@ add_qt_module(Qml
parser/qqmljsastfwd_p.h
parser/qqmljsastvisitor.cpp parser/qqmljsastvisitor_p.h
parser/qqmljsengine_p.cpp parser/qqmljsengine_p.h parser/qqmljsengine_p.h
- parser/qqmljsglobal_p.h parser/qqmljsglobal_p.h
+ parser/qqmljsglobal_p.h
parser/qqmljskeywords_p.h
parser/qqmljslexer.cpp parser/qqmljslexer_p.h
- parser/qqmljsmemorypool_p.h
parser/qqmljssourcelocation_p.h
qml/ftw/qbitfield_p.h
qml/ftw/qfieldlist_p.h
@@ -204,11 +206,13 @@ add_qt_module(Qml
qml/qqmlcontext.cpp qml/qqmlcontext.h qml/qqmlcontext_p.h
qml/qqmlcustomparser.cpp qml/qqmlcustomparser_p.h
qml/qqmldata_p.h
+ qml/qqmldatablob.cpp qml/qqmldatablob_p.h
qml/qqmldelayedcallqueue.cpp qml/qqmldelayedcallqueue_p.h
+ qml/qqmldirdata.cpp qml/qqmldirdata_p.h
qml/qqmlengine.cpp qml/qqmlengine.h qml/qqmlengine_p.h
qml/qqmlenumdata_p.h
qml/qqmlenumvalue_p.h
- qml/qqmlerror.cpp
+ qml/qqmlerror.cpp qml/qqmlerror.h
qml/qqmlexpression.cpp qml/qqmlexpression.h qml/qqmlexpression_p.h
qml/qqmlextensioninterface.h
qml/qqmlextensionplugin.cpp qml/qqmlextensionplugin.h qml/qqmlextensionplugin_p.h
@@ -247,6 +251,8 @@ add_qt_module(Qml
qml/qqmlpropertyvalueinterceptor.cpp qml/qqmlpropertyvalueinterceptor_p.h
qml/qqmlpropertyvaluesource.cpp qml/qqmlpropertyvaluesource.h
qml/qqmlproxymetaobject.cpp qml/qqmlproxymetaobject_p.h
+ qml/qqmlscriptblob.cpp qml/qqmlscriptblob_p.h
+ qml/qqmlscriptdata.cpp qml/qqmlscriptdata_p.h
qml/qqmlscriptstring.cpp qml/qqmlscriptstring.h qml/qqmlscriptstring_p.h
qml/qqmlsourcecoordinate_p.h
qml/qqmlstaticmetaobject.cpp qml/qqmlstaticmetaobject_p.h
@@ -254,7 +260,10 @@ add_qt_module(Qml
qml/qqmltype.cpp qml/qqmltype_p.h
qml/qqmltype_p_p.h
qml/qqmltypecompiler.cpp qml/qqmltypecompiler_p.h
+ qml/qqmltypedata.cpp qml/qqmltypedata_p.h
qml/qqmltypeloader.cpp qml/qqmltypeloader_p.h
+ qml/qqmltypeloaderqmldircontent.cpp qml/qqmltypeloaderqmldircontent_p.h
+ qml/qqmltypeloaderthread.cpp qml/qqmltypeloaderthread_p.h
qml/qqmltypemodule.cpp qml/qqmltypemodule_p.h
qml/qqmltypemodule_p_p.h
qml/qqmltypemoduleversion.cpp qml/qqmltypemoduleversion_p.h
@@ -270,10 +279,10 @@ add_qt_module(Qml
qml/v8/qv4domerrors.cpp qml/v8/qv4domerrors_p.h
qml/v8/qv4sqlerrors.cpp qml/v8/qv4sqlerrors_p.h
qmldirparser/qqmldirparser.cpp qmldirparser/qqmldirparser_p.h
+ qtqmlcompilerglobal.h qtqmlcompilerglobal_p.h
qtqmlglobal.h qtqmlglobal_p.h
types/qqmlbind.cpp types/qqmlbind_p.h
types/qqmlconnections.cpp types/qqmlconnections_p.h
- types/qqmlmodelindexvaluetype.cpp types/qqmlmodelindexvaluetype_p.h
util/qqmlpropertymap.cpp util/qqmlpropertymap.h
DEFINES
BUILDING_QT__
@@ -335,6 +344,8 @@ qt_declarative_generate_reg_exp_jit_tables(Qml)
#####################################################################
extend_target(Qml CONDITION QT_FEATURE_qml_network
+ SOURCES
+ qml/qqmltypeloadernetworkreplyproxy.cpp qml/qqmltypeloadernetworkreplyproxy_p.h
PUBLIC_LIBRARIES
Qt::Network
)
@@ -364,22 +375,6 @@ extend_target(Qml CONDITION GCC AND (TEST_architecture_arch STREQUAL "mips")
-fno-reorder-blocks
)
-#### Keys ignored in scope 8:.:.:qml.pro:NOT build_pass:
-# 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)"
-# tag = <EMPTY>
-# tagFile = "$$PWD/../../.tag"
-
-#### Keys ignored in scope 9:.:.:qml.pro:EXISTS _ss_tagFile:
-# QMAKE_INTERNAL_INCLUDED_FILES = "$$tagFile"
-# tag = "$$cat$$tagFile,singleline"
-
-#### Keys ignored in scope 10:.:.:qml.pro:NOT tag___equals____ss_{LITERAL_DOLLAR}Format AND %H_ss_{LITERAL_DOLLAR}:
-# QML_COMPILE_HASH = "$$tag"
-
-#### Keys ignored in scope 12:.:.:qml.pro:EXISTS _ss_PWD/../../.git:
-# QML_COMPILE_HASH = "$$commit"
-# commit = "$$systemgitrev-parseHEAD"
-
extend_target(Qml CONDITION EXISTS "qqml_enable_gcov"
LIBRARIES
gcov
@@ -394,10 +389,10 @@ extend_target(Qml CONDITION release AND MSVC AND QT_CL_MAJOR_VERSION___equals___
-d2SSAOptimizer-
)
-#### Keys ignored in scope 16:.:.:qml.pro:ICC:
+#### Keys ignored in scope 10:.:.:qml.pro:ICC:
# WERROR = "-ww2415"
-#### Keys ignored in scope 17:.:.:qml.pro:greaterThan(QT_CLANG_MAJOR_VERSION,3) OR greaterThan(QT_CLANG_MINOR_VERSION,3) OR greaterThan(QT_APPLE_CLANG_MAJOR_VERSION,5) OR QT_APPLE_CLANG_MAJOR_VERSION___equals___5 AND greaterThan(QT_APPLE_CLANG_MINOR_VERSION,0):
+#### Keys ignored in scope 11:.:.:qml.pro:greaterThan(QT_CLANG_MAJOR_VERSION,3) OR greaterThan(QT_CLANG_MINOR_VERSION,3) OR greaterThan(QT_APPLE_CLANG_MAJOR_VERSION,5) OR QT_APPLE_CLANG_MAJOR_VERSION___equals___5 AND greaterThan(QT_APPLE_CLANG_MINOR_VERSION,0):
# WERROR = "-Wno-error=unused-const-variable"
extend_target(Qml CONDITION QT_FEATURE_qml_jit
@@ -424,6 +419,22 @@ extend_target(Qml CONDITION QT_FEATURE_qml_animation
animations
)
+#### Keys ignored in scope 17:.:common:common/common.pri:NOT build_pass:
+# 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)"
+# tag = <EMPTY>
+# tagFile = "$$PWD/../../.tag"
+
+#### Keys ignored in scope 18:.:common:common/common.pri:EXISTS _ss_tagFile:
+# QMAKE_INTERNAL_INCLUDED_FILES = "$$tagFile"
+# tag = "$$cat$$tagFile,singleline"
+
+#### Keys ignored in scope 19:.:common:common/common.pri:NOT tag___equals____ss_{LITERAL_DOLLAR}Format AND %H_ss_{LITERAL_DOLLAR}:
+# QML_COMPILE_HASH = "$$tag"
+
+#### Keys ignored in scope 21:.:common:common/common.pri:EXISTS _ss_PWD/../../.git:
+# QML_COMPILE_HASH = "$$commit"
+# commit = "$$systemgitrev-parseHEAD"
+
extend_target(Qml CONDITION (GCC) AND ((QT_COMPILER_VERSION_MAJOR STREQUAL 5))
COMPILE_OPTIONS
-fno-strict-aliasing
@@ -499,6 +510,11 @@ extend_target(Qml CONDITION QT_FEATURE_clock_gettime AND linux-_x_ OR hpux-_x_ O
rt
)
+extend_target(Qml CONDITION QT_FEATURE_qml_itemmodel
+ SOURCES
+ types/qqmlmodelindexvaluetype.cpp types/qqmlmodelindexvaluetype_p.h
+)
+
extend_target(Qml CONDITION (disassembler) AND ((TEST_architecture_arch STREQUAL "i386") OR (TEST_architecture_arch STREQUAL "x86_64")) # special case
DEFINES
WTF_USE_UDIS86=1
@@ -534,7 +550,7 @@ extend_target(Qml CONDITION (NOT ICC AND NOT CLANG AND GCC) AND ((QT_COMPILER_VE
-Wno-expansion-to-defined
)
-#### Keys ignored in scope 62:.:../3rdparty/masm:../3rdparty/masm/masm-defs.pri:(QT_COMPILER_VERSION_MAJOR STRGREATER 6):
+#### Keys ignored in scope 64:.:../3rdparty/masm:../3rdparty/masm/masm-defs.pri:(QT_COMPILER_VERSION_MAJOR STRGREATER 6):
# QMAKE_CXXFLAGS_WARN_ON = "-Wno-expansion-to-defined"
extend_target(Qml CONDITION WINRT
@@ -563,7 +579,7 @@ extend_target(Qml CONDITION DEFINES___contains___WTF_USE_UDIS86=1
../3rdparty/masm/disassembler/udis86/udis86_syn-intel.c
)
-#### Keys ignored in scope 70:.:../3rdparty/masm:../3rdparty/masm/masm.pri:DEFINES___contains___WTF_USE_UDIS86=1:
+#### Keys ignored in scope 72:.:../3rdparty/masm:../3rdparty/masm/masm.pri:DEFINES___contains___WTF_USE_UDIS86=1:
# ITAB = "$$PWD/disassembler/udis86/optable.xml"
# QMAKE_EXTRA_COMPILERS = "udis86"
# QMAKE_EXTRA_TARGETS = "udis86_tab_cfile"
@@ -574,10 +590,10 @@ extend_target(Qml CONDITION DEFINES___contains___WTF_USE_UDIS86=1
# udis86_tab_cfile.depends = "udis86_itab.h"
# udis86_tab_cfile.target = "$$OUT_PWD/udis86_itab.c"
-#### Keys ignored in scope 72:.:../3rdparty/masm:../3rdparty/masm/masm.pri:(CMAKE_BUILD_TYPE STREQUAL Debug):
+#### Keys ignored in scope 74:.:../3rdparty/masm:../3rdparty/masm/masm.pri:(CMAKE_BUILD_TYPE STREQUAL Debug):
# GENERATEDDIR = "$$GENERATEDDIR/debug"
-#### Keys ignored in scope 73:.:../3rdparty/masm:../3rdparty/masm/masm.pri:else:
+#### Keys ignored in scope 75:.:../3rdparty/masm:../3rdparty/masm/masm.pri:else:
# GENERATEDDIR = "$$GENERATEDDIR/release"
extend_target(Qml CONDITION (NOT c++11 AND NOT ICC) AND (CLANG)
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.cmake b/src/qml/configure.cmake
index 0baa79097f..d26aabee28 100644
--- a/src/qml/configure.cmake
+++ b/src/qml/configure.cmake
@@ -176,3 +176,9 @@ qt_feature("qml_worker_script" PRIVATE
PURPOSE "Enables the use of threads in QML."
CONDITION QT_FEATURE_thread
)
+qt_feature("qml_itemmodel" PRIVATE
+ SECTION "QML"
+ LABEL "QML Item Model"
+ PURPOSE "Provides the item model for item views in QML"
+ CONDITION QT_FEATURE_itemmodel
+)
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..82b040232a 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)
@@ -783,8 +803,10 @@ UiHeaderItemList: UiHeaderItemList UiImport;
PragmaId: JsIdentifier;
-UiPragma: T_PRAGMA PragmaId T_AUTOMATIC_SEMICOLON;
-UiPragma: T_PRAGMA PragmaId T_SEMICOLON;
+Semicolon: T_AUTOMATIC_SEMICOLON;
+Semicolon: T_SEMICOLON;
+
+UiPragma: T_PRAGMA PragmaId Semicolon;
/.
case $rule_number: {
AST::UiPragma *pragma = new (pool) AST::UiPragma(stringRef(2));
@@ -796,8 +818,7 @@ UiPragma: T_PRAGMA PragmaId T_SEMICOLON;
ImportId: MemberExpression;
-UiImport: UiImportHead T_AUTOMATIC_SEMICOLON;
-UiImport: UiImportHead T_SEMICOLON;
+UiImport: UiImportHead Semicolon;
/.
case $rule_number: {
sym(1).UiImport->semicolonToken = loc(2);
@@ -824,8 +845,7 @@ UiVersionSpecifier: T_VERSION_NUMBER;
} break;
./
-UiImport: UiImportHead UiVersionSpecifier T_AUTOMATIC_SEMICOLON;
-UiImport: UiImportHead UiVersionSpecifier T_SEMICOLON;
+UiImport: UiImportHead UiVersionSpecifier Semicolon;
/.
case $rule_number: {
auto versionToken = loc(2);
@@ -839,8 +859,7 @@ UiImport: UiImportHead UiVersionSpecifier T_SEMICOLON;
} break;
./
-UiImport: UiImportHead UiVersionSpecifier T_AS QmlIdentifier T_AUTOMATIC_SEMICOLON;
-UiImport: UiImportHead UiVersionSpecifier T_AS QmlIdentifier T_SEMICOLON;
+UiImport: UiImportHead UiVersionSpecifier T_AS QmlIdentifier Semicolon;
/.
case $rule_number: {
sym(1).UiImport->versionToken = loc(2);
@@ -852,8 +871,7 @@ UiImport: UiImportHead UiVersionSpecifier T_AS QmlIdentifier T_SEMICOLON;
} break;
./
-UiImport: UiImportHead T_AS QmlIdentifier T_AUTOMATIC_SEMICOLON;
-UiImport: UiImportHead T_AS QmlIdentifier T_SEMICOLON;
+UiImport: UiImportHead T_AS QmlIdentifier Semicolon;
/.
case $rule_number: {
sym(1).UiImport->asToken = loc(2);
@@ -1086,6 +1104,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 +1125,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: {
@@ -1107,8 +1148,7 @@ UiParameterList: UiParameterList T_COMMA UiPropertyType QmlIdentifier;
} break;
./
-UiObjectMember: T_SIGNAL T_IDENTIFIER T_LPAREN UiParameterListOpt T_RPAREN T_AUTOMATIC_SEMICOLON;
-UiObjectMember: T_SIGNAL T_IDENTIFIER T_LPAREN UiParameterListOpt T_RPAREN T_SEMICOLON;
+UiObjectMember: T_SIGNAL T_IDENTIFIER T_LPAREN UiParameterListOpt T_RPAREN Semicolon;
/.
case $rule_number: {
AST::UiPublicMember *node = new (pool) AST::UiPublicMember(nullptr, stringRef(2));
@@ -1122,8 +1162,7 @@ UiObjectMember: T_SIGNAL T_IDENTIFIER T_LPAREN UiParameterListOpt T_RPAREN T_SEM
} break;
./
-UiObjectMember: T_SIGNAL T_IDENTIFIER T_AUTOMATIC_SEMICOLON;
-UiObjectMember: T_SIGNAL T_IDENTIFIER T_SEMICOLON;
+UiObjectMember: T_SIGNAL T_IDENTIFIER Semicolon;
/.
case $rule_number: {
AST::UiPublicMember *node = new (pool) AST::UiPublicMember(nullptr, stringRef(2));
@@ -1136,8 +1175,7 @@ UiObjectMember: T_SIGNAL T_IDENTIFIER T_SEMICOLON;
} break;
./
-UiObjectMember: T_PROPERTY T_IDENTIFIER T_LT UiPropertyType T_GT QmlIdentifier T_AUTOMATIC_SEMICOLON;
-UiObjectMember: T_PROPERTY T_IDENTIFIER T_LT UiPropertyType T_GT QmlIdentifier T_SEMICOLON;
+UiObjectMember: T_PROPERTY T_IDENTIFIER T_LT UiPropertyType T_GT QmlIdentifier Semicolon;
/.
case $rule_number: {
AST::UiPublicMember *node = new (pool) AST::UiPublicMember(sym(4).UiQualifiedId->finish(), stringRef(6));
@@ -1151,8 +1189,7 @@ UiObjectMember: T_PROPERTY T_IDENTIFIER T_LT UiPropertyType T_GT QmlIdentifier T
} break;
./
-UiObjectMember: T_READONLY T_PROPERTY T_IDENTIFIER T_LT UiPropertyType T_GT QmlIdentifier T_AUTOMATIC_SEMICOLON;
-UiObjectMember: T_READONLY T_PROPERTY T_IDENTIFIER T_LT UiPropertyType T_GT QmlIdentifier T_SEMICOLON;
+UiObjectMember: T_READONLY T_PROPERTY T_IDENTIFIER T_LT UiPropertyType T_GT QmlIdentifier Semicolon;
/.
case $rule_number: {
AST::UiPublicMember *node = new (pool) AST::UiPublicMember(sym(5).UiQualifiedId->finish(), stringRef(7));
@@ -1168,8 +1205,7 @@ UiObjectMember: T_READONLY T_PROPERTY T_IDENTIFIER T_LT UiPropertyType T_GT QmlI
} break;
./
-UiObjectMember: T_PROPERTY UiPropertyType QmlIdentifier T_AUTOMATIC_SEMICOLON;
-UiObjectMember: T_PROPERTY UiPropertyType QmlIdentifier T_SEMICOLON;
+UiObjectMember: T_PROPERTY UiPropertyType QmlIdentifier Semicolon;
/.
case $rule_number: {
AST::UiPublicMember *node = new (pool) AST::UiPublicMember(sym(2).UiQualifiedId->finish(), stringRef(3));
@@ -1181,8 +1217,7 @@ UiObjectMember: T_PROPERTY UiPropertyType QmlIdentifier T_SEMICOLON;
} break;
./
-UiObjectMember: T_DEFAULT T_PROPERTY UiPropertyType QmlIdentifier T_AUTOMATIC_SEMICOLON;
-UiObjectMember: T_DEFAULT T_PROPERTY UiPropertyType QmlIdentifier T_SEMICOLON;
+UiObjectMember: T_DEFAULT T_PROPERTY UiPropertyType QmlIdentifier Semicolon;
/.
case $rule_number: {
AST::UiPublicMember *node = new (pool) AST::UiPublicMember(sym(3).UiQualifiedId->finish(), stringRef(4));
@@ -1196,8 +1231,7 @@ UiObjectMember: T_DEFAULT T_PROPERTY UiPropertyType QmlIdentifier T_SEMICOLON;
} break;
./
-UiObjectMember: T_DEFAULT T_PROPERTY T_IDENTIFIER T_LT UiPropertyType T_GT QmlIdentifier T_AUTOMATIC_SEMICOLON;
-UiObjectMember: T_DEFAULT T_PROPERTY T_IDENTIFIER T_LT UiPropertyType T_GT QmlIdentifier T_SEMICOLON;
+UiObjectMember: T_DEFAULT T_PROPERTY T_IDENTIFIER T_LT UiPropertyType T_GT QmlIdentifier Semicolon;
/.
case $rule_number: {
AST::UiPublicMember *node = new (pool) AST::UiPublicMember(sym(5).UiQualifiedId->finish(), stringRef(7));
@@ -1355,7 +1389,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 +1505,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
--------------------------------------------------------------------------------------------------------
@@ -2800,8 +2891,7 @@ StatementListItem: Statement;
} break;
./
-StatementListItem: ExpressionStatementLookahead T_FORCE_DECLARATION Declaration T_AUTOMATIC_SEMICOLON;
-StatementListItem: ExpressionStatementLookahead T_FORCE_DECLARATION Declaration T_SEMICOLON;
+StatementListItem: ExpressionStatementLookahead T_FORCE_DECLARATION Declaration Semicolon;
/.
case $rule_number: {
sym(1).Node = new (pool) AST::StatementList(sym(3).FunctionDeclaration);
@@ -2851,14 +2941,20 @@ 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;
./
-VariableStatement: VarDeclaration_In T_AUTOMATIC_SEMICOLON;
-VariableStatement: VarDeclaration_In T_SEMICOLON;
+VariableStatement: VarDeclaration_In Semicolon;
BindingList: LexicalBinding_In;
/. case $rule_number: Q_FALLTHROUGH(); ./
@@ -2888,22 +2984,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 +3149,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 +3174,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;
@@ -3128,8 +3224,7 @@ ExpressionStatementLookahead: ;
} break;
./
-ExpressionStatement: Expression_In T_AUTOMATIC_SEMICOLON;
-ExpressionStatement: Expression_In T_SEMICOLON;
+ExpressionStatement: Expression_In Semicolon;
/.
case $rule_number: {
AST::ExpressionStatement *node = new (pool) AST::ExpressionStatement(sym(1).Expression);
@@ -3162,9 +3257,8 @@ IfStatement: T_IF T_LPAREN Expression_In T_RPAREN Statement;
./
-IterationStatement: T_DO Statement T_WHILE T_LPAREN Expression_In T_RPAREN T_AUTOMATIC_SEMICOLON;
IterationStatement: T_DO Statement T_WHILE T_LPAREN Expression_In T_RPAREN T_COMPATIBILITY_SEMICOLON; -- for JSC/V8 compatibility
-IterationStatement: T_DO Statement T_WHILE T_LPAREN Expression_In T_RPAREN T_SEMICOLON;
+IterationStatement: T_DO Statement T_WHILE T_LPAREN Expression_In T_RPAREN Semicolon;
/.
case $rule_number: {
AST::DoWhileStatement *node = new (pool) AST::DoWhileStatement(sym(2).Statement, sym(5).Expression);
@@ -3268,12 +3362,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;
@@ -3293,8 +3391,7 @@ ForDeclaration: Var BindingPattern;
} break;
./
-ContinueStatement: T_CONTINUE T_AUTOMATIC_SEMICOLON;
-ContinueStatement: T_CONTINUE T_SEMICOLON;
+ContinueStatement: T_CONTINUE Semicolon;
/.
case $rule_number: {
AST::ContinueStatement *node = new (pool) AST::ContinueStatement();
@@ -3304,8 +3401,7 @@ ContinueStatement: T_CONTINUE T_SEMICOLON;
} break;
./
-ContinueStatement: T_CONTINUE IdentifierReference T_AUTOMATIC_SEMICOLON;
-ContinueStatement: T_CONTINUE IdentifierReference T_SEMICOLON;
+ContinueStatement: T_CONTINUE IdentifierReference Semicolon;
/.
case $rule_number: {
AST::ContinueStatement *node = new (pool) AST::ContinueStatement(stringRef(2));
@@ -3316,8 +3412,7 @@ ContinueStatement: T_CONTINUE IdentifierReference T_SEMICOLON;
} break;
./
-BreakStatement: T_BREAK T_AUTOMATIC_SEMICOLON;
-BreakStatement: T_BREAK T_SEMICOLON;
+BreakStatement: T_BREAK Semicolon;
/.
case $rule_number: {
AST::BreakStatement *node = new (pool) AST::BreakStatement(QStringRef());
@@ -3327,8 +3422,7 @@ BreakStatement: T_BREAK T_SEMICOLON;
} break;
./
-BreakStatement: T_BREAK IdentifierReference T_AUTOMATIC_SEMICOLON;
-BreakStatement: T_BREAK IdentifierReference T_SEMICOLON;
+BreakStatement: T_BREAK IdentifierReference Semicolon;
/.
case $rule_number: {
AST::BreakStatement *node = new (pool) AST::BreakStatement(stringRef(2));
@@ -3339,8 +3433,7 @@ BreakStatement: T_BREAK IdentifierReference T_SEMICOLON;
} break;
./
-ReturnStatement: T_RETURN ExpressionOpt_In T_AUTOMATIC_SEMICOLON;
-ReturnStatement: T_RETURN ExpressionOpt_In T_SEMICOLON;
+ReturnStatement: T_RETURN ExpressionOpt_In Semicolon;
/.
case $rule_number: {
if (!functionNestingLevel) {
@@ -3464,8 +3557,7 @@ LabelledItem: ExpressionStatementLookahead T_FORCE_DECLARATION FunctionDeclarati
} break;
./
-ThrowStatement: T_THROW Expression_In T_AUTOMATIC_SEMICOLON;
-ThrowStatement: T_THROW Expression_In T_SEMICOLON;
+ThrowStatement: T_THROW Expression_In Semicolon;
/.
case $rule_number: {
AST::ThrowStatement *node = new (pool) AST::ThrowStatement(sym(2).Expression);
@@ -3542,8 +3634,7 @@ CatchParameter: BindingPattern;
} break;
./
-DebuggerStatement: T_DEBUGGER T_AUTOMATIC_SEMICOLON; -- automatic semicolon
-DebuggerStatement: T_DEBUGGER T_SEMICOLON;
+DebuggerStatement: T_DEBUGGER Semicolon;
/.
case $rule_number: {
AST::DebuggerStatement *node = new (pool) AST::DebuggerStatement();
@@ -3560,59 +3651,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 +3839,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 +3873,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 +3909,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;
@@ -4118,13 +4243,10 @@ ModuleItemList: ModuleItemList ModuleItem;
} break;
./
-ModuleItem: ImportDeclaration T_AUTOMATIC_SEMICOLON;
-/. case $rule_number: Q_FALLTHROUGH(); ./
-ModuleItem: ImportDeclaration T_SEMICOLON;
-/. case $rule_number: Q_FALLTHROUGH(); ./
-ModuleItem: ExportDeclaration T_AUTOMATIC_SEMICOLON;
+
+ModuleItem: ImportDeclaration Semicolon;
/. case $rule_number: Q_FALLTHROUGH(); ./
-ModuleItem: ExportDeclaration T_SEMICOLON;
+ModuleItem: ExportDeclaration Semicolon;
/.
case $rule_number: {
sym(1).StatementList = new (pool) AST::StatementList(sym(1).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..7652cec322
--- /dev/null
+++ b/src/qml/qml/qqmldirdata.cpp
@@ -0,0 +1,95 @@
+/****************************************************************************
+**
+** 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;
+}
+
+QQmlTypeLoader::Blob::PendingImportPtr QQmlQmldirData::import(QQmlTypeLoader::Blob *blob) const
+{
+ auto it = m_imports.find(blob);
+ if (it == m_imports.end())
+ return nullptr;
+ return *it;
+}
+
+void QQmlQmldirData::setImport(QQmlTypeLoader::Blob *blob, QQmlTypeLoader::Blob::PendingImportPtr 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..34f1ff1678
--- /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;
+
+ PendingImportPtr import(QQmlTypeLoader::Blob *) const;
+ void setImport(QQmlTypeLoader::Blob *, PendingImportPtr);
+
+ 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 *, QQmlTypeLoader::Blob::PendingImportPtr> 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 4460312e2c..7ba5fc08a5 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>
@@ -219,30 +220,6 @@ void QQmlEnginePrivate::defineModule()
#endif
}
-#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
-void QQmlEnginePrivate::registerQuickTypes()
-{
- // Don't add anything here. These are only for backwards compatibility.
-
- const char uri[] = "QtQuick";
-
- qmlRegisterType<QQmlComponent>(uri, 2, 0, "Component");
- qmlRegisterType<QObject>(uri, 2, 0, "QtObject");
- qmlRegisterType<QQmlBind>(uri, 2, 0, "Binding");
- qmlRegisterType<QQmlBind, 8>(uri, 2, 8, "Binding");
- qmlRegisterCustomType<QQmlConnections>(uri, 2, 0, "Connections", new QQmlConnectionsParser);
- qmlRegisterCustomType<QQmlConnections, 1>(uri, 2, 7, "Connections", new QQmlConnectionsParser);
-#if QT_CONFIG(qml_animation)
- qmlRegisterType<QQmlTimer>(uri, 2, 0,"Timer");
-#endif
- qmlRegisterType<QQmlLoggingCategory>(uri, 2, 8, "LoggingCategory");
- qmlRegisterType<QQmlLoggingCategory, 1>(uri, 2, 12, "LoggingCategory");
-#if QT_CONFIG(qml_locale)
- qmlRegisterUncreatableType<QQmlLocale>(uri, 2, 0, "Locale", QQmlEngine::tr("Locale cannot be instantiated. Use Qt.locale()"));
-#endif
-}
-#endif // QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
-
bool QQmlEnginePrivate::designerMode()
{
return s_designerMode;
@@ -1790,7 +1767,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 +2092,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 +2303,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..2c4bb36c8f 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>
@@ -251,9 +252,6 @@ public:
static QList<QQmlError> qmlErrorFromDiagnostics(const QString &fileName, const QList<QQmlJS::DiagnosticMessage> &diagnosticMessages);
static void defineModule();
-#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
- static void registerQuickTypes();
-#endif
static bool designerMode();
static void activateDesignerMode();
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..8d75b57fc1
--- /dev/null
+++ b/src/qml/qml/qqmltypedata.cpp
@@ -0,0 +1,843 @@
+/****************************************************************************
+**
+** 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;
+ auto pendingImport = std::make_shared<PendingImport>(this, import);
+ if (!fetchQmldir(qmldirUrl, pendingImport, 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
+ auto implicitImport = std::make_shared<PendingImport>();
+ implicitImport->uri = QLatin1String(".");
+ 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;
+ auto it = m_unresolvedImports.constBegin(), end = m_unresolvedImports.constEnd();
+ for ( ; it != end; ++it) {
+ if ((*it)->priority == 0) {
+ // This import was not resolved
+ for (auto keyIt = m_unresolvedImports.constBegin(),
+ keyEnd = m_unresolvedImports.constEnd();
+ keyIt != keyEnd; ++keyIt) {
+ PendingImportPtr import = *keyIt;
+ QQmlError error;
+ error.setDescription(QQmlTypeLoader::tr("module \"%1\" is not installed").arg(import->uri));
+ error.setUrl(m_importCache.baseUrl());
+ error.setLine(import->location.line);
+ error.setColumn(import->location.column);
+ 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..3a18bbf7c9 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.
@@ -1331,6 +468,16 @@ void QQmlTypeLoader::shutdownThread()
m_thread->shutdown();
}
+QQmlTypeLoader::Blob::PendingImport::PendingImport(QQmlTypeLoader::Blob *blob, const QV4::CompiledData::Import *import)
+{
+ type = static_cast<QV4::CompiledData::Import::ImportType>(quint32(import->type));
+ uri = blob->stringAt(import->uriIndex);
+ qualifier = blob->stringAt(import->qualifierIndex);
+ majorVersion = import->majorVersion;
+ minorVersion = import->minorVersion;
+ location = import->location;
+}
+
QQmlTypeLoader::Blob::Blob(const QUrl &url, QQmlDataBlob::Type type, QQmlTypeLoader *loader)
: QQmlDataBlob(url, type, loader), m_importCache(loader)
{
@@ -1340,7 +487,7 @@ QQmlTypeLoader::Blob::~Blob()
{
}
-bool QQmlTypeLoader::Blob::fetchQmldir(const QUrl &url, const QV4::CompiledData::Import *import, int priority, QList<QQmlError> *errors)
+bool QQmlTypeLoader::Blob::fetchQmldir(const QUrl &url, PendingImportPtr import, int priority, QList<QQmlError> *errors)
{
QQmlRefPointer<QQmlQmldirData> data = typeLoader()->getQmldir(url);
@@ -1360,26 +507,25 @@ bool QQmlTypeLoader::Blob::fetchQmldir(const QUrl &url, const QV4::CompiledData:
return true;
}
-bool QQmlTypeLoader::Blob::updateQmldir(const QQmlRefPointer<QQmlQmldirData> &data, const QV4::CompiledData::Import *import, QList<QQmlError> *errors)
+bool QQmlTypeLoader::Blob::updateQmldir(const QQmlRefPointer<QQmlQmldirData> &data, PendingImportPtr import, QList<QQmlError> *errors)
{
QString qmldirIdentifier = data->urlString();
QString qmldirUrl = qmldirIdentifier.left(qmldirIdentifier.lastIndexOf(QLatin1Char('/')) + 1);
typeLoader()->setQmldirContent(qmldirIdentifier, data->content());
- if (!m_importCache.updateQmldirContent(typeLoader()->importDatabase(), stringAt(import->uriIndex), stringAt(import->qualifierIndex), qmldirIdentifier, qmldirUrl, errors))
+ if (!m_importCache.updateQmldirContent(typeLoader()->importDatabase(), import->uri, import->qualifier, qmldirIdentifier, qmldirUrl, errors))
return false;
- QHash<const QV4::CompiledData::Import *, int>::iterator it = m_unresolvedImports.find(import);
- if (it != m_unresolvedImports.end()) {
- *it = data->priority(this);
- }
+ if (!loadImportDependencies(import, qmldirIdentifier, errors))
+ return false;
+
+ import->priority = data->priority(this);
// Release this reference at destruction
m_qmldirs << data;
- const QString &importQualifier = stringAt(import->qualifierIndex);
- if (!importQualifier.isEmpty()) {
+ if (!import->qualifier.isEmpty()) {
// Does this library contain any qualified scripts?
QUrl libraryUrl(qmldirUrl);
const QQmlTypeLoaderQmldirContent qmldir = typeLoader()->qmldirContent(qmldirIdentifier);
@@ -1389,7 +535,7 @@ bool QQmlTypeLoader::Blob::updateQmldir(const QQmlRefPointer<QQmlQmldirData> &da
QQmlRefPointer<QQmlScriptBlob> blob = typeLoader()->getScript(scriptUrl);
addDependency(blob.data());
- scriptImported(blob, import->location, script.nameSpace, importQualifier);
+ scriptImported(blob, import->location, script.nameSpace, import->qualifier);
}
}
@@ -1398,36 +544,42 @@ bool QQmlTypeLoader::Blob::updateQmldir(const QQmlRefPointer<QQmlQmldirData> &da
bool QQmlTypeLoader::Blob::addImport(const QV4::CompiledData::Import *import, QList<QQmlError> *errors)
{
+ return addImport(std::make_shared<PendingImport>(this, import), errors);
+}
+
+bool QQmlTypeLoader::Blob::addImport(QQmlTypeLoader::Blob::PendingImportPtr import, QList<QQmlError> *errors)
+{
Q_ASSERT(errors);
QQmlImportDatabase *importDatabase = typeLoader()->importDatabase();
- const QString &importUri = stringAt(import->uriIndex);
- const QString &importQualifier = stringAt(import->qualifierIndex);
if (import->type == QV4::CompiledData::Import::ImportScript) {
- QUrl scriptUrl = finalUrl().resolved(QUrl(importUri));
+ QUrl scriptUrl = finalUrl().resolved(QUrl(import->uri));
QQmlRefPointer<QQmlScriptBlob> blob = typeLoader()->getScript(scriptUrl);
addDependency(blob.data());
- scriptImported(blob, import->location, importQualifier, QString());
+ scriptImported(blob, import->location, import->qualifier, QString());
} else if (import->type == QV4::CompiledData::Import::ImportLibrary) {
QString qmldirFilePath;
QString qmldirUrl;
- if (QQmlMetaType::isLockedModule(importUri, import->majorVersion)) {
+ if (QQmlMetaType::isLockedModule(import->uri, import->majorVersion)) {
//Locked modules are checked first, to save on filesystem checks
- if (!m_importCache.addLibraryImport(importDatabase, importUri, importQualifier, import->majorVersion,
+ if (!m_importCache.addLibraryImport(importDatabase, import->uri, import->qualifier, import->majorVersion,
import->minorVersion, QString(), QString(), false, errors))
return false;
- } else if (m_importCache.locateQmldir(importDatabase, importUri, import->majorVersion, import->minorVersion,
+ } else if (m_importCache.locateQmldir(importDatabase, import->uri, import->majorVersion, import->minorVersion,
&qmldirFilePath, &qmldirUrl)) {
// This is a local library import
- if (!m_importCache.addLibraryImport(importDatabase, importUri, importQualifier, import->majorVersion,
+ if (!m_importCache.addLibraryImport(importDatabase, import->uri, import->qualifier, import->majorVersion,
import->minorVersion, qmldirFilePath, qmldirUrl, false, errors))
return false;
- if (!importQualifier.isEmpty()) {
+ if (!loadImportDependencies(import, qmldirFilePath, errors))
+ return false;
+
+ if (!import->qualifier.isEmpty()) {
// Does this library contain any qualified scripts?
QUrl libraryUrl(qmldirUrl);
const QQmlTypeLoaderQmldirContent qmldir = typeLoader()->qmldirContent(qmldirFilePath);
@@ -1437,18 +589,18 @@ bool QQmlTypeLoader::Blob::addImport(const QV4::CompiledData::Import *import, QL
QQmlRefPointer<QQmlScriptBlob> blob = typeLoader()->getScript(scriptUrl);
addDependency(blob.data());
- scriptImported(blob, import->location, script.nameSpace, importQualifier);
+ scriptImported(blob, import->location, script.nameSpace, import->qualifier);
}
}
} else {
// Is this a module?
- if (QQmlMetaType::isAnyModule(importUri)) {
- if (!m_importCache.addLibraryImport(importDatabase, importUri, importQualifier, import->majorVersion,
+ if (QQmlMetaType::isAnyModule(import->uri)) {
+ if (!m_importCache.addLibraryImport(importDatabase, import->uri, import->qualifier, import->majorVersion,
import->minorVersion, QString(), QString(), false, errors))
return false;
} else {
// We haven't yet resolved this import
- m_unresolvedImports.insert(import, 0);
+ m_unresolvedImports << import;
QQmlAbstractUrlInterceptor *interceptor = typeLoader()->engine()->urlInterceptor();
@@ -1459,13 +611,13 @@ bool QQmlTypeLoader::Blob::addImport(const QV4::CompiledData::Import *import, QL
: QQmlImportDatabase::Remote);
if (!remotePathList.isEmpty()) {
// Add this library and request the possible locations for it
- if (!m_importCache.addLibraryImport(importDatabase, importUri, importQualifier, import->majorVersion,
+ if (!m_importCache.addLibraryImport(importDatabase, import->uri, import->qualifier, import->majorVersion,
import->minorVersion, QString(), QString(), true, errors))
return false;
// Probe for all possible locations
int priority = 0;
- const QStringList qmlDirPaths = QQmlImports::completeQmldirPaths(importUri, remotePathList, import->majorVersion, import->minorVersion);
+ const QStringList qmlDirPaths = QQmlImports::completeQmldirPaths(import->uri, remotePathList, import->majorVersion, import->minorVersion);
for (const QString &qmldirPath : qmlDirPaths) {
if (interceptor) {
QUrl url = interceptor->intercept(
@@ -1488,13 +640,17 @@ bool QQmlTypeLoader::Blob::addImport(const QV4::CompiledData::Import *import, QL
bool incomplete = false;
- QUrl qmldirUrl = finalUrl().resolved(QUrl(importUri + QLatin1String("/qmldir")));
+ QUrl importUrl(import->uri);
+ QString path = importUrl.path();
+ path.append(QLatin1String(path.endsWith(QLatin1Char('/')) ? "qmldir" : "/qmldir"));
+ importUrl.setPath(path);
+ QUrl qmldirUrl = finalUrl().resolved(importUrl);
if (!QQmlImports::isLocal(qmldirUrl)) {
// This is a remote file; the import is currently incomplete
incomplete = true;
}
- if (!m_importCache.addFileImport(importDatabase, importUri, importQualifier, import->majorVersion,
+ if (!m_importCache.addFileImport(importDatabase, import->uri, import->qualifier, import->majorVersion,
import->minorVersion, incomplete, errors))
return false;
@@ -1512,7 +668,7 @@ void QQmlTypeLoader::Blob::dependencyComplete(QQmlDataBlob *blob)
if (blob->type() == QQmlDataBlob::QmldirFile) {
QQmlQmldirData *data = static_cast<QQmlQmldirData *>(blob);
- const QV4::CompiledData::Import *import = data->import(this);
+ PendingImportPtr import = data->import(this);
QList<QQmlError> errors;
if (!qmldirDataAvailable(data, &errors)) {
@@ -1527,16 +683,39 @@ void QQmlTypeLoader::Blob::dependencyComplete(QQmlDataBlob *blob)
}
}
+bool QQmlTypeLoader::Blob::loadImportDependencies(PendingImportPtr currentImport, const QString &qmldirUri, QList<QQmlError> *errors)
+{
+ const QQmlTypeLoaderQmldirContent qmldir = typeLoader()->qmldirContent(qmldirUri);
+ for (const QString &implicitImports: qmldir.imports()) {
+ auto dependencyImport = std::make_shared<PendingImport>();
+ dependencyImport->uri = implicitImports;
+ dependencyImport->qualifier = currentImport->qualifier;
+ dependencyImport->majorVersion = currentImport->majorVersion;
+ dependencyImport->minorVersion = currentImport->minorVersion;
+ if (!addImport(dependencyImport, errors))
+ return false;
+ }
+ return true;
+}
+
bool QQmlTypeLoader::Blob::isDebugging() const
{
return typeLoader()->engine()->handle()->debugger() != nullptr;
}
-bool QQmlTypeLoader::Blob::qmldirDataAvailable(const QQmlRefPointer<QQmlQmldirData> &data, QList<QQmlError> *errors)
+bool QQmlTypeLoader::Blob::diskCacheDisabled()
+{
+ return disableDiskCache();
+}
+
+bool QQmlTypeLoader::Blob::diskCacheForced()
{
- bool resolve = true;
+ return forceDiskCache();
+}
- const QV4::CompiledData::Import *import = data->import(this);
+bool QQmlTypeLoader::Blob::qmldirDataAvailable(const QQmlRefPointer<QQmlQmldirData> &data, QList<QQmlError> *errors)
+{
+ PendingImportPtr import = data->import(this);
data->setImport(this, nullptr);
int priority = data->priority(this);
@@ -1544,10 +723,7 @@ bool QQmlTypeLoader::Blob::qmldirDataAvailable(const QQmlRefPointer<QQmlQmldirDa
if (import) {
// Do we need to resolve this import?
- QHash<const QV4::CompiledData::Import *, int>::iterator it = m_unresolvedImports.find(import);
- if (it != m_unresolvedImports.end()) {
- resolve = (*it == 0) || (*it > priority);
- }
+ const bool resolve = (import->priority == 0) || (import->priority > priority);
if (resolve) {
// This is the (current) best resolution for this import
@@ -1555,8 +731,7 @@ bool QQmlTypeLoader::Blob::qmldirDataAvailable(const QQmlRefPointer<QQmlQmldirDa
return false;
}
- if (it != m_unresolvedImports.end())
- *it = priority;
+ import->priority = priority;
return true;
}
}
@@ -1564,77 +739,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 +892,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 +1202,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..612d6777ed 100644
--- a/src/qml/qml/qqmltypeloader_p.h
+++ b/src/qml/qml/qqmltypeloader_p.h
@@ -51,213 +51,27 @@
// 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 <QtCore/qcache.h>
+#include <QtCore/qmutex.h>
-#include <private/qv4value_p.h>
-#include <private/qv4script_p.h>
+#include <memory>
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
{
@@ -275,11 +89,31 @@ public:
void setCachedUnitStatus(QQmlMetaType::CachedUnitLookupError status) { m_cachedUnitStatus = status; }
+ struct PendingImport
+ {
+ QV4::CompiledData::Import::ImportType type = QV4::CompiledData::Import::ImportType::ImportLibrary;
+
+ QString uri;
+ QString qualifier;
+
+ int majorVersion = -1;
+ int minorVersion = -1;
+
+ QV4::CompiledData::Location location;
+
+ int priority = 0;
+
+ PendingImport() = default;
+ PendingImport(Blob *blob, const QV4::CompiledData::Import *import);
+ };
+ using PendingImportPtr = std::shared_ptr<PendingImport>;
+
protected:
bool addImport(const QV4::CompiledData::Import *import, QList<QQmlError> *errors);
+ bool addImport(PendingImportPtr import, QList<QQmlError> *errors);
- bool fetchQmldir(const QUrl &url, const QV4::CompiledData::Import *import, int priority, QList<QQmlError> *errors);
- bool updateQmldir(const QQmlRefPointer<QQmlQmldirData> &data, const QV4::CompiledData::Import *import, QList<QQmlError> *errors);
+ bool fetchQmldir(const QUrl &url, PendingImportPtr import, int priority, QList<QQmlError> *errors);
+ bool updateQmldir(const QQmlRefPointer<QQmlQmldirData> &data, PendingImportPtr import, QList<QQmlError> *errors);
private:
virtual bool qmldirDataAvailable(const QQmlRefPointer<QQmlQmldirData> &, QList<QQmlError> *);
@@ -288,13 +122,18 @@ public:
void dependencyComplete(QQmlDataBlob *) override;
+ bool loadImportDependencies(PendingImportPtr currentImport, const QString &qmldirUri, QList<QQmlError> *errors);
+
protected:
virtual QString stringAt(int) const { return QString(); }
bool isDebugging() const;
+ static bool diskCacheDisabled();
+ static bool diskCacheForced();
+
QQmlImports m_importCache;
- QHash<const QV4::CompiledData::Import*, int> m_unresolvedImports;
+ QVector<PendingImportPtr> m_unresolvedImports;
QVector<QQmlRefPointer<QQmlQmldirData>> m_qmldirs;
QQmlMetaType::CachedUnitLookupError m_cachedUnitStatus = QQmlMetaType::CachedUnitLookupError::NoError;
};
@@ -418,209 +257,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..238af9b710
--- /dev/null
+++ b/src/qml/qml/qqmltypeloaderqmldircontent.cpp
@@ -0,0 +1,120 @@
+/****************************************************************************
+**
+** 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();
+}
+
+QStringList QQmlTypeLoaderQmldirContent::imports() const
+{
+ return m_parser.imports();
+}
+
+QString QQmlTypeLoaderQmldirContent::pluginLocation() const
+{
+ return m_location;
+}
+
+bool QQmlTypeLoaderQmldirContent::designerSupported() const
+{
+ return m_parser.designerSupported();
+}
+
+QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmltypeloaderqmldircontent_p.h b/src/qml/qml/qqmltypeloaderqmldircontent_p.h
new file mode 100644
index 0000000000..698643c7ec
--- /dev/null
+++ b/src/qml/qml/qqmltypeloaderqmldircontent_p.h
@@ -0,0 +1,95 @@
+/****************************************************************************
+**
+** 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;
+ QStringList imports() 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.cpp b/src/qml/qmldirparser/qqmldirparser.cpp
index d7662b11f5..5bf33d3602 100644
--- a/src/qml/qmldirparser/qqmldirparser.cpp
+++ b/src/qml/qmldirparser/qqmldirparser.cpp
@@ -262,6 +262,13 @@ bool QQmlDirParser::parse(const QString &source)
} else {
reportError(lineNumber, 0, QStringLiteral("invalid version %1, expected <major>.<minor>").arg(sections[2]));
}
+ } else if (sections[0] == QLatin1String("import")) {
+ if (sectionCount != 2) {
+ reportError(lineNumber, 0,
+ QStringLiteral("import requires 2 arguments, but %1 were provided").arg(sectionCount - 1));
+ continue;
+ }
+ _imports << sections[1];
} else if (sectionCount == 2) {
// No version specified (should only be used for relative qmldir files)
const Component entry(sections[0], sections[1], -1, -1);
@@ -354,6 +361,11 @@ QHash<QString, QQmlDirParser::Component> QQmlDirParser::dependencies() const
return _dependencies;
}
+QStringList QQmlDirParser::imports() const
+{
+ return _imports;
+}
+
QList<QQmlDirParser::Script> QQmlDirParser::scripts() const
{
return _scripts;
diff --git a/src/qml/qmldirparser/qqmldirparser_p.h b/src/qml/qmldirparser/qqmldirparser_p.h
index 0957c8373a..37ca1ef2ce 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();
@@ -136,6 +136,7 @@ public:
QHash<QString,Component> components() const;
QHash<QString,Component> dependencies() const;
+ QStringList imports() const;
QList<Script> scripts() const;
QList<Plugin> plugins() const;
bool designerSupported() const;
@@ -162,6 +163,7 @@ private:
QString _typeNamespace;
QHash<QString,Component> _components; // multi hash
QHash<QString,Component> _dependencies;
+ QStringList _imports;
QList<Script> _scripts;
QList<Plugin> _plugins;
bool _designerSupported;
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/qmldevtools/.prev_CMakeLists.txt b/src/qmldevtools/.prev_CMakeLists.txt
index 9f3587f2a0..6e229f7d80 100644
--- a/src/qmldevtools/.prev_CMakeLists.txt
+++ b/src/qmldevtools/.prev_CMakeLists.txt
@@ -11,29 +11,31 @@ add_qt_module(QmlDevTools
SOURCES
../qml/common/qqmlapiversion_p.h
../qml/common/qqmljsdiagnosticmessage_p.h
+ ../qml/common/qqmljsfixedpoolarray_p.h
+ ../qml/common/qqmljsmemorypool_p.h
+ ../qml/common/qv4alloca_p.h
+ ../qml/common/qv4calldata_p.h
+ ../qml/common/qv4compileddata_p.h
+ ../qml/common/qv4staticvalue_p.h
+ ../qml/common/qv4stringtoarrayindex_p.h
../qml/compiler/qqmlirbuilder.cpp ../qml/compiler/qqmlirbuilder_p.h
- ../qml/compiler/qv4alloca_p.h
../qml/compiler/qv4bytecodegenerator.cpp ../qml/compiler/qv4bytecodegenerator_p.h
../qml/compiler/qv4bytecodehandler.cpp ../qml/compiler/qv4bytecodehandler_p.h
- ../qml/compiler/qv4calldata_p.h
../qml/compiler/qv4codegen.cpp ../qml/compiler/qv4codegen_p.h
- ../qml/compiler/qv4compileddata_p.h
../qml/compiler/qv4compiler.cpp ../qml/compiler/qv4compiler_p.h
../qml/compiler/qv4compilercontext.cpp ../qml/compiler/qv4compilercontext_p.h
../qml/compiler/qv4compilercontrolflow_p.h
+ ../qml/compiler/qv4compilerglobal_p.h
../qml/compiler/qv4compilerscanfunctions.cpp ../qml/compiler/qv4compilerscanfunctions_p.h
../qml/compiler/qv4instr_moth.cpp ../qml/compiler/qv4instr_moth_p.h
- ../qml/compiler/qv4staticvalue_p.h
- ../qml/compiler/qv4stringtoarrayindex_p.h
../qml/compiler/qv4util_p.h
../qml/parser/qqmljsast.cpp ../qml/parser/qqmljsast_p.h
../qml/parser/qqmljsastfwd_p.h
../qml/parser/qqmljsastvisitor.cpp ../qml/parser/qqmljsastvisitor_p.h
../qml/parser/qqmljsengine_p.cpp ../qml/parser/qqmljsengine_p.h ../qml/parser/qqmljsengine_p.h
- ../qml/parser/qqmljsglobal_p.h ../qml/parser/qqmljsglobal_p.h
+ ../qml/parser/qqmljsglobal_p.h
../qml/parser/qqmljskeywords_p.h
../qml/parser/qqmljslexer.cpp ../qml/parser/qqmljslexer_p.h
- ../qml/parser/qqmljsmemorypool_p.h
../qml/parser/qqmljssourcelocation_p.h
../qml/qmldirparser/qqmldirparser.cpp ../qml/qmldirparser/qqmldirparser_p.h
INCLUDE_DIRECTORIES
@@ -63,6 +65,22 @@ add_qt_module(QmlDevTools
#### Keys ignored in scope 3:.:.:qmldevtools.pro:CLANG AND greaterThan(QT_CLANG_MAJOR_VERSION,3 OR greaterThan(QT_CLANG_MINOR_VERSION,3)):
# WERROR = "-Wno-error=unused-const-variable"
+#### Keys ignored in scope 5:.:../qml/common:../qml/common/common.pri:NOT build_pass:
+# 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)"
+# tag = <EMPTY>
+# tagFile = "$$PWD/../../.tag"
+
+#### Keys ignored in scope 6:.:../qml/common:../qml/common/common.pri:EXISTS _ss_tagFile:
+# QMAKE_INTERNAL_INCLUDED_FILES = "$$tagFile"
+# tag = "$$cat$$tagFile,singleline"
+
+#### Keys ignored in scope 7:.:../qml/common:../qml/common/common.pri:NOT tag___equals____ss_{LITERAL_DOLLAR}Format AND %H_ss_{LITERAL_DOLLAR}:
+# QML_COMPILE_HASH = "$$tag"
+
+#### Keys ignored in scope 9:.:../qml/common:../qml/common/common.pri:EXISTS _ss_PWD/../../.git:
+# QML_COMPILE_HASH = "$$commit"
+# commit = "$$systemgitrev-parseHEAD"
+
extend_target(QmlDevTools CONDITION (GCC) AND ((QT_COMPILER_VERSION_MAJOR STREQUAL 5))
COMPILE_OPTIONS
-fno-strict-aliasing
diff --git a/src/qmldevtools/CMakeLists.txt b/src/qmldevtools/CMakeLists.txt
index 9ed5aad94a..f906df4cc9 100644
--- a/src/qmldevtools/CMakeLists.txt
+++ b/src/qmldevtools/CMakeLists.txt
@@ -11,29 +11,31 @@ add_qt_module(QmlDevTools
SOURCES
../qml/common/qqmlapiversion_p.h
../qml/common/qqmljsdiagnosticmessage_p.h
+ ../qml/common/qqmljsfixedpoolarray_p.h
+ ../qml/common/qqmljsmemorypool_p.h
+ ../qml/common/qv4alloca_p.h
+ ../qml/common/qv4calldata_p.h
+ ../qml/common/qv4compileddata_p.h
+ ../qml/common/qv4staticvalue_p.h
+ ../qml/common/qv4stringtoarrayindex_p.h
../qml/compiler/qqmlirbuilder.cpp ../qml/compiler/qqmlirbuilder_p.h
- ../qml/compiler/qv4alloca_p.h
../qml/compiler/qv4bytecodegenerator.cpp ../qml/compiler/qv4bytecodegenerator_p.h
../qml/compiler/qv4bytecodehandler.cpp ../qml/compiler/qv4bytecodehandler_p.h
- ../qml/compiler/qv4calldata_p.h
../qml/compiler/qv4codegen.cpp ../qml/compiler/qv4codegen_p.h
- ../qml/compiler/qv4compileddata_p.h
../qml/compiler/qv4compiler.cpp ../qml/compiler/qv4compiler_p.h
../qml/compiler/qv4compilercontext.cpp ../qml/compiler/qv4compilercontext_p.h
../qml/compiler/qv4compilercontrolflow_p.h
+ ../qml/compiler/qv4compilerglobal_p.h
../qml/compiler/qv4compilerscanfunctions.cpp ../qml/compiler/qv4compilerscanfunctions_p.h
../qml/compiler/qv4instr_moth.cpp ../qml/compiler/qv4instr_moth_p.h
- ../qml/compiler/qv4staticvalue_p.h
- ../qml/compiler/qv4stringtoarrayindex_p.h
../qml/compiler/qv4util_p.h
../qml/parser/qqmljsast.cpp ../qml/parser/qqmljsast_p.h
../qml/parser/qqmljsastfwd_p.h
../qml/parser/qqmljsastvisitor.cpp ../qml/parser/qqmljsastvisitor_p.h
../qml/parser/qqmljsengine_p.cpp ../qml/parser/qqmljsengine_p.h ../qml/parser/qqmljsengine_p.h
- ../qml/parser/qqmljsglobal_p.h ../qml/parser/qqmljsglobal_p.h
+ ../qml/parser/qqmljsglobal_p.h
../qml/parser/qqmljskeywords_p.h
../qml/parser/qqmljslexer.cpp ../qml/parser/qqmljslexer_p.h
- ../qml/parser/qqmljsmemorypool_p.h
../qml/parser/qqmljssourcelocation_p.h
../qml/qmldirparser/qqmldirparser.cpp ../qml/qmldirparser/qqmldirparser_p.h
INCLUDE_DIRECTORIES
@@ -81,6 +83,22 @@ target_include_directories(QmlDevToolsPrivate INTERFACE ${_qml_dev_tools_private
#### Keys ignored in scope 3:.:.:qmldevtools.pro:CLANG AND greaterThan(QT_CLANG_MAJOR_VERSION,3 OR greaterThan(QT_CLANG_MINOR_VERSION,3)):
# WERROR = "-Wno-error=unused-const-variable"
+#### Keys ignored in scope 5:.:../qml/common:../qml/common/common.pri:NOT build_pass:
+# 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)"
+# tag = <EMPTY>
+# tagFile = "$$PWD/../../.tag"
+
+#### Keys ignored in scope 6:.:../qml/common:../qml/common/common.pri:EXISTS _ss_tagFile:
+# QMAKE_INTERNAL_INCLUDED_FILES = "$$tagFile"
+# tag = "$$cat$$tagFile,singleline"
+
+#### Keys ignored in scope 7:.:../qml/common:../qml/common/common.pri:NOT tag___equals____ss_{LITERAL_DOLLAR}Format AND %H_ss_{LITERAL_DOLLAR}:
+# QML_COMPILE_HASH = "$$tag"
+
+#### Keys ignored in scope 9:.:../qml/common:../qml/common/common.pri:EXISTS _ss_PWD/../../.git:
+# QML_COMPILE_HASH = "$$commit"
+# commit = "$$systemgitrev-parseHEAD"
+
extend_target(QmlDevTools CONDITION (GCC) AND ((QT_COMPILER_VERSION_MAJOR STREQUAL 5))
COMPILE_OPTIONS
-fno-strict-aliasing
diff --git a/src/qmlmodels/configure.cmake b/src/qmlmodels/configure.cmake
index 086b08ca8a..b8409f7106 100644
--- a/src/qmlmodels/configure.cmake
+++ b/src/qmlmodels/configure.cmake
@@ -23,15 +23,17 @@ qt_feature("qml_list_model" PRIVATE
SECTION "QML"
LABEL "QML list model"
PURPOSE "Provides the ListModel QML type."
+ CONDITION QT_FEATURE_qml_itemmodel
)
qt_feature("qml_delegate_model" PRIVATE
SECTION "QML"
LABEL "QML delegate model"
PURPOSE "Provides the DelegateModel QML type."
- CONDITION QT_FEATURE_qml_object_model
+ CONDITION QT_FEATURE_qml_object_model AND QT_FEATURE_qml_itemmodel
)
qt_feature("qml_table_model" PRIVATE
SECTION "QML"
LABEL "QML table model"
PURPOSE "Provides the TableModel QML type."
+ CONDITION QT_FEATURE_qml_itemmodel
)
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/qmlmodels/qqmlmodelsmodule.cpp b/src/qmlmodels/qqmlmodelsmodule.cpp
index 2db5dd834f..5195f9baad 100644
--- a/src/qmlmodels/qqmlmodelsmodule.cpp
+++ b/src/qmlmodels/qqmlmodelsmodule.cpp
@@ -62,58 +62,23 @@
QT_BEGIN_NAMESPACE
-#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
-
-void QQmlModelsModule::registerQmlTypes()
-{
- // Don't add anything here. These are only for backwards compatibility.
-#if QT_CONFIG(qml_object_model)
- qmlRegisterType<QQmlInstantiator>("QtQml", 2, 1, "Instantiator"); // Only available in >= 2.1
- qmlRegisterType<QQmlInstanceModel>();
-#endif
-}
-
-void QQmlModelsModule::registerQuickTypes()
-{
- // Don't add anything here. These are only for backwards compatibility.
-
- const char uri[] = "QtQuick";
-
-#if QT_CONFIG(qml_object_model)
- qmlRegisterType<QQmlInstantiator>(uri, 2, 1, "Instantiator");
- qmlRegisterType<QQmlInstanceModel>();
- qmlRegisterType<QQmlObjectModel>(uri, 2, 0, "VisualItemModel");
-#endif
-#if QT_CONFIG(qml_list_model)
- qmlRegisterType<QQmlListElement>(uri, 2, 0, "ListElement");
- qmlRegisterCustomType<QQmlListModel>(uri, 2, 0, "ListModel", new QQmlListModelParser);
-#endif
-#if QT_CONFIG(qml_delegate_model)
- qmlRegisterType<QQmlDelegateModel>(uri, 2, 0, "VisualDataModel");
- qmlRegisterType<QQmlDelegateModelGroup>(uri, 2, 0, "VisualDataGroup");
- qmlRegisterType<QQuickPackage>(uri, 2, 0, "Package");
-#endif
-}
-
-#endif // QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
-
void QQmlModelsModule::defineModule()
{
const char uri[] = "QtQml.Models";
#if QT_CONFIG(qml_list_model)
- qmlRegisterType<QQmlListElement>(uri, 2, 1, "ListElement");
- qmlRegisterCustomType<QQmlListModel>(uri, 2, 1, "ListModel", new QQmlListModelParser);
+ qmlRegisterType<QQmlListElement>(uri, 2, 0, "ListElement");
+ qmlRegisterCustomType<QQmlListModel>(uri, 2, 0, "ListModel", new QQmlListModelParser);
#endif
#if QT_CONFIG(qml_delegate_model)
qmlRegisterType<QQmlDelegateModel>(uri, 2, 1, "DelegateModel");
qmlRegisterType<QQmlDelegateModelGroup>(uri, 2, 1, "DelegateModelGroup");
- qmlRegisterType<QQuickPackage>(uri, 2, 14, "Package");
+ qmlRegisterType<QQuickPackage>(uri, 2, 0, "Package");
#endif
#if QT_CONFIG(qml_object_model)
qmlRegisterType<QQmlObjectModel>(uri, 2, 1, "ObjectModel");
qmlRegisterType<QQmlObjectModel,3>(uri, 2, 3, "ObjectModel");
- qmlRegisterType<QQmlInstantiator>(uri, 2, 14, "Instantiator");
+ qmlRegisterType<QQmlInstantiator>(uri, 2, 1, "Instantiator");
qmlRegisterType<QQmlInstanceModel>();
#endif
#if QT_CONFIG(itemmodel)
diff --git a/src/qmlmodels/qqmlmodelsmodule_p.h b/src/qmlmodels/qqmlmodelsmodule_p.h
index 7e02578db9..f63052b682 100644
--- a/src/qmlmodels/qqmlmodelsmodule_p.h
+++ b/src/qmlmodels/qqmlmodelsmodule_p.h
@@ -58,11 +58,6 @@ QT_BEGIN_NAMESPACE
class Q_QMLMODELS_PRIVATE_EXPORT QQmlModelsModule
{
public:
-#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
- static void registerQmlTypes();
- static void registerQuickTypes();
-#endif
-
static void defineModule();
static void defineLabsModule();
};
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/qmlworkerscript/qqmlworkerscriptmodule.cpp b/src/qmlworkerscript/qqmlworkerscriptmodule.cpp
index 98e82dbeba..5eb7d306bc 100644
--- a/src/qmlworkerscript/qqmlworkerscriptmodule.cpp
+++ b/src/qmlworkerscript/qqmlworkerscriptmodule.cpp
@@ -42,17 +42,6 @@
QT_BEGIN_NAMESPACE
-#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
-
-void QQmlWorkerScriptModule::registerQuickTypes()
-{
- // Don't add anything here. These are only for backwards compatibility.
- const char uri[] = "QtQuick";
- qmlRegisterType<QQuickWorkerScript>(uri, 2, 0, "WorkerScript");
-}
-
-#endif // QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
-
void QQmlWorkerScriptModule::defineModule()
{
const char uri[] = "QtQml.WorkerScript";
diff --git a/src/qmlworkerscript/qqmlworkerscriptmodule_p.h b/src/qmlworkerscript/qqmlworkerscriptmodule_p.h
index a2efb304c1..ae52d10c16 100644
--- a/src/qmlworkerscript/qqmlworkerscriptmodule_p.h
+++ b/src/qmlworkerscript/qqmlworkerscriptmodule_p.h
@@ -58,9 +58,6 @@ QT_BEGIN_NAMESPACE
class Q_QMLWORKERSCRIPT_PRIVATE_EXPORT QQmlWorkerScriptModule
{
public:
-#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
- static void registerQuickTypes();
-#endif
static void defineModule();
};
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..e6090e66ba 100644
--- a/src/quick/items/qquickitemsmodule.cpp
+++ b/src/quick/items/qquickitemsmodule.cpp
@@ -180,8 +180,7 @@ static void qt_quickitems_defineModule(const char *uri, int major, int minor)
QQmlPrivate::RegisterAutoParent autoparent = { 0, &qquickitem_autoParent };
QQmlPrivate::qmlregister(QQmlPrivate::AutoParentRegistration, &autoparent);
- // Register the latest version, even if there are no new types or new revisions for existing types yet.
- qmlRegisterModule(uri, 2, QT_VERSION_MINOR);
+ qmlRegisterModule(uri, 2, 15);
#if !QT_CONFIG(quick_animatedimage)
qmlRegisterTypeNotAvailable(uri,major,minor,"AnimatedImage", QCoreApplication::translate("QQuickAnimatedImage","Qt was built without support for QMovie"));
@@ -477,9 +476,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>
diff --git a/tests/auto/qml/qmlcachegen/tst_qmlcachegen.cpp b/tests/auto/qml/qmlcachegen/tst_qmlcachegen.cpp
index 5462e6c8ae..102acf73d6 100644
--- a/tests/auto/qml/qmlcachegen/tst_qmlcachegen.cpp
+++ b/tests/auto/qml/qmlcachegen/tst_qmlcachegen.cpp
@@ -36,6 +36,7 @@
#include <QSysInfo>
#include <QLoggingCategory>
#include <private/qqmlcomponent_p.h>
+#include <private/qqmlscriptdata_p.h>
#include <qtranslator.h>
#include "../../shared/util.h"
diff --git a/tests/auto/qml/qmldiskcache/tst_qmldiskcache.cpp b/tests/auto/qml/qmldiskcache/tst_qmldiskcache.cpp
index 23be541a72..1f0115b926 100644
--- a/tests/auto/qml/qmldiskcache/tst_qmldiskcache.cpp
+++ b/tests/auto/qml/qmldiskcache/tst_qmldiskcache.cpp
@@ -34,6 +34,7 @@
#include <private/qv4codegen_p.h>
#include <private/qqmlcomponent_p.h>
#include <private/qv4executablecompilationunit_p.h>
+#include <private/qqmlscriptdata_p.h>
#include <QQmlComponent>
#include <QQmlEngine>
#include <QQmlFileSelector>
diff --git a/tests/auto/qml/qmllint/data/FromRoot.qml b/tests/auto/qml/qmllint/data/FromRoot.qml
new file mode 100644
index 0000000000..021c09285e
--- /dev/null
+++ b/tests/auto/qml/qmllint/data/FromRoot.qml
@@ -0,0 +1,17 @@
+import QtQuick 2.0
+
+Item {
+ id: root
+ property int unqualified: 42
+
+ Item {
+ Item {
+ x: unqualified // user defined property from root
+ }
+
+ QtObject {
+ property int check: x // existing property from root
+ }
+ }
+
+}
diff --git a/tests/auto/qml/qmllint/data/FromRootDirectParent.qml b/tests/auto/qml/qmllint/data/FromRootDirectParent.qml
new file mode 100644
index 0000000000..c0bfd0f26b
--- /dev/null
+++ b/tests/auto/qml/qmllint/data/FromRootDirectParent.qml
@@ -0,0 +1,14 @@
+import QtQuick 2.0
+
+Item {
+ id: root
+ property int unqualified: 42
+
+ Item {
+ x: unqualified // user defined property from root
+ }
+
+ QtObject {
+ property int check: x // existing property from root
+ }
+}
diff --git a/tests/auto/qml/qmllint/data/IdFromOuterSpace.qml b/tests/auto/qml/qmllint/data/IdFromOuterSpace.qml
new file mode 100644
index 0000000000..774a1cfc7c
--- /dev/null
+++ b/tests/auto/qml/qmllint/data/IdFromOuterSpace.qml
@@ -0,0 +1,9 @@
+import QtQuick 2.0
+
+Item {
+ x: alien.x
+
+ Component.onCompleted: {
+ console.log(alien);
+ }
+}
diff --git a/tests/auto/qml/qmllint/data/SignalHandler.qml b/tests/auto/qml/qmllint/data/SignalHandler.qml
new file mode 100644
index 0000000000..bdf503e3dc
--- /dev/null
+++ b/tests/auto/qml/qmllint/data/SignalHandler.qml
@@ -0,0 +1,5 @@
+import QtQuick 2.0
+
+MouseArea {
+ onDoubleClicked: console.log(mouse);
+}
diff --git a/tests/auto/qml/qmllint/data/WithStatement.qml b/tests/auto/qml/qmllint/data/WithStatement.qml
new file mode 100644
index 0000000000..5641f21eeb
--- /dev/null
+++ b/tests/auto/qml/qmllint/data/WithStatement.qml
@@ -0,0 +1,13 @@
+import QtQuick 2.0
+
+Item {
+ Item {
+ id: target
+ property int test: 42
+ }
+ Component.onCompleted: {
+ with(target) {
+ console.log(test);
+ }
+ }
+}
diff --git a/tests/auto/qml/qmllint/main.cpp b/tests/auto/qml/qmllint/main.cpp
index eedbd7c2f2..038826790b 100644
--- a/tests/auto/qml/qmllint/main.cpp
+++ b/tests/auto/qml/qmllint/main.cpp
@@ -38,6 +38,8 @@ private Q_SLOTS:
void initTestCase();
void test();
void test_data();
+ void testUnqualified();
+ void testUnqualified_data();
private:
QString m_qmllintPath;
};
@@ -69,6 +71,49 @@ void TestQmllint::test_data()
QTest::newRow("Invalid_syntax_JS") << QStringLiteral("failure1.js") << false;
}
+void TestQmllint::testUnqualified()
+{
+ QFETCH(QString, filename);
+ QFETCH(QString, warningMessage);
+ QFETCH(int, warningLine);
+ QFETCH(int, warningColumn);
+ filename.prepend(QStringLiteral("data/"));
+ QStringList args;
+ args << QStringLiteral("-U") << filename;
+
+ QProcess process;
+ process.start(m_qmllintPath, args);
+ QVERIFY(process.waitForFinished());
+ QVERIFY(process.exitStatus() == QProcess::NormalExit);
+ QVERIFY(process.exitCode());
+ QString output = process.readAllStandardError();
+ QVERIFY(output.contains(QString::asprintf("Warning: unqualified access at %d:%d", warningLine, warningColumn)));
+ QVERIFY(output.contains(warningMessage));
+}
+
+void TestQmllint::testUnqualified_data()
+{
+ QTest::addColumn<QString>("filename");
+ QTest::addColumn<QString>("warningMessage");
+ QTest::addColumn<int>("warningLine");
+ QTest::addColumn<int>("warningColumn");
+
+ // check for false positive due to and warning about with statement
+ QTest::newRow("WithStatement") << QStringLiteral("WithStatement.qml") << QStringLiteral("with statements are strongly discouraged") << 10 << 25;
+ // id from nowhere (as with setContextProperty)
+ QTest::newRow("IdFromOuterSpaceDirect") << QStringLiteral("IdFromOuterSpace.qml") << "alien.x" << 4 << 8;
+ QTest::newRow("IdFromOuterSpaceAccess") << QStringLiteral("IdFromOuterSpace.qml") << "console.log(alien)" << 7 << 21;
+ // access property of root object
+ QTest::newRow("FromRootDirect") << QStringLiteral("FromRoot.qml") << QStringLiteral("x: root.unqualified") << 9 << 16; // new property
+ QTest::newRow("FromRootAccess") << QStringLiteral("FromRoot.qml") << QStringLiteral("property int check: root.x") << 13 << 33; // builtin property
+ // access property of root object from direct child
+ QTest::newRow("FromRootDirectParentDirect") << QStringLiteral("FromRootDirectParent.qml") << QStringLiteral("x: parent.unqualified") << 8 << 12;
+ QTest::newRow("FromRootDirectParentAccess") << QStringLiteral("FromRootDirectParent.qml") << QStringLiteral("property int check: parent.x") << 12 << 29;
+ // access injected name from signal
+ QTest::newRow("SignalHandler") << QStringLiteral("SignalHandler.qml") << QStringLiteral("onDoubleClicked: function(mouse) {...") << 4 << 34;
+
+}
+
void TestQmllint::test()
{
QFETCH(QString, filename);
diff --git a/tests/auto/qml/qqmlcomponent/tst_qqmlcomponent.cpp b/tests/auto/qml/qqmlcomponent/tst_qqmlcomponent.cpp
index 6a3bf53a31..71d3e8fe5f 100644
--- a/tests/auto/qml/qqmlcomponent/tst_qqmlcomponent.cpp
+++ b/tests/auto/qml/qqmlcomponent/tst_qqmlcomponent.cpp
@@ -120,6 +120,7 @@ private slots:
void setNonExistentInitialProperty();
void relativeUrl_data();
void relativeUrl();
+ void setDataNoEngineNoSegfault();
private:
QQmlEngine engine;
@@ -655,6 +656,17 @@ void tst_qqmlcomponent::relativeUrl()
QVERIFY2(!component.isError(), qPrintable(component.errorString()));
}
+void tst_qqmlcomponent::setDataNoEngineNoSegfault()
+{
+ QQmlEngine eng;
+ QQmlComponent comp;
+ QTest::ignoreMessage(QtWarningMsg, "QQmlComponent: Must provide an engine before calling setData");
+ comp.setData("import QtQuick 1.0; QtObject { }", QUrl(""));
+ QTest::ignoreMessage(QtWarningMsg, "QQmlComponent: Must provide an engine before calling create");
+ auto c = comp.create();
+ QVERIFY(!c);
+}
+
QTEST_MAIN(tst_qqmlcomponent)
#include "tst_qqmlcomponent.moc"
diff --git a/tests/auto/qml/qqmlconnections/tst_qqmlconnections.cpp b/tests/auto/qml/qqmlconnections/tst_qqmlconnections.cpp
index dc29363fcf..7e6a0f79f9 100644
--- a/tests/auto/qml/qqmlconnections/tst_qqmlconnections.cpp
+++ b/tests/auto/qml/qqmlconnections/tst_qqmlconnections.cpp
@@ -428,7 +428,7 @@ void tst_qqmlconnections::noAcceleratedGlobalLookup()
QVERIFY(c.isReady());
QScopedPointer<QObject> object(c.create());
const QVariant val = object->property("testEnum");
- QCOMPARE(val.type(), QMetaType::Int);
+ QCOMPARE(val.type(), int(QMetaType::Int));
QCOMPARE(val.toInt(), int(Proxy::EnumValue));
}
diff --git a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp
index b1a1ed4dec..d603ca6907 100644
--- a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp
+++ b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp
@@ -47,6 +47,7 @@
#include <private/qv4alloca_p.h>
#include <private/qv4runtime_p.h>
#include <private/qv4object_p.h>
+#include <private/qv4script_p.h>
#include <private/qqmlcomponentattached_p.h>
#include <private/qv4objectiterator_p.h>
#include <private/qqmlabstractbinding_p.h>
diff --git a/tests/auto/qml/qqmlengine/tst_qqmlengine.cpp b/tests/auto/qml/qqmlengine/tst_qqmlengine.cpp
index e55cd6f7a0..66d50cfe39 100644
--- a/tests/auto/qml/qqmlengine/tst_qqmlengine.cpp
+++ b/tests/auto/qml/qqmlengine/tst_qqmlengine.cpp
@@ -43,6 +43,7 @@
#include <QQmlIncubationController>
#include <QTemporaryDir>
#include <private/qqmlengine_p.h>
+#include <private/qqmltypedata_p.h>
#include <QQmlAbstractUrlInterceptor>
class tst_qqmlengine : public QQmlDataTest
diff --git a/tests/auto/qml/qqmllanguage/data/functionParameterTypes.qml b/tests/auto/qml/qqmllanguage/data/functionParameterTypes.qml
new file mode 100644
index 0000000000..26931a4f10
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/functionParameterTypes.qml
@@ -0,0 +1,7 @@
+import QtQuick 2.0 as QQ
+import QtQml 2.0 as Core
+QQ.Item {
+ id: root
+ function returnItem() : Core.QtObject { return root; }
+ function takeString(arg: string) { return arg; }
+}
diff --git a/tests/auto/qml/qqmllanguage/data/signalParameterTypes.3.qml b/tests/auto/qml/qqmllanguage/data/signalParameterTypes.3.qml
new file mode 100644
index 0000000000..6dee30de95
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/signalParameterTypes.3.qml
@@ -0,0 +1,19 @@
+import QtQml 2.0
+
+QtObject {
+ id: root
+
+ property bool success: false
+
+ signal testSignal(param: bool)
+
+ function handleTestSignal(param) {
+ success = param
+ }
+
+ Component.onCompleted: {
+ success = false;
+ root.testSignal.connect(handleTestSignal)
+ root.testSignal(true);
+ }
+}
diff --git a/tests/auto/qml/qqmllanguage/data/typeAnnotations.2.errors.txt b/tests/auto/qml/qqmllanguage/data/typeAnnotations.2.errors.txt
new file mode 100644
index 0000000000..b316acae30
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/typeAnnotations.2.errors.txt
@@ -0,0 +1 @@
+5:14:Type annotations are not permitted in variable declarations
diff --git a/tests/auto/qml/qqmllanguage/data/typeAnnotations.2.qml b/tests/auto/qml/qqmllanguage/data/typeAnnotations.2.qml
new file mode 100644
index 0000000000..655fe4c226
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/typeAnnotations.2.qml
@@ -0,0 +1,8 @@
+import QtQml 2.0
+
+QtObject {
+ function notYet() {
+ var x: string = "ko"
+ return x
+ }
+}
diff --git a/tests/auto/qml/qqmllanguage/testtypes.cpp b/tests/auto/qml/qqmllanguage/testtypes.cpp
index d6215307bf..ffb1d51971 100644
--- a/tests/auto/qml/qqmllanguage/testtypes.cpp
+++ b/tests/auto/qml/qqmllanguage/testtypes.cpp
@@ -27,6 +27,8 @@
****************************************************************************/
#include "testtypes.h"
+#include <private/qv4qmlcontext_p.h>
+
static QObject *myTypeObjectSingleton(QQmlEngine *engine, QJSEngine *scriptEngine)
{
Q_UNUSED(engine)
diff --git a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp
index 8cbb39974e..a54c4b35d4 100644
--- a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp
+++ b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp
@@ -208,6 +208,7 @@ private slots:
void remoteLoadCrash();
void signalWithDefaultArg();
void signalParameterTypes();
+ void functionParameterTypes();
// regression tests for crashes
void crash1();
@@ -622,6 +623,8 @@ void tst_qqmllanguage::errors_data()
QTest::newRow("fuzzed.2") << "fuzzed.2.qml" << "fuzzed.2.errors.txt" << false;
QTest::newRow("bareQmlImport") << "bareQmlImport.qml" << "bareQmlImport.errors.txt" << false;
+
+ QTest::newRow("typeAnnotations.2") << "typeAnnotations.2.qml" << "typeAnnotations.2.errors.txt" << false;
}
@@ -3696,6 +3699,38 @@ void tst_qqmllanguage::signalParameterTypes()
QVERIFY(obj != nullptr);
QVERIFY(obj->property("success").toBool());
}
+
+ // dynamic signal connections
+ {
+ QQmlComponent component(&engine, testFileUrl("signalParameterTypes.3.qml"));
+ QScopedPointer<QObject> obj(component.create());
+ QVERIFY(obj != nullptr);
+ QVERIFY(obj->property("success").toBool());
+ }
+}
+
+void tst_qqmllanguage::functionParameterTypes()
+{
+ QQmlComponent component(&engine, testFileUrl("functionParameterTypes.qml"));
+ QScopedPointer<QObject> obj(component.create());
+ QVERIFY2(!obj.isNull(), qPrintable(component.errorString()));
+ const QMetaObject *metaObject = obj->metaObject();
+
+ {
+ QMetaMethod slot = metaObject->method(metaObject->indexOfSlot("returnItem()"));
+ QVERIFY(slot.isValid());
+ QCOMPARE(slot.returnType(), QMetaType::type("QObject*"));
+ QObject *returnedPtr = nullptr;
+ slot.invoke(obj.data(), Qt::DirectConnection, Q_RETURN_ARG(QObject*, returnedPtr));
+ QCOMPARE(returnedPtr, obj.data());
+ }
+
+ {
+ QMetaMethod slot = metaObject->method(metaObject->indexOfSlot("takeString(QString)"));
+ QVERIFY(slot.isValid());
+ QCOMPARE(slot.parameterCount(), 1);
+ QCOMPARE(slot.parameterType(0), int(QMetaType::QString));
+ }
}
// QTBUG-20639
diff --git a/tests/auto/qml/qqmlmoduleplugin/tst_qqmlmoduleplugin.cpp b/tests/auto/qml/qqmlmoduleplugin/tst_qqmlmoduleplugin.cpp
index 3148ffb5a5..82aa265465 100644
--- a/tests/auto/qml/qqmlmoduleplugin/tst_qqmlmoduleplugin.cpp
+++ b/tests/auto/qml/qqmlmoduleplugin/tst_qqmlmoduleplugin.cpp
@@ -103,7 +103,7 @@ public:
qmlRegisterModule(uri, 1, 0);
}
- void initializeEngine(QQmlEngine *engine, const char *uri) override
+ void initializeEngine(QQmlEngine *, const char *) override
{
initializeEngineEntered.lock();
leavingInitializeEngine.lock();
diff --git a/tests/auto/qml/qqmlparser/data/disallowedtypeannotations/anonfunctionexpr.js b/tests/auto/qml/qqmlparser/data/disallowedtypeannotations/anonfunctionexpr.js
new file mode 100644
index 0000000000..f660edb69e
--- /dev/null
+++ b/tests/auto/qml/qqmlparser/data/disallowedtypeannotations/anonfunctionexpr.js
@@ -0,0 +1,3 @@
+(function () : string {
+ return "ko"
+})
diff --git a/tests/auto/qml/qqmlparser/data/disallowedtypeannotations/classmemberparam.js b/tests/auto/qml/qqmlparser/data/disallowedtypeannotations/classmemberparam.js
new file mode 100644
index 0000000000..ab85d90880
--- /dev/null
+++ b/tests/auto/qml/qqmlparser/data/disallowedtypeannotations/classmemberparam.js
@@ -0,0 +1,6 @@
+
+class Foo {
+ member(param: string) {
+ return "ko"
+ }
+}
diff --git a/tests/auto/qml/qqmlparser/data/disallowedtypeannotations/classreturnvalue.js b/tests/auto/qml/qqmlparser/data/disallowedtypeannotations/classreturnvalue.js
new file mode 100644
index 0000000000..a7da9e0ca7
--- /dev/null
+++ b/tests/auto/qml/qqmlparser/data/disallowedtypeannotations/classreturnvalue.js
@@ -0,0 +1,6 @@
+
+class Foo {
+ member(): string {
+ return "ko"
+ }
+}
diff --git a/tests/auto/qml/qqmlparser/data/disallowedtypeannotations/function.js b/tests/auto/qml/qqmlparser/data/disallowedtypeannotations/function.js
new file mode 100644
index 0000000000..4d6021e835
--- /dev/null
+++ b/tests/auto/qml/qqmlparser/data/disallowedtypeannotations/function.js
@@ -0,0 +1,4 @@
+
+function x() : string {
+ return "ok"
+}
diff --git a/tests/auto/qml/qqmlparser/data/disallowedtypeannotations/functionexpr.js b/tests/auto/qml/qqmlparser/data/disallowedtypeannotations/functionexpr.js
new file mode 100644
index 0000000000..33f2abbb61
--- /dev/null
+++ b/tests/auto/qml/qqmlparser/data/disallowedtypeannotations/functionexpr.js
@@ -0,0 +1,3 @@
+(function x() : string {
+ return "ko"
+})
diff --git a/tests/auto/qml/qqmlparser/data/disallowedtypeannotations/functionparams.js b/tests/auto/qml/qqmlparser/data/disallowedtypeannotations/functionparams.js
new file mode 100644
index 0000000000..2c23628e3f
--- /dev/null
+++ b/tests/auto/qml/qqmlparser/data/disallowedtypeannotations/functionparams.js
@@ -0,0 +1,3 @@
+
+function test(x: string, y: string) {
+}
diff --git a/tests/auto/qml/qqmlparser/data/disallowedtypeannotations/iteration.js b/tests/auto/qml/qqmlparser/data/disallowedtypeannotations/iteration.js
new file mode 100644
index 0000000000..a6cc00e38a
--- /dev/null
+++ b/tests/auto/qml/qqmlparser/data/disallowedtypeannotations/iteration.js
@@ -0,0 +1,3 @@
+
+for (var i: int = 0; i < 100; ++i) {
+}
diff --git a/tests/auto/qml/qqmlparser/data/disallowedtypeannotations/iteration2.js b/tests/auto/qml/qqmlparser/data/disallowedtypeannotations/iteration2.js
new file mode 100644
index 0000000000..24d5acce98
--- /dev/null
+++ b/tests/auto/qml/qqmlparser/data/disallowedtypeannotations/iteration2.js
@@ -0,0 +1,5 @@
+
+let y = [1, 2, 3];
+
+for (let x: int of y) {
+}
diff --git a/tests/auto/qml/qqmlparser/data/disallowedtypeannotations/qmlnestedfunction.qml b/tests/auto/qml/qqmlparser/data/disallowedtypeannotations/qmlnestedfunction.qml
new file mode 100644
index 0000000000..f435bf1b25
--- /dev/null
+++ b/tests/auto/qml/qqmlparser/data/disallowedtypeannotations/qmlnestedfunction.qml
@@ -0,0 +1,9 @@
+import QtQuick 2.12 as MyQuick
+MyQuick.Item {
+ function factory(param: string) : MyQuick.Item {
+ function nested(foo: string) {
+ return this
+ }
+ return nested()
+ }
+}
diff --git a/tests/auto/qml/qqmlparser/data/disallowedtypeannotations/variables.js b/tests/auto/qml/qqmlparser/data/disallowedtypeannotations/variables.js
new file mode 100644
index 0000000000..bf332ac7a8
--- /dev/null
+++ b/tests/auto/qml/qqmlparser/data/disallowedtypeannotations/variables.js
@@ -0,0 +1,2 @@
+
+var x: string = "ko"
diff --git a/tests/auto/qml/qqmlparser/data/typeannotations/basic_qmltypes_bool.qml b/tests/auto/qml/qqmlparser/data/typeannotations/basic_qmltypes_bool.qml
new file mode 100644
index 0000000000..79a9ede3d4
--- /dev/null
+++ b/tests/auto/qml/qqmlparser/data/typeannotations/basic_qmltypes_bool.qml
@@ -0,0 +1,4 @@
+import QtQml 2.0
+QtObject {
+ function test() : bool { return true; }
+}
diff --git a/tests/auto/qml/qqmlparser/data/typeannotations/basic_qmltypes_double.qml b/tests/auto/qml/qqmlparser/data/typeannotations/basic_qmltypes_double.qml
new file mode 100644
index 0000000000..f58e4b92d9
--- /dev/null
+++ b/tests/auto/qml/qqmlparser/data/typeannotations/basic_qmltypes_double.qml
@@ -0,0 +1,4 @@
+import QtQml 2.0
+QtObject {
+ function test() : double { return 0; }
+}
diff --git a/tests/auto/qml/qqmlparser/data/typeannotations/basic_qmltypes_int.qml b/tests/auto/qml/qqmlparser/data/typeannotations/basic_qmltypes_int.qml
new file mode 100644
index 0000000000..267ad7191f
--- /dev/null
+++ b/tests/auto/qml/qqmlparser/data/typeannotations/basic_qmltypes_int.qml
@@ -0,0 +1,4 @@
+import QtQml 2.0
+QtObject {
+ function test() : int { return 0; }
+}
diff --git a/tests/auto/qml/qqmlparser/data/typeannotations/basic_qmltypes_real.qml b/tests/auto/qml/qqmlparser/data/typeannotations/basic_qmltypes_real.qml
new file mode 100644
index 0000000000..9973819ad2
--- /dev/null
+++ b/tests/auto/qml/qqmlparser/data/typeannotations/basic_qmltypes_real.qml
@@ -0,0 +1,4 @@
+import QtQml 2.0
+QtObject {
+ function test() : real { return 0; }
+}
diff --git a/tests/auto/qml/qqmlparser/data/typeannotations/basic_qmltypes_string.qml b/tests/auto/qml/qqmlparser/data/typeannotations/basic_qmltypes_string.qml
new file mode 100644
index 0000000000..e632ec7154
--- /dev/null
+++ b/tests/auto/qml/qqmlparser/data/typeannotations/basic_qmltypes_string.qml
@@ -0,0 +1,4 @@
+import QtQml 2.0
+QtObject {
+ function test(s: string) {}
+}
diff --git a/tests/auto/qml/qqmlparser/data/typeannotations/basic_qmltypes_url.qml b/tests/auto/qml/qqmlparser/data/typeannotations/basic_qmltypes_url.qml
new file mode 100644
index 0000000000..ebf3f32561
--- /dev/null
+++ b/tests/auto/qml/qqmlparser/data/typeannotations/basic_qmltypes_url.qml
@@ -0,0 +1,4 @@
+import QtQml 2.0
+QtObject {
+ function test(u: url) {}
+}
diff --git a/tests/auto/qml/qqmlparser/data/typeannotations/parametrized.qml b/tests/auto/qml/qqmlparser/data/typeannotations/parametrized.qml
new file mode 100644
index 0000000000..d80b5e3f87
--- /dev/null
+++ b/tests/auto/qml/qqmlparser/data/typeannotations/parametrized.qml
@@ -0,0 +1,5 @@
+import QtQuick 2.0 as MyQuick
+MyQuick.Item {
+ function factory() : list<MyQuick.Item> {
+ }
+}
diff --git a/tests/auto/qml/qqmlparser/data/typeannotations/qmlfunction.qml b/tests/auto/qml/qqmlparser/data/typeannotations/qmlfunction.qml
new file mode 100644
index 0000000000..cd5c1f51e5
--- /dev/null
+++ b/tests/auto/qml/qqmlparser/data/typeannotations/qmlfunction.qml
@@ -0,0 +1,6 @@
+import QtQuick 2.12 as MyQuick
+MyQuick.Item {
+ function factory(param: string) : MyQuick.Item {
+ return this
+ }
+}
diff --git a/tests/auto/qml/qqmlparser/qqmlparser.pro b/tests/auto/qml/qqmlparser/qqmlparser.pro
index 74cb620f06..d8e4b0dd06 100644
--- a/tests/auto/qml/qqmlparser/qqmlparser.pro
+++ b/tests/auto/qml/qqmlparser/qqmlparser.pro
@@ -7,3 +7,7 @@ SOURCES += tst_qqmlparser.cpp
DEFINES += SRCDIR=\\\"$$PWD\\\"
cross_compile: DEFINES += QTEST_CROSS_COMPILED
+
+TESTDATA = data/*
+
+include (../../shared/util.pri)
diff --git a/tests/auto/qml/qqmlparser/tst_qqmlparser.cpp b/tests/auto/qml/qqmlparser/tst_qqmlparser.cpp
index 5f58df75d4..9d8818d01e 100644
--- a/tests/auto/qml/qqmlparser/tst_qqmlparser.cpp
+++ b/tests/auto/qml/qqmlparser/tst_qqmlparser.cpp
@@ -32,12 +32,14 @@
#include <private/qqmljsastvisitor_p.h>
#include <private/qqmljsast_p.h>
+#include "../../shared/util.h"
+
#include <qtest.h>
#include <QDir>
#include <QDebug>
#include <cstdlib>
-class tst_qqmlparser : public QObject
+class tst_qqmlparser : public QQmlDataTest
{
Q_OBJECT
public:
@@ -56,6 +58,10 @@ private slots:
void leadingSemicolonInClass();
void templatedReadonlyProperty();
void qmlImportInJSRequiresFullVersion();
+ void typeAnnotations_data();
+ void typeAnnotations();
+ void disallowedTypeAnnotations_data();
+ void disallowedTypeAnnotations();
private:
QStringList excludedDirs;
@@ -88,7 +94,7 @@ public:
qDebug() << "first source loc failed: node:" << node->kind << "at" << node->firstSourceLocation().startLine << "/" << node->firstSourceLocation().startColumn
<< "parent" << parent->kind << "at" << parent->firstSourceLocation().startLine << "/" << parent->firstSourceLocation().startColumn;
if (node->lastSourceLocation().end() > parentEnd)
- qDebug() << "first source loc failed: node:" << node->kind << "at" << node->lastSourceLocation().startLine << "/" << node->lastSourceLocation().startColumn
+ qDebug() << "last source loc failed: node:" << node->kind << "at" << node->lastSourceLocation().startLine << "/" << node->lastSourceLocation().startColumn
<< "parent" << parent->kind << "at" << parent->lastSourceLocation().startLine << "/" << parent->lastSourceLocation().startColumn;
QVERIFY(node->firstSourceLocation().begin() >= parentBegin);
@@ -114,6 +120,27 @@ public:
}
};
+struct TypeAnnotationObserver: public AST::Visitor
+{
+ bool typeAnnotationSeen = false;
+
+ void operator()(AST::Node *node)
+ {
+ AST::Node::accept(node, this);
+ }
+
+ virtual bool visit(AST::TypeAnnotation *)
+ {
+ typeAnnotationSeen = true;
+ return true;
+ }
+
+ void throwRecursionDepthError() final
+ {
+ QFAIL("Maximum statement or expression depth exceeded");
+ }
+};
+
}
tst_qqmlparser::tst_qqmlparser()
@@ -122,6 +149,7 @@ tst_qqmlparser::tst_qqmlparser()
void tst_qqmlparser::initTestCase()
{
+ QQmlDataTest::initTestCase();
// Add directories you want excluded here
// These snippets are not expected to run on their own.
@@ -334,6 +362,82 @@ void tst_qqmlparser::qmlImportInJSRequiresFullVersion()
}
}
+void tst_qqmlparser::typeAnnotations_data()
+{
+ QTest::addColumn<QString>("file");
+
+ QString tests = dataDirectory() + "/typeannotations/";
+
+ QStringList files;
+ files << findFiles(QDir(tests));
+
+ for (const QString &file: qAsConst(files))
+ QTest::newRow(qPrintable(file)) << file;
+}
+
+void tst_qqmlparser::typeAnnotations()
+{
+ using namespace QQmlJS;
+
+ QFETCH(QString, file);
+
+ QString code;
+
+ QFile f(file);
+ if (f.open(QFile::ReadOnly))
+ code = QString::fromUtf8(f.readAll());
+
+ const bool qmlMode = file.endsWith(QLatin1String(".qml"));
+
+ Engine engine;
+ Lexer lexer(&engine);
+ lexer.setCode(code, 1, qmlMode);
+ Parser parser(&engine);
+ bool ok = qmlMode ? parser.parse() : parser.parseProgram();
+ QVERIFY(ok);
+
+ check::TypeAnnotationObserver observer;
+ observer(parser.rootNode());
+
+ QVERIFY(observer.typeAnnotationSeen);
+}
+
+void tst_qqmlparser::disallowedTypeAnnotations_data()
+{
+ QTest::addColumn<QString>("file");
+
+ QString tests = dataDirectory() + "/disallowedtypeannotations/";
+
+ QStringList files;
+ files << findFiles(QDir(tests));
+
+ for (const QString &file: qAsConst(files))
+ QTest::newRow(qPrintable(file)) << file;
+}
+
+void tst_qqmlparser::disallowedTypeAnnotations()
+{
+ using namespace QQmlJS;
+
+ QFETCH(QString, file);
+
+ QString code;
+
+ QFile f(file);
+ if (f.open(QFile::ReadOnly))
+ code = QString::fromUtf8(f.readAll());
+
+ const bool qmlMode = file.endsWith(QLatin1String(".qml"));
+
+ Engine engine;
+ Lexer lexer(&engine);
+ lexer.setCode(code, 1, qmlMode);
+ Parser parser(&engine);
+ bool ok = qmlMode ? parser.parse() : parser.parseProgram();
+ QVERIFY(!ok);
+ QVERIFY2(parser.errorMessage().startsWith("Type annotations are not permitted "), qPrintable(parser.errorMessage()));
+}
+
QTEST_MAIN(tst_qqmlparser)
#include "tst_qqmlparser.moc"
diff --git a/tests/auto/qml/qqmltranslation/tst_qqmltranslation.cpp b/tests/auto/qml/qqmltranslation/tst_qqmltranslation.cpp
index 3b17df9872..dcfe914af6 100644
--- a/tests/auto/qml/qqmltranslation/tst_qqmltranslation.cpp
+++ b/tests/auto/qml/qqmltranslation/tst_qqmltranslation.cpp
@@ -32,6 +32,7 @@
#include <QTranslator>
#include <QQmlContext>
#include <private/qqmlengine_p.h>
+#include <private/qqmltypedata_p.h>
#include "../../shared/util.h"
class tst_qqmltranslation : public QQmlDataTest
diff --git a/tests/auto/qml/qqmltypeloader/data/implicitimporttest.qml b/tests/auto/qml/qqmltypeloader/data/implicitimporttest.qml
new file mode 100644
index 0000000000..7a054e199b
--- /dev/null
+++ b/tests/auto/qml/qqmltypeloader/data/implicitimporttest.qml
@@ -0,0 +1,5 @@
+import modulewithimplicitimport 2.0 as MyNS
+MyNS.Test {
+ MyNS.Item {} // Implicitly imported from QtQuick
+ MyNS.ListModel {}
+}
diff --git a/tests/auto/qml/qqmltypeloader/data/imports/modulewithimplicitimport/Test.qml b/tests/auto/qml/qqmltypeloader/data/imports/modulewithimplicitimport/Test.qml
new file mode 100644
index 0000000000..2f78302506
--- /dev/null
+++ b/tests/auto/qml/qqmltypeloader/data/imports/modulewithimplicitimport/Test.qml
@@ -0,0 +1,3 @@
+import QtQuick 2.0
+Item {
+}
diff --git a/tests/auto/qml/qqmltypeloader/data/imports/modulewithimplicitimport/qmldir b/tests/auto/qml/qqmltypeloader/data/imports/modulewithimplicitimport/qmldir
new file mode 100644
index 0000000000..10e8f90f62
--- /dev/null
+++ b/tests/auto/qml/qqmltypeloader/data/imports/modulewithimplicitimport/qmldir
@@ -0,0 +1,2 @@
+import QtQuick
+Test 2.0 Test.qml
diff --git a/tests/auto/qml/qqmltypeloader/data/qrcRootPath.qml b/tests/auto/qml/qqmltypeloader/data/qrcRootPath.qml
new file mode 100644
index 0000000000..bdbee4eb59
--- /dev/null
+++ b/tests/auto/qml/qqmltypeloader/data/qrcRootPath.qml
@@ -0,0 +1,4 @@
+import QtQml 2.12
+import "qrc:/"
+
+QtObject {}
diff --git a/tests/auto/qml/qqmltypeloader/tst_qqmltypeloader.cpp b/tests/auto/qml/qqmltypeloader/tst_qqmltypeloader.cpp
index 0c4abf19f4..2993b4b3c8 100644
--- a/tests/auto/qml/qqmltypeloader/tst_qqmltypeloader.cpp
+++ b/tests/auto/qml/qqmltypeloader/tst_qqmltypeloader.cpp
@@ -28,6 +28,7 @@
#include <QtTest/QtTest>
#include <QtQml/qqmlengine.h>
+#include <QtQml/qqmlfile.h>
#include <QtQml/qqmlnetworkaccessmanagerfactory.h>
#include <QtQuick/qquickview.h>
#include <QtQuick/qquickitem.h>
@@ -35,6 +36,7 @@
#include <QtCore/qprocess.h>
#endif
#include <QtQml/private/qqmlengine_p.h>
+#include <QtQml/private/qqmltypedata_p.h>
#include <QtQml/private/qqmltypeloader_p.h>
#include "../../shared/testhttpserver.h"
#include "../../shared/util.h"
@@ -56,6 +58,8 @@ private slots:
void qmlSingletonWithinModule();
void multiSingletonModule();
void implicitComponentModule();
+ void qrcRootPathUrl();
+ void implicitImport();
};
void tst_QQMLTypeLoader::testLoadComplete()
@@ -503,6 +507,23 @@ void tst_QQMLTypeLoader::implicitComponentModule()
checkCleanCacheLoad(QLatin1String("implicitComponentModule"));
}
+void tst_QQMLTypeLoader::qrcRootPathUrl()
+{
+ QQmlEngine engine;
+ QQmlComponent component(&engine, testFileUrl("qrcRootPath.qml"));
+ QCOMPARE(component.status(), QQmlComponent::Ready);
+}
+
+void tst_QQMLTypeLoader::implicitImport()
+{
+ QQmlEngine engine;
+ engine.addImportPath(testFile("imports"));
+ QQmlComponent component(&engine, testFileUrl("implicitimporttest.qml"));
+ QVERIFY2(component.isReady(), qPrintable(component.errorString()));
+ QScopedPointer<QObject> obj(component.create());
+ QVERIFY(!obj.isNull());
+}
+
QTEST_MAIN(tst_QQMLTypeLoader)
#include "tst_qqmltypeloader.moc"
diff --git a/tests/auto/quick/drawingmodes/tst_drawingmodes.cpp b/tests/auto/quick/drawingmodes/tst_drawingmodes.cpp
index f3825b350f..9bcc21c77d 100644
--- a/tests/auto/quick/drawingmodes/tst_drawingmodes.cpp
+++ b/tests/auto/quick/drawingmodes/tst_drawingmodes.cpp
@@ -385,9 +385,10 @@ bool tst_drawingmodes::isRunningOnRhi() const
decided = true;
QQuickView dummy;
dummy.show();
- QTest::qWaitForWindowExposed(&dummy);
- QSGRendererInterface::GraphicsApi api = dummy.rendererInterface()->graphicsApi();
- retval = QSGRendererInterface::isApiRhiBased(api);
+ if (QTest::qWaitForWindowExposed(&dummy)) {
+ QSGRendererInterface::GraphicsApi api = dummy.rendererInterface()->graphicsApi();
+ retval = QSGRendererInterface::isApiRhiBased(api);
+ }
dummy.hide();
}
return retval;
diff --git a/tests/auto/quick/pointerhandlers/multipointtoucharea_interop/tst_multipointtoucharea_interop.cpp b/tests/auto/quick/pointerhandlers/multipointtoucharea_interop/tst_multipointtoucharea_interop.cpp
index bf582b820b..58bc3d40b5 100644
--- a/tests/auto/quick/pointerhandlers/multipointtoucharea_interop/tst_multipointtoucharea_interop.cpp
+++ b/tests/auto/quick/pointerhandlers/multipointtoucharea_interop/tst_multipointtoucharea_interop.cpp
@@ -136,7 +136,6 @@ void tst_MptaInterop::touchDrag()
// TODO touchesThenPinch_data with press/release sequences somehow: vectors of touchpoint IDs? or a string representation?
void tst_MptaInterop::touchesThenPinch()
{
- const int dragThreshold = QGuiApplication::styleHints()->startDragDistance();
QScopedPointer<QQuickView> windowPtr;
createView(windowPtr, "pinchDragMPTA.qml");
QQuickView * window = windowPtr.data();
diff --git a/tests/auto/quick/qquickaccessible/tst_qquickaccessible.cpp b/tests/auto/quick/qquickaccessible/tst_qquickaccessible.cpp
index c5fdb6c1b9..d1f6d67aa1 100644
--- a/tests/auto/quick/qquickaccessible/tst_qquickaccessible.cpp
+++ b/tests/auto/quick/qquickaccessible/tst_qquickaccessible.cpp
@@ -338,7 +338,7 @@ void tst_QQuickAccessible::basicPropertiesTest()
QCOMPARE(text2->rect().y(), item->rect().y() + 40);
QCOMPARE(text2->role(), QAccessible::StaticText);
QCOMPARE(item->indexOfChild(text2), 1);
- QCOMPARE(text2->state().editable, 0);
+ QCOMPARE(text2->state().editable, 0u);
QCOMPARE(text2->state().readOnly, 1);
QCOMPARE(iface->indexOfChild(text2), -1);
diff --git a/tests/auto/quick/qquickfontloader_static/tst_qquickfontloader_static.cpp b/tests/auto/quick/qquickfontloader_static/tst_qquickfontloader_static.cpp
index c0f66bd709..7e848ef2fc 100644
--- a/tests/auto/quick/qquickfontloader_static/tst_qquickfontloader_static.cpp
+++ b/tests/auto/quick/qquickfontloader_static/tst_qquickfontloader_static.cpp
@@ -59,6 +59,8 @@ int main(int argc, char **argv)
component.setData(qmltemplate, current);
window.setContent(current, &component, component.create());
window.show();
- QTest::qWaitForWindowActive(&window);
+ if (!QTest::qWaitForWindowActive(&window))
+ return EXIT_FAILURE;
}
+ return 0;
}
diff --git a/tests/auto/quick/qquickimage/tst_qquickimage.cpp b/tests/auto/quick/qquickimage/tst_qquickimage.cpp
index c722f2fc2c..34c18aa64b 100644
--- a/tests/auto/quick/qquickimage/tst_qquickimage.cpp
+++ b/tests/auto/quick/qquickimage/tst_qquickimage.cpp
@@ -1107,7 +1107,7 @@ class MyInterceptor : public QQmlAbstractUrlInterceptor
{
public:
MyInterceptor(QUrl url) : QQmlAbstractUrlInterceptor(), m_url(url) {}
- QUrl intercept(const QUrl &url, QQmlAbstractUrlInterceptor::DataType type)
+ QUrl intercept(const QUrl &url, QQmlAbstractUrlInterceptor::DataType)
{
if (url.scheme() == "interceptthis")
return m_url;
diff --git a/tests/auto/quick/qquickimageprovider/tst_qquickimageprovider.cpp b/tests/auto/quick/qquickimageprovider/tst_qquickimageprovider.cpp
index c79e665d94..9dc9ad53ea 100644
--- a/tests/auto/quick/qquickimageprovider/tst_qquickimageprovider.cpp
+++ b/tests/auto/quick/qquickimageprovider/tst_qquickimageprovider.cpp
@@ -669,7 +669,7 @@ public:
emit finished();
}
- QQuickTextureFactory *textureFactory() const
+ QQuickTextureFactory *textureFactory() const override
{
QImage image(50, 50, QImage::Format_RGB32);
auto texture = QQuickTextureFactory::textureFactoryForImage(image);
@@ -696,7 +696,7 @@ public:
~WaitingAsyncProvider() {}
- QQuickImageResponse *requestImageResponse(const QString &id, const QSize &requestedSize)
+ QQuickImageResponse *requestImageResponse(const QString & /* id */, const QSize & /* requestedSize */)
{
auto response = new WaitingAsyncImageResponse(m_providerRemovedMutex, m_providerRemovedCond, m_providerRemoved, m_imageRequestedMutex, m_imageRequestedCondition, m_imageRequested);
pool.start(response);
diff --git a/tests/auto/quick/qquicktableview/tst_qquicktableview.cpp b/tests/auto/quick/qquicktableview/tst_qquicktableview.cpp
index fbe56abda5..19967efcd9 100644
--- a/tests/auto/quick/qquicktableview/tst_qquicktableview.cpp
+++ b/tests/auto/quick/qquicktableview/tst_qquicktableview.cpp
@@ -50,7 +50,6 @@
using namespace QQuickViewTestUtil;
using namespace QQuickVisualTestUtil;
-static const char* kTableViewPropName = "tableView";
static const char* kDelegateObjectName = "tableViewDelegate";
static const char *kDelegatesCreatedCountProp = "delegatesCreatedCount";
static const char *kModelDataBindingProp = "modelDataBinding";
diff --git a/tests/auto/quick/rendernode/tst_rendernode.cpp b/tests/auto/quick/rendernode/tst_rendernode.cpp
index b6028079f3..e75e9e30b9 100644
--- a/tests/auto/quick/rendernode/tst_rendernode.cpp
+++ b/tests/auto/quick/rendernode/tst_rendernode.cpp
@@ -49,8 +49,7 @@ public:
view.setResizeMode(QQuickView::SizeViewToRootObject);
view.setSource(testFileUrl(fileName));
view.setVisible(true);
- QTest::qWaitForWindowExposed(&view);
- return view.grabWindow();
+ return QTest::qWaitForWindowExposed(&view) ? view.grabWindow() : QImage();
}
//It is important for platforms that only are able to show fullscreen windows
@@ -225,6 +224,7 @@ void tst_rendernode::renderOrder()
QSKIP("Render nodes not yet supported with QRhi");
QImage fb = runTest("RenderOrder.qml");
+ QVERIFY(!fb.isNull());
const qreal scaleFactor = QGuiApplication::primaryScreen()->devicePixelRatio();
QCOMPARE(fb.width(), qRound(200 * scaleFactor));
@@ -257,6 +257,7 @@ void tst_rendernode::messUpState()
QSKIP("Render nodes not yet supported with QRhi");
QImage fb = runTest("MessUpState.qml");
+ QVERIFY(!fb.isNull());
int x1 = 0;
int x2 = fb.width() / 2;
int x3 = fb.width() - 1;
@@ -318,7 +319,7 @@ void tst_rendernode::matrix()
qmlRegisterType<StateRecordingRenderNodeItem>("RenderNode", 1, 0, "StateRecorder");
StateRecordingRenderNode::matrices.clear();
- runTest("matrix.qml");
+ QVERIFY(!runTest("matrix.qml").isNull());
QMatrix4x4 noRotateOffset;
noRotateOffset.translate(20, 20);
@@ -371,9 +372,10 @@ bool tst_rendernode::isRunningOnRhi() const
decided = true;
QQuickView dummy;
dummy.show();
- QTest::qWaitForWindowExposed(&dummy);
- QSGRendererInterface::GraphicsApi api = dummy.rendererInterface()->graphicsApi();
- retval = QSGRendererInterface::isApiRhiBased(api);
+ if (QTest::qWaitForWindowExposed(&dummy)) {
+ QSGRendererInterface::GraphicsApi api = dummy.rendererInterface()->graphicsApi();
+ retval = QSGRendererInterface::isApiRhiBased(api);
+ }
dummy.hide();
}
return retval;
diff --git a/tests/auto/quick/scenegraph/tst_scenegraph.cpp b/tests/auto/quick/scenegraph/tst_scenegraph.cpp
index c15f1e941e..3f605348c3 100644
--- a/tests/auto/quick/scenegraph/tst_scenegraph.cpp
+++ b/tests/auto/quick/scenegraph/tst_scenegraph.cpp
@@ -75,8 +75,8 @@ public:
delete node;
node = new QSGNode;
- const int w = width();
- const int h = height();
+ const int w = int(width());
+ const int h = int(height());
QQuickWindow *win = window();
for (int y = 0; y < h; ++y) {
for (int x = 0; x < w; ++x) {
@@ -569,8 +569,8 @@ bool tst_SceneGraph::isRunningOnOpenGLDirectly()
decided = true;
QQuickView dummy;
dummy.show();
- QTest::qWaitForWindowExposed(&dummy);
- retval = dummy.rendererInterface()->graphicsApi() == QSGRendererInterface::OpenGL;
+ if (QTest::qWaitForWindowExposed(&dummy))
+ retval = dummy.rendererInterface()->graphicsApi() == QSGRendererInterface::OpenGL;
dummy.hide();
}
return retval;
diff --git a/tools/qmlcachegen/qmlcachegen.cpp b/tools/qmlcachegen/qmlcachegen.cpp
index abad2435dc..0202bd4df0 100644
--- a/tools/qmlcachegen/qmlcachegen.cpp
+++ b/tools/qmlcachegen/qmlcachegen.cpp
@@ -45,6 +45,8 @@
#include <algorithm>
+using namespace QQmlJS;
+
int filterResourceFile(const QString &input, const QString &output);
bool generateLoader(const QStringList &compiledFiles, const QStringList &retainedFiles,
const QString &output, const QStringList &resourceFileMappings,
@@ -205,10 +207,7 @@ static bool compileQmlFile(const QString &inputFileName, SaveFunction saveFuncti
annotateListElements(&irDocument);
{
- QmlIR::JSCodeGen v4CodeGen(irDocument.code,
- &irDocument.jsGenerator, &irDocument.jsModule,
- &irDocument.jsParserEngine, irDocument.program,
- &irDocument.jsGenerator.stringTable, illegalNames);
+ QmlIR::JSCodeGen v4CodeGen(&irDocument, illegalNames);
for (QmlIR::Object *object: qAsConst(irDocument.objects)) {
if (object->functionsAndExpressions->count == 0)
continue;
@@ -309,9 +308,7 @@ static bool compileJSFile(const QString &inputFileName, const QString &inputFile
}
{
- QmlIR::JSCodeGen v4CodeGen(irDocument.code, &irDocument.jsGenerator,
- &irDocument.jsModule, &irDocument.jsParserEngine,
- irDocument.program, &irDocument.jsGenerator.stringTable, illegalNames);
+ QmlIR::JSCodeGen v4CodeGen(&irDocument, illegalNames);
v4CodeGen.generateFromProgram(inputFileName, inputFileUrl, sourceCode, program,
&irDocument.jsModule, QV4::Compiler::ContextType::ScriptImportedByQML);
if (v4CodeGen.hasError()) {
diff --git a/tools/qmlcachegen/qtquickcompiler.prf b/tools/qmlcachegen/qtquickcompiler.prf
index 2f98aadefe..24cbe7f2e5 100644
--- a/tools/qmlcachegen/qtquickcompiler.prf
+++ b/tools/qmlcachegen/qtquickcompiler.prf
@@ -1,5 +1,15 @@
if(qtc_run|lupdate_run): return()
+!contains(QT, qml) {
+ qt_modules = \
+ $$replace(QT, -private$, _private) \
+ $$replace(QT_PRIVATE, -private$, _private)
+ qt_modules = $$resolve_depends(qt_modules, "QT.", ".depends" ".run_depends")
+ !contains(qt_modules, qml): \
+ error("The qtquickcompiler feature cannot be used without the QML module.")
+ unset(qt_modules)
+}
+
qtPrepareTool(QML_CACHEGEN, qmlcachegen, _FILTER)
qtPrepareTool(QMAKE_RCC, rcc, _DEP)
diff --git a/tools/qmllint/.prev_CMakeLists.txt b/tools/qmllint/.prev_CMakeLists.txt
index 3eb5872903..9970e494b6 100644
--- a/tools/qmllint/.prev_CMakeLists.txt
+++ b/tools/qmllint/.prev_CMakeLists.txt
@@ -6,7 +6,13 @@
add_qt_tool(qmllint
SOURCES
+ componentversion.cpp componentversion.h
+ fakemetaobject.cpp fakemetaobject.h
+ findunqualified.cpp findunqualified.h
main.cpp
+ qcoloroutput.cpp qcoloroutput_p.h
+ qmljstypedescriptionreader.cpp qmljstypedescriptionreader.h
+ scopetree.cpp scopetree.h
LIBRARIES
Qt::QmlDevToolsPrivate
PUBLIC_LIBRARIES
diff --git a/tools/qmllint/CMakeLists.txt b/tools/qmllint/CMakeLists.txt
index 62cdbde95c..5b3128458f 100644
--- a/tools/qmllint/CMakeLists.txt
+++ b/tools/qmllint/CMakeLists.txt
@@ -7,7 +7,13 @@
add_qt_tool(qmllint
TOOLS_TARGET Qml # special case
SOURCES
+ componentversion.cpp componentversion.h
+ fakemetaobject.cpp fakemetaobject.h
+ findunqualified.cpp findunqualified.h
main.cpp
+ qcoloroutput.cpp qcoloroutput_p.h
+ qmljstypedescriptionreader.cpp qmljstypedescriptionreader.h
+ scopetree.cpp scopetree.h
LIBRARIES
Qt::QmlDevToolsPrivate
PUBLIC_LIBRARIES
diff --git a/tools/qmllint/componentversion.cpp b/tools/qmllint/componentversion.cpp
new file mode 100644
index 0000000000..3dc4ac37d0
--- /dev/null
+++ b/tools/qmllint/componentversion.cpp
@@ -0,0 +1,123 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the tools applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "componentversion.h"
+
+#include <QString>
+#include <QCryptographicHash>
+
+#include <limits>
+
+using namespace LanguageUtils;
+
+const int ComponentVersion::NoVersion = -1;
+const int ComponentVersion::MaxVersion = std::numeric_limits<int>::max();
+
+ComponentVersion::ComponentVersion()
+ : _major(NoVersion), _minor(NoVersion)
+{
+}
+
+ComponentVersion::ComponentVersion(int major, int minor)
+ : _major(major), _minor(minor)
+{
+}
+
+ComponentVersion::ComponentVersion(const QString &versionString)
+ : _major(NoVersion), _minor(NoVersion)
+{
+ int dotIdx = versionString.indexOf(QLatin1Char('.'));
+ if (dotIdx == -1)
+ return;
+ bool ok = false;
+ int maybeMajor = versionString.leftRef(dotIdx).toInt(&ok);
+ if (!ok)
+ return;
+ int maybeMinor = versionString.midRef(dotIdx + 1).toInt(&ok);
+ if (!ok)
+ return;
+ _major = maybeMajor;
+ _minor = maybeMinor;
+}
+
+ComponentVersion::~ComponentVersion()
+{
+}
+
+bool ComponentVersion::isValid() const
+{
+ return _major >= 0 && _minor >= 0;
+}
+
+QString ComponentVersion::toString() const
+{
+ return QString::fromLatin1("%1.%2").arg(QString::number(_major),
+ QString::number(_minor));
+}
+
+void ComponentVersion::addToHash(QCryptographicHash &hash) const
+{
+ hash.addData(reinterpret_cast<const char *>(&_major), sizeof(_major));
+ hash.addData(reinterpret_cast<const char *>(&_minor), sizeof(_minor));
+}
+
+namespace LanguageUtils {
+
+bool operator<(const ComponentVersion &lhs, const ComponentVersion &rhs)
+{
+ return lhs.majorVersion() < rhs.majorVersion()
+ || (lhs.majorVersion() == rhs.majorVersion() && lhs.minorVersion() < rhs.minorVersion());
+}
+
+bool operator<=(const ComponentVersion &lhs, const ComponentVersion &rhs)
+{
+ return lhs.majorVersion() < rhs.majorVersion()
+ || (lhs.majorVersion() == rhs.majorVersion() && lhs.minorVersion() <= rhs.minorVersion());
+}
+
+bool operator>(const ComponentVersion &lhs, const ComponentVersion &rhs)
+{
+ return rhs < lhs;
+}
+
+bool operator>=(const ComponentVersion &lhs, const ComponentVersion &rhs)
+{
+ return rhs <= lhs;
+}
+
+bool operator==(const ComponentVersion &lhs, const ComponentVersion &rhs)
+{
+ return lhs.majorVersion() == rhs.majorVersion() && lhs.minorVersion() == rhs.minorVersion();
+}
+
+bool operator!=(const ComponentVersion &lhs, const ComponentVersion &rhs)
+{
+ return !(lhs == rhs);
+}
+
+}
diff --git a/tools/qmllint/componentversion.h b/tools/qmllint/componentversion.h
new file mode 100644
index 0000000000..9d079f1d30
--- /dev/null
+++ b/tools/qmllint/componentversion.h
@@ -0,0 +1,73 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the tools applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef COMPONENTVERSION_H
+#define COMPONENTVERSION_H
+
+#include <qglobal.h>
+
+QT_BEGIN_NAMESPACE
+class QCryptographicHash;
+QT_END_NAMESPACE
+
+namespace LanguageUtils {
+
+class ComponentVersion
+{
+ int _major;
+ int _minor;
+
+public:
+ static const int NoVersion;
+ static const int MaxVersion;
+
+ ComponentVersion();
+ ComponentVersion(int major, int minor);
+ explicit ComponentVersion(const QString &versionString);
+ ~ComponentVersion();
+
+ int majorVersion() const
+ { return _major; }
+ int minorVersion() const
+ { return _minor; }
+
+ bool isValid() const;
+ QString toString() const;
+ void addToHash(QCryptographicHash &hash) const;
+};
+
+bool operator<(const ComponentVersion &lhs, const ComponentVersion &rhs);
+bool operator<=(const ComponentVersion &lhs, const ComponentVersion &rhs);
+bool operator>(const ComponentVersion &lhs, const ComponentVersion &rhs);
+bool operator>=(const ComponentVersion &lhs, const ComponentVersion &rhs);
+bool operator==(const ComponentVersion &lhs, const ComponentVersion &rhs);
+bool operator!=(const ComponentVersion &lhs, const ComponentVersion &rhs);
+
+} // namespace LanguageUtils
+
+#endif // COMPONENTVERSION_H
diff --git a/tools/qmllint/fakemetaobject.cpp b/tools/qmllint/fakemetaobject.cpp
new file mode 100644
index 0000000000..514bb2fe42
--- /dev/null
+++ b/tools/qmllint/fakemetaobject.cpp
@@ -0,0 +1,600 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the tools applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include "fakemetaobject.h"
+#include <QCryptographicHash>
+
+using namespace LanguageUtils;
+
+FakeMetaEnum::FakeMetaEnum()
+{}
+
+FakeMetaEnum::FakeMetaEnum(const QString &name)
+ : m_name(name)
+{}
+
+bool FakeMetaEnum::isValid() const
+{ return !m_name.isEmpty(); }
+
+QString FakeMetaEnum::name() const
+{ return m_name; }
+
+void FakeMetaEnum::setName(const QString &name)
+{ m_name = name; }
+
+void FakeMetaEnum::addKey(const QString &key, int value)
+{ m_keys.append(key); m_values.append(value); }
+
+QString FakeMetaEnum::key(int index) const
+{ return m_keys.at(index); }
+
+int FakeMetaEnum::keyCount() const
+{ return m_keys.size(); }
+
+QStringList FakeMetaEnum::keys() const
+{ return m_keys; }
+
+bool FakeMetaEnum::hasKey(const QString &key) const
+{ return m_keys.contains(key); }
+
+void FakeMetaEnum::addToHash(QCryptographicHash &hash) const
+{
+ int len = m_name.size();
+ hash.addData(reinterpret_cast<const char *>(&len), sizeof(len));
+ hash.addData(reinterpret_cast<const char *>(m_name.constData()), len * sizeof(QChar));
+ len = m_keys.size();
+ hash.addData(reinterpret_cast<const char *>(&len), sizeof(len));
+ foreach (const QString &key, m_keys) {
+ len = key.size();
+ hash.addData(reinterpret_cast<const char *>(&len), sizeof(len));
+ hash.addData(reinterpret_cast<const char *>(key.constData()), len * sizeof(QChar));
+ }
+ len = m_values.size();
+ hash.addData(reinterpret_cast<const char *>(&len), sizeof(len));
+ foreach (int value, m_values)
+ hash.addData(reinterpret_cast<const char *>(&value), sizeof(value));
+}
+
+QString FakeMetaEnum::describe(int baseIndent) const
+{
+ QString newLine = QString::fromLatin1("\n") + QString::fromLatin1(" ").repeated(baseIndent);
+ QString res = QLatin1String("Enum ");
+ res += name();
+ res += QLatin1String(":{");
+ for (int i = 0; i < keyCount(); ++i) {
+ res += newLine;
+ res += QLatin1String(" ");
+ res += key(i);
+ res += QLatin1String(": ");
+ res += QString::number(m_values.value(i, -1));
+ }
+ res += newLine;
+ res += QLatin1Char('}');
+ return res;
+}
+
+QString FakeMetaEnum::toString() const
+{
+ return describe();
+}
+
+FakeMetaMethod::FakeMetaMethod(const QString &name, const QString &returnType)
+ : m_name(name)
+ , m_returnType(returnType)
+ , m_methodTy(FakeMetaMethod::Method)
+ , m_methodAccess(FakeMetaMethod::Public)
+ , m_revision(0)
+{}
+
+FakeMetaMethod::FakeMetaMethod()
+ : m_methodTy(FakeMetaMethod::Method)
+ , m_methodAccess(FakeMetaMethod::Public)
+ , m_revision(0)
+{}
+
+QString FakeMetaMethod::methodName() const
+{ return m_name; }
+
+void FakeMetaMethod::setMethodName(const QString &name)
+{ m_name = name; }
+
+void FakeMetaMethod::setReturnType(const QString &type)
+{ m_returnType = type; }
+
+QStringList FakeMetaMethod::parameterNames() const
+{ return m_paramNames; }
+
+QStringList FakeMetaMethod::parameterTypes() const
+{ return m_paramTypes; }
+
+void FakeMetaMethod::addParameter(const QString &name, const QString &type)
+{ m_paramNames.append(name); m_paramTypes.append(type); }
+
+int FakeMetaMethod::methodType() const
+{ return m_methodTy; }
+
+void FakeMetaMethod::setMethodType(int methodType)
+{ m_methodTy = methodType; }
+
+int FakeMetaMethod::access() const
+{ return m_methodAccess; }
+
+int FakeMetaMethod::revision() const
+{ return m_revision; }
+
+void FakeMetaMethod::setRevision(int r)
+{ m_revision = r; }
+
+void FakeMetaMethod::addToHash(QCryptographicHash &hash) const
+{
+ int len = m_name.size();
+ hash.addData(reinterpret_cast<const char *>(&len), sizeof(len));
+ hash.addData(reinterpret_cast<const char *>(m_name.constData()), len * sizeof(QChar));
+ hash.addData(reinterpret_cast<const char *>(&m_methodAccess), sizeof(m_methodAccess));
+ hash.addData(reinterpret_cast<const char *>(&m_methodTy), sizeof(m_methodTy));
+ hash.addData(reinterpret_cast<const char *>(&m_revision), sizeof(m_revision));
+ len = m_paramNames.size();
+ hash.addData(reinterpret_cast<const char *>(&len), sizeof(len));
+ foreach (const QString &pName, m_paramNames) {
+ len = pName.size();
+ hash.addData(reinterpret_cast<const char *>(&len), sizeof(len));
+ hash.addData(reinterpret_cast<const char *>(pName.constData()), len * sizeof(QChar));
+ }
+ len = m_paramTypes.size();
+ hash.addData(reinterpret_cast<const char *>(&len), sizeof(len));
+ foreach (const QString &pType, m_paramTypes) {
+ len = pType.size();
+ hash.addData(reinterpret_cast<const char *>(&len), sizeof(len));
+ hash.addData(reinterpret_cast<const char *>(pType.constData()), len * sizeof(QChar));
+ }
+ len = m_returnType.size();
+ hash.addData(reinterpret_cast<const char *>(&len), sizeof(len));
+ hash.addData(reinterpret_cast<const char *>(m_returnType.constData()), len * sizeof(QChar));
+}
+
+QString FakeMetaMethod::describe(int baseIndent) const
+{
+ QString newLine = QString::fromLatin1("\n") + QString::fromLatin1(" ").repeated(baseIndent);
+ QString res = QLatin1String("Method {");
+ res += newLine;
+ res += QLatin1String(" methodName:");
+ res += methodName();
+ res += newLine;
+ res += QLatin1String(" methodType:");
+ res += methodType();
+ res += newLine;
+ res += QLatin1String(" parameterNames:[");
+ foreach (const QString &pName, parameterNames()) {
+ res += newLine;
+ res += QLatin1String(" ");
+ res += pName;
+ }
+ res += QLatin1Char(']');
+ res += newLine;
+ res += QLatin1String(" parameterTypes:[");
+ foreach (const QString &pType, parameterTypes()) {
+ res += newLine;
+ res += QLatin1String(" ");
+ res += pType;
+ }
+ res += QLatin1Char(']');
+ res += newLine;
+ res += QLatin1Char('}');
+ return res;
+}
+
+QString FakeMetaMethod::toString() const
+{
+ return describe();
+}
+
+
+FakeMetaProperty::FakeMetaProperty(const QString &name, const QString &type, bool isList,
+ bool isWritable, bool isPointer, int revision)
+ : m_propertyName(name)
+ , m_type(type)
+ , m_isList(isList)
+ , m_isWritable(isWritable)
+ , m_isPointer(isPointer)
+ , m_revision(revision)
+{}
+
+QString FakeMetaProperty::name() const
+{ return m_propertyName; }
+
+QString FakeMetaProperty::typeName() const
+{ return m_type; }
+
+bool FakeMetaProperty::isList() const
+{ return m_isList; }
+
+bool FakeMetaProperty::isWritable() const
+{ return m_isWritable; }
+
+bool FakeMetaProperty::isPointer() const
+{ return m_isPointer; }
+
+int FakeMetaProperty::revision() const
+{ return m_revision; }
+
+void FakeMetaProperty::addToHash(QCryptographicHash &hash) const
+{
+ int len = m_propertyName.size();
+ hash.addData(reinterpret_cast<const char *>(&len), sizeof(len));
+ hash.addData(reinterpret_cast<const char *>(m_propertyName.constData()), len * sizeof(QChar));
+ hash.addData(reinterpret_cast<const char *>(&m_revision), sizeof(m_revision));
+ int flags = (m_isList ? (1 << 0) : 0)
+ + (m_isPointer ? (1 << 1) : 0)
+ + (m_isWritable ? (1 << 2) : 0);
+ hash.addData(reinterpret_cast<const char *>(&flags), sizeof(flags));
+ len = m_type.size();
+ hash.addData(reinterpret_cast<const char *>(&len), sizeof(len));
+ hash.addData(reinterpret_cast<const char *>(m_type.constData()), len * sizeof(QChar));
+}
+
+QString FakeMetaProperty::describe(int baseIndent) const
+{
+ auto boolStr = [] (bool v) { return v ? QLatin1String("true") : QLatin1String("false"); };
+ QString newLine = QString::fromLatin1("\n") + QString::fromLatin1(" ").repeated(baseIndent);
+ QString res = QLatin1String("Property {");
+ res += newLine;
+ res += QLatin1String(" name:");
+ res += name();
+ res += newLine;
+ res += QLatin1String(" typeName:");
+ res += typeName();
+ res += newLine;
+ res += QLatin1String(" typeName:");
+ res += QString::number(revision());
+ res += newLine;
+ res += QLatin1String(" isList:");
+ res += boolStr(isList());
+ res += newLine;
+ res += QLatin1String(" isPointer:");
+ res += boolStr(isPointer());
+ res += newLine;
+ res += QLatin1String(" isWritable:");
+ res += boolStr(isWritable());
+ res += newLine;
+ res += QLatin1Char('}');
+ return res;
+}
+
+QString FakeMetaProperty::toString() const
+{
+ return describe();
+}
+
+
+FakeMetaObject::FakeMetaObject() : m_isSingleton(false), m_isCreatable(true), m_isComposite(false)
+{
+}
+
+QString FakeMetaObject::className() const
+{ return m_className; }
+void FakeMetaObject::setClassName(const QString &name)
+{ m_className = name; }
+
+void FakeMetaObject::addExport(const QString &name, const QString &package, ComponentVersion version)
+{
+ Export exp;
+ exp.type = name;
+ exp.package = package;
+ exp.version = version;
+ m_exports.append(exp);
+}
+
+void FakeMetaObject::setExportMetaObjectRevision(int exportIndex, int metaObjectRevision)
+{
+ m_exports[exportIndex].metaObjectRevision = metaObjectRevision;
+}
+
+QList<FakeMetaObject::Export> FakeMetaObject::exports() const
+{ return m_exports; }
+FakeMetaObject::Export FakeMetaObject::exportInPackage(const QString &package) const
+{
+ foreach (const Export &exp, m_exports) {
+ if (exp.package == package)
+ return exp;
+ }
+ return Export();
+}
+
+void FakeMetaObject::setSuperclassName(const QString &superclass)
+{ m_superName = superclass; }
+QString FakeMetaObject::superclassName() const
+{ return m_superName; }
+
+void FakeMetaObject::addEnum(const FakeMetaEnum &fakeEnum)
+{ m_enumNameToIndex.insert(fakeEnum.name(), m_enums.size()); m_enums.append(fakeEnum); }
+int FakeMetaObject::enumeratorCount() const
+{ return m_enums.size(); }
+int FakeMetaObject::enumeratorOffset() const
+{ return 0; }
+FakeMetaEnum FakeMetaObject::enumerator(int index) const
+{ return m_enums.at(index); }
+int FakeMetaObject::enumeratorIndex(const QString &name) const
+{ return m_enumNameToIndex.value(name, -1); }
+
+void FakeMetaObject::addProperty(const FakeMetaProperty &property)
+{ m_propNameToIdx.insert(property.name(), m_props.size()); m_props.append(property); }
+int FakeMetaObject::propertyCount() const
+{ return m_props.size(); }
+int FakeMetaObject::propertyOffset() const
+{ return 0; }
+FakeMetaProperty FakeMetaObject::property(int index) const
+{ return m_props.at(index); }
+int FakeMetaObject::propertyIndex(const QString &name) const
+{ return m_propNameToIdx.value(name, -1); }
+
+void FakeMetaObject::addMethod(const FakeMetaMethod &method)
+{ m_methods.append(method); }
+int FakeMetaObject::methodCount() const
+{ return m_methods.size(); }
+int FakeMetaObject::methodOffset() const
+{ return 0; }
+FakeMetaMethod FakeMetaObject::method(int index) const
+{ return m_methods.at(index); }
+int FakeMetaObject::methodIndex(const QString &name) const //If performances becomes an issue, just use a nameToIdx hash
+{
+ for (int i=0; i<m_methods.count(); i++)
+ if (m_methods[i].methodName() == name)
+ return i;
+ return -1;
+}
+
+QString FakeMetaObject::defaultPropertyName() const
+{ return m_defaultPropertyName; }
+void FakeMetaObject::setDefaultPropertyName(const QString &defaultPropertyName)
+{ m_defaultPropertyName = defaultPropertyName; }
+
+QString FakeMetaObject::attachedTypeName() const
+{ return m_attachedTypeName; }
+void FakeMetaObject::setAttachedTypeName(const QString &name)
+{ m_attachedTypeName = name; }
+
+QByteArray FakeMetaObject::calculateFingerprint() const
+{
+ QCryptographicHash hash(QCryptographicHash::Sha1);
+ int len = m_className.size();
+ hash.addData(reinterpret_cast<const char *>(&len), sizeof(len));
+ hash.addData(reinterpret_cast<const char *>(m_className.constData()), len * sizeof(QChar));
+ len = m_attachedTypeName.size();
+ hash.addData(reinterpret_cast<const char *>(&len), sizeof(len));
+ hash.addData(reinterpret_cast<const char *>(m_attachedTypeName.constData()), len * sizeof(QChar));
+ len = m_defaultPropertyName.size();
+ hash.addData(reinterpret_cast<const char *>(&len), sizeof(len));
+ hash.addData(reinterpret_cast<const char *>(m_defaultPropertyName.constData()), len * sizeof(QChar));
+ len = m_enumNameToIndex.size();
+ hash.addData(reinterpret_cast<const char *>(&len), sizeof(len));
+ {
+ QStringList keys(m_enumNameToIndex.keys());
+ keys.sort();
+ foreach (const QString &key, keys) {
+ len = key.size();
+ hash.addData(reinterpret_cast<const char *>(&len), sizeof(len));
+ hash.addData(reinterpret_cast<const char *>(key.constData()), len * sizeof(QChar));
+ int value = m_enumNameToIndex.value(key);
+ hash.addData(reinterpret_cast<const char *>(&value), sizeof(value)); // avoid? this adds order dependency to fingerprint...
+ m_enums.at(value).addToHash(hash);
+ }
+ }
+ len = m_exports.size();
+ hash.addData(reinterpret_cast<const char *>(&len), sizeof(len));
+ foreach (const Export &e, m_exports)
+ e.addToHash(hash); // normalize order?
+ len = m_exports.size();
+ hash.addData(reinterpret_cast<const char *>(&len), sizeof(len));
+ foreach (const FakeMetaMethod &m, m_methods)
+ m.addToHash(hash); // normalize order?
+ {
+ QStringList keys(m_propNameToIdx.keys());
+ keys.sort();
+ foreach (const QString &key, keys) {
+ len = key.size();
+ hash.addData(reinterpret_cast<const char *>(&len), sizeof(len));
+ hash.addData(reinterpret_cast<const char *>(key.constData()), len * sizeof(QChar));
+ int value = m_propNameToIdx.value(key);
+ hash.addData(reinterpret_cast<const char *>(&value), sizeof(value)); // avoid? this adds order dependency to fingerprint...
+ m_props.at(value).addToHash(hash);
+ }
+ }
+ len = m_superName.size();
+ hash.addData(reinterpret_cast<const char *>(&len), sizeof(len));
+ hash.addData(reinterpret_cast<const char *>(m_superName.constData()), len * sizeof(QChar));
+
+ QByteArray res = hash.result();
+ res.append('F');
+ return res;
+}
+
+void FakeMetaObject::updateFingerprint()
+{
+ m_fingerprint = calculateFingerprint();
+}
+
+QByteArray FakeMetaObject::fingerprint() const
+{
+ return m_fingerprint;
+}
+
+bool FakeMetaObject::isSingleton() const
+{
+ return m_isSingleton;
+}
+
+bool FakeMetaObject::isCreatable() const
+{
+ return m_isCreatable;
+}
+
+bool FakeMetaObject::isComposite() const
+{
+ return m_isComposite;
+}
+
+void FakeMetaObject::setIsSingleton(bool value)
+{
+ m_isSingleton = value;
+}
+
+void FakeMetaObject::setIsCreatable(bool value)
+{
+ m_isCreatable = value;
+}
+
+void FakeMetaObject::setIsComposite(bool value)
+{
+ m_isSingleton = value;
+}
+
+QString FakeMetaObject::toString() const
+{
+ return describe();
+}
+
+QString FakeMetaObject::describe(bool printDetails, int baseIndent) const
+{
+ QString res = QString::fromLatin1("FakeMetaObject@%1")
+ .arg((quintptr)(void *)this, 0, 16);
+ if (!printDetails)
+ return res;
+ auto boolStr = [] (bool v) { return v ? QLatin1String("true") : QLatin1String("false"); };
+ QString newLine = QString::fromLatin1("\n") + QString::fromLatin1(" ").repeated(baseIndent);
+ res += QLatin1Char('{');
+ res += newLine;
+ res += QLatin1String("className:");
+ res += className();
+ res += newLine;
+ res += QLatin1String("superClassName:");
+ res += superclassName();
+ res += newLine;
+ res += QLatin1String("isSingleton:");
+ res += boolStr(isSingleton());
+ res += newLine;
+ res += QLatin1String("isCreatable:");
+ res += boolStr(isCreatable());
+ res += newLine;
+ res += QLatin1String("isComposite:");
+ res += boolStr(isComposite());
+ res += newLine;
+ res += QLatin1String("defaultPropertyName:");
+ res += defaultPropertyName();
+ res += newLine;
+ res += QLatin1String("attachedTypeName:");
+ res += attachedTypeName();
+ res += newLine;
+ res += QLatin1String("fingerprint:");
+ res += QString::fromUtf8(fingerprint());
+
+ res += newLine;
+ res += QLatin1String("exports:[");
+ foreach (const Export &e, exports()) {
+ res += newLine;
+ res += QLatin1String(" ");
+ res += e.describe(baseIndent + 2);
+ }
+ res += QLatin1Char(']');
+
+ res += newLine;
+ res += QLatin1String("enums:[");
+ for (int iEnum = 0; iEnum < enumeratorCount() ; ++ iEnum) {
+ FakeMetaEnum e = enumerator(enumeratorOffset() + iEnum);
+ res += newLine;
+ res += QLatin1String(" ");
+ res += e.describe(baseIndent + 2);
+ }
+ res += QLatin1Char(']');
+
+ res += newLine;
+ res += QLatin1String("properties:[");
+ for (int iProp = 0; iProp < propertyCount() ; ++ iProp) {
+ FakeMetaProperty prop = property(propertyOffset() + iProp);
+ res += newLine;
+ res += QLatin1String(" ");
+ res += prop.describe(baseIndent + 2);
+ }
+ res += QLatin1Char(']');
+ res += QLatin1String("methods:[");
+ for (int iMethod = 0; iMethod < methodOffset() ; ++ iMethod) {
+ FakeMetaMethod m = method(methodOffset() + iMethod);
+ res += newLine;
+ res += QLatin1String(" ");
+ m.describe(baseIndent + 2);
+ }
+ res += QLatin1Char(']');
+ res += newLine;
+ res += QLatin1Char('}');
+ return res;
+}
+
+FakeMetaObject::Export::Export()
+ : metaObjectRevision(0)
+{}
+bool FakeMetaObject::Export::isValid() const
+{ return version.isValid() || !package.isEmpty() || !type.isEmpty(); }
+
+void FakeMetaObject::Export::addToHash(QCryptographicHash &hash) const
+{
+ int len = package.size();
+ hash.addData(reinterpret_cast<const char *>(&len), sizeof(len));
+ hash.addData(reinterpret_cast<const char *>(package.constData()), len * sizeof(QChar));
+ len = type.size();
+ hash.addData(reinterpret_cast<const char *>(&len), sizeof(len));
+ hash.addData(reinterpret_cast<const char *>(type.constData()), len * sizeof(QChar));
+ version.addToHash(hash);
+ hash.addData(reinterpret_cast<const char *>(&metaObjectRevision), sizeof(metaObjectRevision));
+}
+
+QString FakeMetaObject::Export::describe(int baseIndent) const
+{
+ QString newLine = QString::fromLatin1("\n") + QString::fromLatin1(" ").repeated(baseIndent);
+ QString res = QLatin1String("Export {");
+ res += newLine;
+ res += QLatin1String(" package:");
+ res += package;
+ res += newLine;
+ res += QLatin1String(" type:");
+ res += type;
+ res += newLine;
+ res += QLatin1String(" version:");
+ res += version.toString();
+ res += newLine;
+ res += QLatin1String(" metaObjectRevision:");
+ res += QString::number(metaObjectRevision);
+ res += newLine;
+ res += QLatin1String(" isValid:");
+ res += QString::number(isValid());
+ res += newLine;
+ res += QLatin1Char('}');
+ return res;
+}
+
+QString FakeMetaObject::Export::toString() const
+{
+ return describe();
+}
diff --git a/tools/qmllint/fakemetaobject.h b/tools/qmllint/fakemetaobject.h
new file mode 100644
index 0000000000..4e0ea1f8b3
--- /dev/null
+++ b/tools/qmllint/fakemetaobject.h
@@ -0,0 +1,236 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the tools applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef FAKEMETAOBJECT_H
+#define FAKEMETAOBJECT_H
+
+#include <QString>
+#include <QStringList>
+#include <QList>
+#include <QHash>
+#include <QSharedPointer>
+
+#include "componentversion.h"
+
+QT_BEGIN_NAMESPACE
+class QCryptographicHash;
+QT_END_NAMESPACE
+
+namespace LanguageUtils {
+
+class FakeMetaEnum {
+ QString m_name;
+ QStringList m_keys;
+ QList<int> m_values;
+
+public:
+ FakeMetaEnum();
+ explicit FakeMetaEnum(const QString &name);
+
+ bool isValid() const;
+
+ QString name() const;
+ void setName(const QString &name);
+
+ void addKey(const QString &key, int value);
+ QString key(int index) const;
+ int keyCount() const;
+ QStringList keys() const;
+ bool hasKey(const QString &key) const;
+ void addToHash(QCryptographicHash &hash) const;
+
+ QString describe(int baseIndent = 0) const;
+ QString toString() const;
+};
+
+class FakeMetaMethod {
+public:
+ enum {
+ Signal,
+ Slot,
+ Method
+ };
+
+ enum {
+ Private,
+ Protected,
+ Public
+ };
+
+public:
+ FakeMetaMethod();
+ explicit FakeMetaMethod(const QString &name, const QString &returnType = QString());
+
+ QString methodName() const;
+ void setMethodName(const QString &name);
+
+ void setReturnType(const QString &type);
+
+ QStringList parameterNames() const;
+ QStringList parameterTypes() const;
+ void addParameter(const QString &name, const QString &type);
+
+ int methodType() const;
+ void setMethodType(int methodType);
+
+ int access() const;
+
+ int revision() const;
+ void setRevision(int r);
+ void addToHash(QCryptographicHash &hash) const;
+
+ QString describe(int baseIndent = 0) const;
+ QString toString() const;
+private:
+ QString m_name;
+ QString m_returnType;
+ QStringList m_paramNames;
+ QStringList m_paramTypes;
+ int m_methodTy;
+ int m_methodAccess;
+ int m_revision;
+};
+
+class FakeMetaProperty {
+ QString m_propertyName;
+ QString m_type;
+ bool m_isList;
+ bool m_isWritable;
+ bool m_isPointer;
+ int m_revision;
+
+public:
+ FakeMetaProperty(const QString &name, const QString &type, bool isList, bool isWritable, bool isPointer, int revision);
+
+ QString name() const;
+ QString typeName() const;
+
+ bool isList() const;
+ bool isWritable() const;
+ bool isPointer() const;
+ int revision() const;
+ void addToHash(QCryptographicHash &hash) const;
+
+ QString describe(int baseIndent = 0) const;
+ QString toString() const;
+};
+
+class FakeMetaObject {
+ Q_DISABLE_COPY(FakeMetaObject);
+
+public:
+ typedef QSharedPointer<FakeMetaObject> Ptr;
+ typedef QSharedPointer<const FakeMetaObject> ConstPtr;
+
+ class Export {
+ public:
+ Export();
+
+ QString package;
+ QString type;
+ ComponentVersion version;
+ int metaObjectRevision;
+
+ bool isValid() const;
+ void addToHash(QCryptographicHash &hash) const;
+
+ QString describe(int baseIndent = 0) const;
+ QString toString() const;
+ };
+
+private:
+ QString m_className;
+ QList<Export> m_exports;
+ QString m_superName;
+ QList<FakeMetaEnum> m_enums;
+ QHash<QString, int> m_enumNameToIndex;
+ QList<FakeMetaProperty> m_props;
+ QHash<QString, int> m_propNameToIdx;
+ QList<FakeMetaMethod> m_methods;
+ QString m_defaultPropertyName;
+ QString m_attachedTypeName;
+ QByteArray m_fingerprint;
+ bool m_isSingleton;
+ bool m_isCreatable;
+ bool m_isComposite;
+
+public:
+ FakeMetaObject();
+
+ QString className() const;
+ void setClassName(const QString &name);
+
+ void addExport(const QString &name, const QString &package, ComponentVersion version);
+ void setExportMetaObjectRevision(int exportIndex, int metaObjectRevision);
+ QList<Export> exports() const;
+ Export exportInPackage(const QString &package) const;
+
+ void setSuperclassName(const QString &superclass);
+ QString superclassName() const;
+
+ void addEnum(const FakeMetaEnum &fakeEnum);
+ int enumeratorCount() const;
+ int enumeratorOffset() const;
+ FakeMetaEnum enumerator(int index) const;
+ int enumeratorIndex(const QString &name) const;
+
+ void addProperty(const FakeMetaProperty &property);
+ int propertyCount() const;
+ int propertyOffset() const;
+ FakeMetaProperty property(int index) const;
+ int propertyIndex(const QString &name) const;
+
+ void addMethod(const FakeMetaMethod &method);
+ int methodCount() const;
+ int methodOffset() const;
+ FakeMetaMethod method(int index) const;
+ int methodIndex(const QString &name) const; // Note: Returns any method with that name in case of overloads
+
+ QString defaultPropertyName() const;
+ void setDefaultPropertyName(const QString &defaultPropertyName);
+
+ QString attachedTypeName() const;
+ void setAttachedTypeName(const QString &name);
+ QByteArray calculateFingerprint() const;
+ void updateFingerprint();
+ QByteArray fingerprint() const;
+
+ bool isSingleton() const;
+ bool isCreatable() const;
+ bool isComposite() const;
+ void setIsSingleton(bool value);
+ void setIsCreatable(bool value);
+ void setIsComposite(bool value);
+
+ QString describe(bool printDetails = true, int baseIndent = 0) const;
+ QString toString() const;
+};
+
+} // namespace LanguageUtils
+
+#endif // FAKEMETAOBJECT_H
diff --git a/tools/qmllint/findunqualified.cpp b/tools/qmllint/findunqualified.cpp
new file mode 100644
index 0000000000..3abdfcfa53
--- /dev/null
+++ b/tools/qmllint/findunqualified.cpp
@@ -0,0 +1,772 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the tools applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "findunqualified.h"
+#include "scopetree.h"
+
+#include "qmljstypedescriptionreader.h"
+
+#include <QFile>
+#include <QDirIterator>
+#include <QScopedValueRollback>
+
+#include <private/qqmljsast_p.h>
+#include <private/qqmljslexer_p.h>
+#include <private/qqmljsparser_p.h>
+
+QDebug &operator<<(QDebug dbg, const QQmlJS::AST::SourceLocation &loc);
+
+static QQmlJS::TypeDescriptionReader createReaderForFile(QString const &filename)
+{
+ QFile f(filename);
+ f.open(QFile::ReadOnly);
+ QQmlJS::TypeDescriptionReader reader { filename, f.readAll() };
+ return reader;
+}
+
+void FindUnqualifiedIDVisitor::enterEnvironment(ScopeType type, QString name)
+{
+ m_currentScope = m_currentScope->createNewChildScope(type, name);
+}
+
+void FindUnqualifiedIDVisitor::leaveEnvironment()
+{
+ m_currentScope = m_currentScope->parentScope();
+}
+
+enum ImportVersion { FullyVersioned, PartiallyVersioned, Unversioned };
+
+QStringList completeQmltypesPaths(const QString &uri, const QStringList &basePaths, int vmaj, int vmin)
+{
+ static const QLatin1Char Slash('/');
+ static const QLatin1Char Backslash('\\');
+ static const QLatin1String SlashPluginsDotQmltypes("/plugins.qmltypes");
+
+ const QVector<QStringRef> parts = uri.splitRef(QLatin1Char('.'), QString::SkipEmptyParts);
+
+ QStringList qmlDirPathsPaths;
+ // fully & partially versioned parts + 1 unversioned for each base path
+ qmlDirPathsPaths.reserve(basePaths.count() * (2 * parts.count() + 1));
+
+ auto versionString = [](int vmaj, int vmin, ImportVersion version)
+ {
+ if (version == FullyVersioned) {
+ // extension with fully encoded version number (eg. MyModule.3.2)
+ return QString::asprintf(".%d.%d", vmaj, vmin);
+ } else if (version == PartiallyVersioned) {
+ // extension with encoded version major (eg. MyModule.3)
+ return QString::asprintf(".%d", vmaj);
+ } // else extension without version number (eg. MyModule)
+ return QString();
+ };
+ auto joinStringRefs = [](const QVector<QStringRef> &refs, const QChar &sep)
+ {
+ QString str;
+ for (auto it = refs.cbegin(); it != refs.cend(); ++it) {
+ if (it != refs.cbegin())
+ str += sep;
+ str += *it;
+ }
+ return str;
+ };
+
+ for (int version = FullyVersioned; version <= Unversioned; ++version) {
+ const QString ver = versionString(vmaj, vmin, static_cast<ImportVersion>(version));
+
+ for (const QString &path : basePaths) {
+ QString dir = path;
+ if (!dir.endsWith(Slash) && !dir.endsWith(Backslash))
+ dir += Slash;
+
+ // append to the end
+ qmlDirPathsPaths += dir + joinStringRefs(parts, Slash) + ver + SlashPluginsDotQmltypes;
+
+ if (version != Unversioned) {
+ // insert in the middle
+ for (int index = parts.count() - 2; index >= 0; --index) {
+ qmlDirPathsPaths += dir + joinStringRefs(parts.mid(0, index + 1), Slash)
+ + ver + Slash
+ + joinStringRefs(parts.mid(index + 1), Slash) + SlashPluginsDotQmltypes;
+ }
+ }
+ }
+ }
+
+ return qmlDirPathsPaths;
+}
+
+void FindUnqualifiedIDVisitor::importHelper(QString id, QString prefix, int major, int minor)
+{
+ QPair<QString, QString> importId { id, prefix };
+ if (m_alreadySeenImports.contains(importId)) {
+ return;
+ } else {
+ m_alreadySeenImports.insert(importId);
+ }
+ id = id.replace(QLatin1String("/"), QLatin1String("."));
+ auto qmltypesPaths = completeQmltypesPaths(id, m_qmltypeDirs, major, minor);
+
+ QHash<QString, LanguageUtils::FakeMetaObject::ConstPtr> objects;
+ QList<QQmlJS::ModuleApiInfo> moduleApis;
+ QStringList dependencies;
+ for (auto const &qmltypesPath : qmltypesPaths) {
+ if (QFile::exists(qmltypesPath)) {
+ auto reader = createReaderForFile(qmltypesPath);
+ auto succ = reader(&objects, &moduleApis, &dependencies);
+ if (!succ) {
+ qDebug() << reader.errorMessage();
+ }
+ break;
+ }
+ }
+ for (auto const &dependency : qAsConst(dependencies)) {
+ auto const split = dependency.split(" ");
+ auto const id = split.at(0);
+ auto const major = split.at(1).split('.').at(0).toInt();
+ auto const minor = split.at(1).split('.').at(1).toInt();
+ importHelper(id, QString(), major, minor);
+ }
+ // add objects
+ for (auto ob_it = objects.begin(); ob_it != objects.end(); ++ob_it) {
+ auto val = ob_it.value();
+ m_exportedName2MetaObject[prefix + val->className()] = val;
+ for (auto export_ : val->exports()) {
+ m_exportedName2MetaObject[prefix + export_.type] = val;
+ }
+ for (auto enumCount = 0; enumCount < val->enumeratorCount(); ++enumCount) {
+ m_currentScope->insertQMLIdentifier(val->enumerator(enumCount).name());
+ }
+ }
+}
+
+LanguageUtils::FakeMetaObject *
+FindUnqualifiedIDVisitor::localQmlFile2FakeMetaObject(QString filePath)
+{
+ using namespace QQmlJS::AST;
+ auto fake = new LanguageUtils::FakeMetaObject;
+ fake->setClassName(QFileInfo { filePath }.baseName());
+ QFile file(filePath);
+ if (!file.open(QFile::ReadOnly)) {
+ return fake;
+ }
+ QString code = file.readAll();
+ file.close();
+
+ QQmlJS::Engine engine;
+ QQmlJS::Lexer lexer(&engine);
+
+ lexer.setCode(code, 1, true);
+ QQmlJS::Parser parser(&engine);
+ if (!parser.parse()) {
+ return fake;
+ }
+ QQmlJS::AST::UiProgram *program = parser.ast();
+ auto header = program->headers;
+ while (header) {
+ if (auto import = cast<UiImport *>(header->headerItem)) {
+ if (import->version) {
+ QString path;
+ auto uri = import->importUri;
+ while (uri) {
+ path.append(uri->name);
+ path.append("/");
+ uri = uri->next;
+ }
+ path.chop(1);
+ QString prefix = QLatin1String("");
+ if (import->asToken.isValid()) {
+ prefix += import->importId + QLatin1Char('.');
+ }
+ importHelper(path, prefix, import->version->majorVersion, import->version->minorVersion);
+ }
+ }
+ header = header->next;
+ }
+ auto member = program->members;
+ // member should be the sole element
+ Q_ASSERT(!member->next);
+ Q_ASSERT(member && member->member->kind == UiObjectMember::Kind_UiObjectDefinition);
+ auto definition = static_cast<UiObjectDefinition *>(member->member);
+ auto qualifiedId = definition->qualifiedTypeNameId;
+ while (qualifiedId && qualifiedId->next) {
+ qualifiedId = qualifiedId->next;
+ }
+ fake->setSuperclassName(qualifiedId->name.toString());
+ UiObjectMemberList *initMembers = definition->initializer->members;
+ while (initMembers) {
+ switch (initMembers->member->kind) {
+ case UiObjectMember::Kind_UiArrayBinding: {
+ // nothing to do
+ break;
+ }
+ case UiObjectMember::Kind_UiEnumDeclaration: {
+ auto enumDeclaration = static_cast<UiEnumDeclaration *>(initMembers->member);
+ qDebug() << "enumdecl" << enumDeclaration->name;
+ break;
+ }
+ case UiObjectMember::Kind_UiObjectBinding: {
+ // nothing to do
+ break;
+ }
+ case UiObjectMember::Kind_UiObjectDefinition: {
+ // creates nothing accessible
+ /*auto objectDefinition = static_cast<UiObjectDefinition*>(initMembers->member);
+ qDebug() << "objdef" << objectDefinition->qualifiedTypeNameId->name;*/
+ break;
+ }
+ case UiObjectMember::Kind_UiPublicMember: {
+ auto publicMember = static_cast<UiPublicMember *>(initMembers->member);
+ switch (publicMember->type) {
+ case UiPublicMember::Signal: {
+ UiParameterList *param = publicMember->parameters;
+ LanguageUtils::FakeMetaMethod method;
+ method.setMethodType(LanguageUtils::FakeMetaMethod::Signal);
+ method.setMethodName(publicMember->name.toString());
+ while (param) {
+ method.addParameter(param->name.toString(), param->type->name.toString());
+ param = param->next;
+ }
+ fake->addMethod(method);
+ break;
+ }
+ case UiPublicMember::Property: {
+ LanguageUtils::FakeMetaProperty fakeprop { publicMember->name.toString(),
+ publicMember->typeModifier.toString(),
+ false,
+ false,
+ false,
+ 0 };
+ fake->addProperty(fakeprop);
+ break;
+ }
+ }
+ break;
+ }
+ case UiObjectMember::Kind_UiScriptBinding: {
+ // does not create anything new, ignore
+ break;
+ }
+ case UiObjectMember::Kind_UiSourceElement: {
+ auto sourceElement = static_cast<UiSourceElement *>(initMembers->member);
+ if (FunctionExpression *fexpr = sourceElement->sourceElement->asFunctionDefinition()) {
+ LanguageUtils::FakeMetaMethod method;
+ method.setMethodType(LanguageUtils::FakeMetaMethod::Method);
+ FormalParameterList *parameters = fexpr->formals;
+ while (parameters) {
+ method.addParameter(parameters->element->bindingIdentifier.toString(),
+ "");
+ parameters = parameters->next;
+ }
+ fake->addMethod(method);
+ } else if (ClassExpression *clexpr =
+ sourceElement->sourceElement->asClassDefinition()) {
+ LanguageUtils::FakeMetaProperty prop {
+ clexpr->name.toString(), "", false, false, false, 1
+ };
+ fake->addProperty(prop);
+ } else if (cast<VariableStatement *>(sourceElement->sourceElement)) {
+ // nothing to do
+ } else {
+ qDebug() << "unsupportedd sourceElement at" << sourceElement->firstSourceLocation()
+ << sourceElement->sourceElement->kind;
+ }
+ break;
+ }
+ default: {
+ qDebug() << "unsupported element of kind" << initMembers->member->kind;
+ }
+ }
+ initMembers = initMembers->next;
+ }
+ return fake;
+}
+
+void FindUnqualifiedIDVisitor::importExportedNames(QStringRef prefix, QString name)
+{
+ for (;;) {
+ auto metaObject = m_exportedName2MetaObject[m_exportedName2MetaObject.contains(name)
+ ? name
+ : prefix + QLatin1Char('.') + name];
+ if (metaObject) {
+ auto propertyCount = metaObject->propertyCount();
+ for (auto i = 0; i < propertyCount; ++i) {
+ m_currentScope->insertPropertyIdentifier(metaObject->property(i).name());
+ }
+
+ m_currentScope->addMethodsFromMetaObject(metaObject);
+
+ name = metaObject->superclassName();
+ if (name.isEmpty() || name == QLatin1String("QObject")) {
+ break;
+ }
+ } else {
+ qDebug() << name << "not found";
+ break;
+ }
+ }
+}
+
+void FindUnqualifiedIDVisitor::throwRecursionDepthError()
+{
+ return;
+}
+
+bool FindUnqualifiedIDVisitor::visit(QQmlJS::AST::UiProgram *)
+{
+ enterEnvironment(ScopeType::QMLScope, "program");
+ QHash<QString, LanguageUtils::FakeMetaObject::ConstPtr> objects;
+ QList<QQmlJS::ModuleApiInfo> moduleApis;
+ QStringList dependencies;
+ for (auto const &dir : m_qmltypeDirs) {
+ QDirIterator it { dir, QStringList() << QLatin1String("builtins.qmltypes"), QDir::NoFilter,
+ QDirIterator::Subdirectories };
+ while (it.hasNext()) {
+ auto reader = createReaderForFile(it.next());
+ auto succ = reader(&objects, &moduleApis, &dependencies);
+ if (!succ) {
+ qDebug() << reader.errorMessage();
+ }
+ }
+ }
+ // add builtins
+ for (auto ob_it = objects.begin(); ob_it != objects.end(); ++ob_it) {
+ auto val = ob_it.value();
+ for (auto export_ : val->exports()) {
+ m_exportedName2MetaObject[export_.type] = val;
+ }
+ for (auto enumCount = 0; enumCount < val->enumeratorCount(); ++enumCount) {
+ m_currentScope->insertQMLIdentifier(val->enumerator(enumCount).name());
+ }
+ }
+ // add "self" (as we only ever check the first part of a qualified identifier, we get away with
+ // using an empty FakeMetaObject
+ m_exportedName2MetaObject[QFileInfo { m_filePath }.baseName()] = {};
+
+ // add QML builtins
+ m_exportedName2MetaObject["QtObject"] = {}; // QtObject contains nothing of interest
+
+ LanguageUtils::FakeMetaObject *meta = new LanguageUtils::FakeMetaObject{};
+ meta->addProperty(LanguageUtils::FakeMetaProperty {"enabled", "bool", false, false, false, 0});
+ meta->addProperty(LanguageUtils::FakeMetaProperty {"ignoreUnknownSignals", "bool", false, false, false, 0});
+ meta->addProperty(LanguageUtils::FakeMetaProperty {"target", "QObject", false, false, false, 0});
+ m_exportedName2MetaObject["Connections"] = LanguageUtils::FakeMetaObject::ConstPtr { meta };
+ return true;
+}
+
+void FindUnqualifiedIDVisitor::endVisit(QQmlJS::AST::UiProgram *)
+{
+ leaveEnvironment();
+}
+
+bool FindUnqualifiedIDVisitor::visit(QQmlJS::AST::ClassExpression *ast)
+{
+ enterEnvironment(ScopeType::JSFunctionScope, ast->name.toString());
+ return true;
+}
+
+void FindUnqualifiedIDVisitor::endVisit(QQmlJS::AST::ClassExpression *)
+{
+ leaveEnvironment();
+}
+
+bool FindUnqualifiedIDVisitor::visit(QQmlJS::AST::ClassDeclaration *ast)
+{
+ enterEnvironment(ScopeType::JSFunctionScope, ast->name.toString());
+ return true;
+}
+
+void FindUnqualifiedIDVisitor::endVisit(QQmlJS::AST::ClassDeclaration *)
+{
+ leaveEnvironment();
+}
+
+bool FindUnqualifiedIDVisitor::visit(QQmlJS::AST::ForStatement *)
+{
+ enterEnvironment(ScopeType::JSLexicalScope, "forloop");
+ return true;
+}
+
+void FindUnqualifiedIDVisitor::endVisit(QQmlJS::AST::ForStatement *)
+{
+ leaveEnvironment();
+}
+
+bool FindUnqualifiedIDVisitor::visit(QQmlJS::AST::ForEachStatement *)
+{
+ enterEnvironment(ScopeType::JSLexicalScope, "foreachloop");
+ return true;
+}
+
+void FindUnqualifiedIDVisitor::endVisit(QQmlJS::AST::ForEachStatement *)
+{
+ leaveEnvironment();
+}
+
+bool FindUnqualifiedIDVisitor::visit(QQmlJS::AST::Block *)
+{
+ enterEnvironment(ScopeType::JSLexicalScope, "block");
+ return true;
+}
+
+void FindUnqualifiedIDVisitor::endVisit(QQmlJS::AST::Block *)
+{
+ leaveEnvironment();
+}
+
+bool FindUnqualifiedIDVisitor::visit(QQmlJS::AST::CaseBlock *)
+{
+ enterEnvironment(ScopeType::JSLexicalScope, "case");
+ return true;
+}
+
+void FindUnqualifiedIDVisitor::endVisit(QQmlJS::AST::CaseBlock *)
+{
+ leaveEnvironment();
+}
+
+bool FindUnqualifiedIDVisitor::visit(QQmlJS::AST::Catch *)
+{
+ enterEnvironment(ScopeType::JSLexicalScope, "catch");
+ return true;
+}
+
+void FindUnqualifiedIDVisitor::endVisit(QQmlJS::AST::Catch *)
+{
+ leaveEnvironment();
+}
+
+bool FindUnqualifiedIDVisitor::visit(QQmlJS::AST::WithStatement *withStatement)
+{
+ m_colorOut.write(QString::asprintf("Warning: "), Warning);
+ m_colorOut.write(QString::asprintf("%d:%d: with statements are strongly discouraged in QML and might cause false positives when analying unqalified identifiers\n", withStatement->firstSourceLocation().startLine, withStatement->firstSourceLocation().startColumn), Normal);
+ enterEnvironment(ScopeType::JSLexicalScope, "with");
+ return true;
+}
+
+void FindUnqualifiedIDVisitor::endVisit(QQmlJS::AST::WithStatement *)
+{
+ leaveEnvironment();
+}
+
+bool FindUnqualifiedIDVisitor::visit(QQmlJS::AST::UiScriptBinding *uisb)
+{
+ using namespace QQmlJS::AST;
+ auto name = uisb->qualifiedId->name;
+ if (name == QLatin1String("id")) {
+ // found id
+ auto expstat = static_cast<ExpressionStatement *>(uisb->statement);
+ auto identexp = static_cast<IdentifierExpression *>(expstat->expression);
+ QString elementName = m_currentScope->name();
+ m_qmlid2meta.insert(identexp->name.toString(), m_exportedName2MetaObject[elementName]);
+ if (m_currentScope->isVisualRootScope()) {
+ m_rootId = identexp->name.toString();
+ }
+ } else if (name.startsWith("on") && name.size() > 2 && name.at(2).isUpper()) {
+ auto statement = uisb->statement;
+ if (statement->kind == Node::Kind::Kind_ExpressionStatement) {
+ if (static_cast<ExpressionStatement *>(statement)->expression->asFunctionDefinition()) {
+ // functions are already handled
+ // they do not get names inserted according to the signal, but access their formal
+ // parameters
+ return true;
+ }
+ }
+ QString signal = name.mid(2).toString();
+ signal[0] = signal[0].toLower();
+ if (!m_currentScope->methods().contains(signal)) {
+ qDebug() << "Info file does not contain signal" << signal;
+ } else {
+ auto method = m_currentScope->methods()[signal];
+ for (auto const &param : method.parameterNames()) {
+ m_currentScope->insertSignalIdentifier(param, method, uisb->statement->firstSourceLocation());
+ }
+ }
+ return true;
+ }
+ return true;
+}
+
+bool FindUnqualifiedIDVisitor::visit(QQmlJS::AST::UiPublicMember *uipm)
+{
+ // property bool inactive: !active
+ // extract name inactive
+ m_currentScope->insertPropertyIdentifier(uipm->name.toString());
+ return true;
+}
+
+bool FindUnqualifiedIDVisitor::visit(QQmlJS::AST::IdentifierExpression *idexp)
+{
+ auto name = idexp->name;
+ if (!m_exportedName2MetaObject.contains(name.toString())) {
+ m_currentScope->addIdToAccssedIfNotInParentScopes(
+ { name.toString(), idexp->firstSourceLocation() });
+ }
+ return true;
+}
+
+FindUnqualifiedIDVisitor::FindUnqualifiedIDVisitor(QStringList const &qmltypeDirs,
+ const QString &code, const QString &fileName)
+ : m_rootScope(new ScopeTree { ScopeType::JSFunctionScope, "global" }),
+ m_currentScope(m_rootScope.get()),
+ m_qmltypeDirs(qmltypeDirs),
+ m_code(code),
+ m_rootId(QLatin1String("<id>")),
+ m_filePath(fileName)
+{
+ // setup color output
+ m_colorOut.insertColorMapping(Error, ColorOutput::RedForeground);
+ m_colorOut.insertColorMapping(Warning, ColorOutput::PurpleForeground);
+ m_colorOut.insertColorMapping(Info, ColorOutput::BlueForeground);
+ m_colorOut.insertColorMapping(Normal, ColorOutput::DefaultColor);
+ m_colorOut.insertColorMapping(Hint, ColorOutput::GreenForeground);
+ QLatin1String jsGlobVars[] = {
+ QLatin1String ("Array"), QLatin1String("Boolean"), QLatin1String("Date"), QLatin1String("Function"), QLatin1String("Math"), QLatin1String("Number"), QLatin1String("Object"), QLatin1String("RegExp"), QLatin1String("String"),
+ QLatin1String("Error"), QLatin1String("EvalError"), QLatin1String("RangeError"), QLatin1String("ReferenceError"), QLatin1String("SyntaxError"), QLatin1String("TypeError"), QLatin1String("URIError"),
+ QLatin1String("encodeURI"), QLatin1String("encodeURIComponent"), QLatin1String("decodeURI"), QLatin1String("decodeURIComponent"), QLatin1String("escape"), QLatin1String("unescape"),
+ QLatin1String("isFinite"), QLatin1String("isNanN"), QLatin1String("parseFloat"), QLatin1String("parseInt"),
+ QLatin1String("eval"), QLatin1String("console"), QLatin1String("print"), QLatin1String("gc"),
+ QLatin1String("qsTr"), QLatin1String("qsTrId"), QLatin1String("QT_TR_NOOP"), QLatin1String("QT_TRANSLATE_NOOP"), QLatin1String("QT_TRID_NOOP"),
+ QLatin1String("XMLHttpRequest"), QLatin1String("JSON"), QLatin1String("Promise"),
+ QLatin1String("undefined")
+ };
+ for (const auto& jsGlobVar: jsGlobVars)
+ m_currentScope->insertJSIdentifier(jsGlobVar, QQmlJS::AST::VariableScope::Const);
+}
+
+FindUnqualifiedIDVisitor::~FindUnqualifiedIDVisitor() = default;
+
+bool FindUnqualifiedIDVisitor::check()
+{
+ // now that all ids are known, revisit any Connections whose target were perviously unknown
+ for (auto const& outstandingConnection: m_outstandingConnections) {
+ auto metaObject = m_qmlid2meta[outstandingConnection.targetName];
+ outstandingConnection.scope->addMethodsFromMetaObject(metaObject);
+ QScopedValueRollback<ScopeTree*> rollback(m_currentScope, outstandingConnection.scope);
+ outstandingConnection.uiod->initializer->accept(this);
+ }
+ return m_rootScope->recheckIdentifiers(m_code, m_qmlid2meta, m_rootScope.get(), m_rootId, m_colorOut);
+}
+
+bool FindUnqualifiedIDVisitor::visit(QQmlJS::AST::VariableDeclarationList *vdl)
+{
+ while (vdl) {
+ m_currentScope->insertJSIdentifier(vdl->declaration->bindingIdentifier.toString(),
+ vdl->declaration->scope);
+ vdl = vdl->next;
+ }
+ return true;
+}
+
+void FindUnqualifiedIDVisitor::visitFunctionExpressionHelper(QQmlJS::AST::FunctionExpression *fexpr)
+{
+ using namespace QQmlJS::AST;
+ if (!fexpr->name.isEmpty()) {
+ auto name = fexpr->name.toString();
+ if (m_currentScope->scopeType() == ScopeType::QMLScope) {
+ m_currentScope->insertQMLIdentifier(name);
+ } else {
+ m_currentScope->insertJSIdentifier(name, VariableScope::Const);
+ }
+ }
+ // qDebug() << fexpr->firstSourceLocation() << "function expression" << fexpr->name;
+ QString name = fexpr->name.toString();
+ if (name.isEmpty())
+ name = "<anon>";
+ enterEnvironment(ScopeType::JSFunctionScope, name);
+}
+
+bool FindUnqualifiedIDVisitor::visit(QQmlJS::AST::FunctionExpression *fexpr)
+{
+ visitFunctionExpressionHelper(fexpr);
+ return true;
+}
+
+void FindUnqualifiedIDVisitor::endVisit(QQmlJS::AST::FunctionExpression *)
+{
+ leaveEnvironment();
+}
+
+bool FindUnqualifiedIDVisitor::visit(QQmlJS::AST::FunctionDeclaration *fdecl)
+{
+ visitFunctionExpressionHelper(fdecl);
+ return true;
+}
+
+void FindUnqualifiedIDVisitor::endVisit(QQmlJS::AST::FunctionDeclaration *)
+{
+ leaveEnvironment();
+}
+
+bool FindUnqualifiedIDVisitor::visit(QQmlJS::AST::FormalParameterList *fpl)
+{
+ for (auto const &boundName : fpl->boundNames()) {
+ m_currentScope->insertJSIdentifier(boundName.id, QQmlJS::AST::VariableScope::Const);
+ }
+ return true;
+}
+
+bool FindUnqualifiedIDVisitor::visit(QQmlJS::AST::UiImport *import)
+{
+ // construct path
+ QString prefix = QLatin1String("");
+ if (import->asToken.isValid()) {
+ prefix += import->importId + QLatin1Char('.');
+ }
+ auto dirname = import->fileName.toString();
+ if (!dirname.isEmpty()) {
+ QFileInfo info { dirname };
+ if (info.isRelative()) {
+ dirname = QDir(QFileInfo { m_filePath }.path()).filePath(dirname);
+ }
+ QDirIterator it { dirname, QStringList() << QLatin1String("*.qml"), QDir::NoFilter };
+ while (it.hasNext()) {
+ LanguageUtils::FakeMetaObject *fake = localQmlFile2FakeMetaObject(it.next());
+ m_exportedName2MetaObject.insert(
+ fake->className(), QSharedPointer<const LanguageUtils::FakeMetaObject>(fake));
+ }
+ }
+ QString path {};
+ if (!import->importId.isEmpty()) {
+ m_qmlid2meta.insert(import->importId.toString(), {}); // TODO: do not put imported ids into the same space as qml IDs
+ }
+ if (import->version) {
+ auto uri = import->importUri;
+ while (uri) {
+ path.append(uri->name);
+ path.append("/");
+ uri = uri->next;
+ }
+ path.chop(1);
+
+ importHelper(path, prefix, import->version->majorVersion, import->version->minorVersion);
+ }
+ return true;
+}
+
+bool FindUnqualifiedIDVisitor::visit(QQmlJS::AST::UiEnumDeclaration *uied)
+{
+ m_currentScope->insertQMLIdentifier(uied->name.toString());
+ return true;
+}
+
+bool FindUnqualifiedIDVisitor::visit(QQmlJS::AST::UiObjectBinding *uiob)
+{
+ // property QtObject __styleData: QtObject {...}
+ m_currentScope->insertPropertyIdentifier(uiob->qualifiedId->name.toString());
+ QString name {};
+ auto id = uiob->qualifiedTypeNameId;
+ QStringRef prefix = uiob->qualifiedTypeNameId->name;
+ while (id) {
+ name += id->name.toString() + QLatin1Char('.');
+ id = id->next;
+ }
+ name.chop(1);
+ enterEnvironment(ScopeType::QMLScope, name);
+ if (name == QLatin1String("Component") || name == QLatin1String("QtObject")) // there is no typeinfo for Component and QtObject, but they also have no interesting properties
+ return true;
+ importExportedNames(prefix, name);
+ return true;
+}
+
+void FindUnqualifiedIDVisitor::endVisit(QQmlJS::AST::UiObjectBinding *)
+{
+ leaveEnvironment();
+}
+
+bool FindUnqualifiedIDVisitor::visit(QQmlJS::AST::UiObjectDefinition *uiod)
+{
+ QString name {};
+ auto id = uiod->qualifiedTypeNameId;
+ QStringRef prefix = uiod->qualifiedTypeNameId->name;
+ while (id) {
+ name += id->name.toString() + QLatin1Char('.');
+ id = id->next;
+ }
+ name.chop(1);
+ enterEnvironment(ScopeType::QMLScope, name);
+ if (name.isLower())
+ return false; // Ignore grouped properties for now
+ if (name == QLatin1String("Component") || name == QLatin1String("QtObject")) // there is no typeinfo for Component
+ return true;
+ importExportedNames(prefix, name);
+ if (name.endsWith("Connections")) {
+ QString target;
+ auto member = uiod->initializer->members;
+ while (member) {
+ if (member->member->kind == QQmlJS::AST::Node::Kind_UiScriptBinding) {
+ auto asBinding = static_cast<QQmlJS::AST::UiScriptBinding*>(member->member);
+ if (asBinding->qualifiedId->name == QLatin1String("target")) {
+ if (asBinding->statement->kind == QQmlJS::AST::Node::Kind_ExpressionStatement) {
+ auto expr = static_cast<QQmlJS::AST::ExpressionStatement*>(asBinding->statement)->expression;
+ if (auto idexpr = QQmlJS::AST::cast<QQmlJS::AST::IdentifierExpression*>(expr)) {
+ target = idexpr->name.toString();
+ } else {
+ // more complex expressions are not supported
+ }
+ }
+ break;
+ }
+ }
+ member = member->next;
+ }
+ LanguageUtils::FakeMetaObject::ConstPtr metaObject {};
+ if (target.isEmpty()) {
+ // no target set, connection comes from parentF
+ ScopeTree* scope = m_currentScope;
+ do {
+ scope = scope->parentScope(); // TODO: rename method
+ } while (scope->scopeType() != ScopeType::QMLScope);
+ auto metaObject = m_exportedName2MetaObject[scope->name()];
+ } else {
+ // there was a target, check if we already can find it
+ auto metaObjectIt = m_qmlid2meta.find(target);
+ if (metaObjectIt != m_qmlid2meta.end()) {
+ metaObject = *metaObjectIt;
+ } else {
+ m_outstandingConnections.push_back({target, m_currentScope, uiod});
+ return false; // visit children later once target is known
+ }
+ }
+ m_currentScope->addMethodsFromMetaObject(metaObject);
+ }
+ return true;
+}
+
+void FindUnqualifiedIDVisitor::endVisit(QQmlJS::AST::UiObjectDefinition *)
+{
+ leaveEnvironment();
+}
+
+QDebug &operator<<(QDebug dbg, const QQmlJS::AST::SourceLocation &loc)
+{
+ QDebugStateSaver saver(dbg);
+ dbg.nospace() << loc.startLine;
+ dbg.nospace() << ":";
+ dbg.nospace() << loc.startColumn;
+ return dbg.maybeSpace();
+}
diff --git a/tools/qmllint/findunqualified.h b/tools/qmllint/findunqualified.h
new file mode 100644
index 0000000000..937194d142
--- /dev/null
+++ b/tools/qmllint/findunqualified.h
@@ -0,0 +1,129 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the tools applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef FINDUNQUALIFIED_H
+#define FINDUNQUALIFIED_H
+
+#include "qmljstypedescriptionreader.h"
+#include "qcoloroutput_p.h"
+
+#include <private/qqmljsastvisitor_p.h>
+#include <private/qqmljsast_p.h>
+
+#include <QScopedPointer>
+
+class ScopeTree;
+enum class ScopeType;
+
+class FindUnqualifiedIDVisitor : public QQmlJS::AST::Visitor {
+
+public:
+ explicit FindUnqualifiedIDVisitor(QStringList const &qmltypeDirs, const QString& code, const QString& fileName);
+ ~FindUnqualifiedIDVisitor() override;
+ bool check();
+
+private:
+ QScopedPointer<ScopeTree> m_rootScope;
+ ScopeTree *m_currentScope;
+ QHash<QString, LanguageUtils::FakeMetaObject::ConstPtr> m_exportedName2MetaObject;
+ QStringList m_qmltypeDirs;
+ const QString& m_code;
+ QHash<QString, LanguageUtils::FakeMetaObject::ConstPtr> m_qmlid2meta;
+ QString m_rootId;
+ QString m_filePath;
+ QSet<QPair<QString, QString>> m_alreadySeenImports;
+ ColorOutput m_colorOut;
+
+ struct OutstandingConnection {QString targetName; ScopeTree *scope; QQmlJS::AST::UiObjectDefinition *uiod;};
+
+ QVarLengthArray<OutstandingConnection, 3> m_outstandingConnections; // Connections whose target we have not encountered
+
+ void enterEnvironment(ScopeType type, QString name);
+ void leaveEnvironment();
+ void importHelper(QString id, QString prefix, int major, int minor);
+ LanguageUtils::FakeMetaObject* localQmlFile2FakeMetaObject(QString filePath);
+
+
+ void importExportedNames(QStringRef prefix, QString name);
+
+ void throwRecursionDepthError() override;
+
+ // start block/scope handling
+ bool visit(QQmlJS::AST::UiProgram *ast) override;
+ void endVisit(QQmlJS::AST::UiProgram *ast) override;
+
+ bool visit(QQmlJS::AST::ClassExpression *ast) override;
+ void endVisit(QQmlJS::AST::ClassExpression *ast) override;
+
+ bool visit(QQmlJS::AST::ClassDeclaration *ast) override;
+ void endVisit(QQmlJS::AST::ClassDeclaration *ast) override;
+
+ bool visit(QQmlJS::AST::ForStatement *ast) override;
+ void endVisit(QQmlJS::AST::ForStatement *ast) override;
+
+ bool visit(QQmlJS::AST::ForEachStatement *ast) override;
+ void endVisit(QQmlJS::AST::ForEachStatement *ast) override;
+
+ bool visit(QQmlJS::AST::Block *ast) override;
+ void endVisit(QQmlJS::AST::Block *ast) override;
+
+ bool visit(QQmlJS::AST::CaseBlock *ast) override;
+ void endVisit(QQmlJS::AST::CaseBlock *ast) override;
+
+ bool visit(QQmlJS::AST::Catch *ast) override;
+ void endVisit(QQmlJS::AST::Catch *ast) override;
+
+ bool visit(QQmlJS::AST::WithStatement *withStatement) override;
+ void endVisit(QQmlJS::AST::WithStatement *ast) override;
+
+ void visitFunctionExpressionHelper(QQmlJS::AST::FunctionExpression *fexpr);
+ bool visit(QQmlJS::AST::FunctionExpression *fexpr) override;
+ void endVisit(QQmlJS::AST::FunctionExpression *fexpr) override;
+
+ bool visit(QQmlJS::AST::FunctionDeclaration *fdecl) override;
+ void endVisit(QQmlJS::AST::FunctionDeclaration *fdecl) override;
+ /* --- end block handling --- */
+
+ bool visit(QQmlJS::AST::VariableDeclarationList *vdl) override;
+ bool visit(QQmlJS::AST::FormalParameterList *fpl) override;
+
+ bool visit(QQmlJS::AST::UiImport *import) override;
+ bool visit(QQmlJS::AST::UiEnumDeclaration *uied) override;
+ bool visit(QQmlJS::AST::UiObjectBinding *uiob) override;
+ void endVisit(QQmlJS::AST::UiObjectBinding *uiob) override;
+ bool visit(QQmlJS::AST::UiObjectDefinition *uiod) override;
+ void endVisit(QQmlJS::AST::UiObjectDefinition *) override;
+ bool visit(QQmlJS::AST::UiScriptBinding *uisb) override;
+ bool visit(QQmlJS::AST::UiPublicMember *uipm) override;
+
+ // expression handling
+ bool visit(QQmlJS::AST::IdentifierExpression *idexp) override;
+};
+
+
+#endif // FINDUNQUALIFIED_H
diff --git a/tools/qmllint/main.cpp b/tools/qmllint/main.cpp
index bf0ceb54b7..235ec16c6e 100644
--- a/tools/qmllint/main.cpp
+++ b/tools/qmllint/main.cpp
@@ -34,12 +34,19 @@
#endif
#include <QCoreApplication>
-#include <private/qv4staticvalue_p.h>
+#ifndef QT_BOOTSTRAPPED
+#include <QLibraryInfo>
+#endif
+
#include <private/qqmljslexer_p.h>
#include <private/qqmljsparser_p.h>
#include <private/qqmljsengine_p.h>
+#include <private/qqmljsastvisitor_p.h>
+#include <private/qqmljsast_p.h>
+
+#include "findunqualified.h"
-static bool lint_file(const QString &filename, bool silent)
+static bool lint_file(const QString &filename, const bool silent, const bool warnUnqualied, QStringList const &qmltypeDirs)
{
QFile file(filename);
if (!file.open(QFile::ReadOnly)) {
@@ -67,6 +74,13 @@ static bool lint_file(const QString &filename, bool silent)
}
}
+ if (success && !isJavaScript && warnUnqualied) {
+ auto root = parser.rootNode();
+ FindUnqualifiedIDVisitor v { qmltypeDirs, code, filename};
+ root->accept(&v);
+ success = v.check();
+ }
+
return success;
}
@@ -80,8 +94,20 @@ int main(int argv, char *argc[])
parser.setApplicationDescription(QLatin1String("QML syntax verifier"));
parser.addHelpOption();
parser.addVersionOption();
+
QCommandLineOption silentOption(QStringList() << "s" << "silent", QLatin1String("Don't output syntax errors"));
parser.addOption(silentOption);
+
+ QCommandLineOption checkUnqualified(QStringList() << "U" << "check-unqualified", QLatin1String("Warn about unqualified identifiers"));
+ parser.addOption(checkUnqualified);
+
+ QCommandLineOption qmltypesDirsOption(
+ QStringList() << "I"
+ << "qmldirs",
+ QLatin1String("Look for qmltypes files in specified directory"),
+ QLatin1String("directory"));
+ parser.addOption(qmltypesDirsOption);
+
parser.addPositionalArgument(QLatin1String("files"), QLatin1String("list of qml or js files to verify"));
parser.process(app);
@@ -92,8 +118,18 @@ int main(int argv, char *argc[])
}
bool silent = parser.isSet(silentOption);
+ bool warnUnqualified = parser.isSet(checkUnqualified);
+ // use host qml import path as a sane default if nothing else has been provided
+ QStringList qmltypeDirs = parser.isSet(qmltypesDirsOption) ? parser.values(qmltypesDirsOption)
+#ifndef QT_BOOTSTRAPPED
+ : QStringList{QLibraryInfo::location(QLibraryInfo::Qml2ImportsPath)};
+#else
+ : QStringList{};
+#endif
#else
bool silent = false;
+ bool warnUnqualified = false;
+ QStringList qmltypeDirs {};
#endif
bool success = true;
#if QT_CONFIG(commandlineparser)
@@ -102,7 +138,7 @@ int main(int argv, char *argc[])
const auto arguments = app.arguments();
for (const QString &filename : arguments)
#endif
- success &= lint_file(filename, silent);
+ success &= lint_file(filename, silent, warnUnqualified, qmltypeDirs);
return success ? 0 : -1;
}
diff --git a/tools/qmllint/qcoloroutput.cpp b/tools/qmllint/qcoloroutput.cpp
new file mode 100644
index 0000000000..d2e723700a
--- /dev/null
+++ b/tools/qmllint/qcoloroutput.cpp
@@ -0,0 +1,342 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the tools applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QFile>
+#include <QHash>
+#include <QTextCodec>
+
+#ifndef Q_OS_WIN
+#include <unistd.h>
+#endif
+
+#include "qcoloroutput_p.h"
+
+class ColorOutputPrivate
+{
+public:
+ ColorOutputPrivate() : currentColorID(-1)
+
+ {
+ /* - QIODevice::Unbuffered because we want it to appear when the user actually calls, performance
+ * is considered of lower priority.
+ */
+ m_out.open(stderr, QIODevice::WriteOnly | QIODevice::Unbuffered);
+
+ coloringEnabled = isColoringPossible();
+ }
+
+ ColorOutput::ColorMapping colorMapping;
+ int currentColorID;
+ bool coloringEnabled;
+
+ static const char *const foregrounds[];
+ static const char *const backgrounds[];
+
+ inline void write(const QString &msg)
+ {
+ m_out.write(msg.toLocal8Bit());
+ }
+
+ static QString escapeCode(const QString &in)
+ {
+ QString result;
+ result.append(QChar(0x1B));
+ result.append(QLatin1Char('['));
+ result.append(in);
+ result.append(QLatin1Char('m'));
+ return result;
+ }
+
+private:
+ QFile m_out;
+
+ /*!
+ Returns true if it's suitable to send colored output to \c stderr.
+ */
+ inline bool isColoringPossible() const
+ {
+# if defined(Q_OS_WIN)
+ /* Windows doesn't at all support ANSI escape codes, unless
+ * the user install a "device driver". See the Wikipedia links in the
+ * class documentation for details. */
+ return false;
+# else
+ /* We use QFile::handle() to get the file descriptor. It's a bit unsure
+ * whether it's 2 on all platforms and in all cases, so hopefully this layer
+ * of abstraction helps handle such cases. */
+ return isatty(m_out.handle());
+# endif
+ }
+};
+
+const char *const ColorOutputPrivate::foregrounds[] =
+{
+ "0;30",
+ "0;34",
+ "0;32",
+ "0;36",
+ "0;31",
+ "0;35",
+ "0;33",
+ "0;37",
+ "1;30",
+ "1;34",
+ "1;32",
+ "1;36",
+ "1;31",
+ "1;35",
+ "1;33",
+ "1;37"
+};
+
+const char *const ColorOutputPrivate::backgrounds[] =
+{
+ "0;40",
+ "0;44",
+ "0;42",
+ "0;46",
+ "0;41",
+ "0;45",
+ "0;43"
+};
+
+/*!
+ \class ColorOutput
+ \since 4.4
+ \nonreentrant
+ \brief Outputs colored messages to \c stderr.
+ \internal
+
+ ColorOutput is a convenience class for outputting messages to \c
+ stderr using color escape codes, as mandated in ECMA-48. ColorOutput
+ will only color output when it is detected to be suitable. For
+ instance, if \c stderr is detected to be attached to a file instead
+ of a TTY, no coloring will be done.
+
+ ColorOutput does its best attempt. but it is generally undefined
+ what coloring or effect the various coloring flags has. It depends
+ strongly on what terminal software that is being used.
+
+ When using `echo -e 'my escape sequence'`, \c{\033} works as an
+ initiator but not when printing from a C++ program, despite having
+ escaped the backslash. That's why we below use characters with
+ value 0x1B.
+
+ It can be convenient to subclass ColorOutput with a private scope,
+ such that the functions are directly available in the class using
+ it.
+
+ \section1 Usage
+
+ To output messages, call write() or writeUncolored(). write() takes
+ as second argument an integer, which ColorOutput uses as a lookup
+ key to find the color it should color the text in. The mapping from
+ keys to colors is done using insertMapping(). Typically this is used
+ by having enums for the various kinds of messages, which
+ subsequently are registered.
+
+ \code
+ enum MyMessage
+ {
+ Error,
+ Important
+ };
+
+ ColorOutput output;
+ output.insertMapping(Error, ColorOutput::RedForeground);
+ output.insertMapping(Import, ColorOutput::BlueForeground);
+
+ output.write("This is important", Important);
+ output.write("Jack, I'm only the selected official!", Error);
+ \endcode
+
+ \sa {http://tldp.org/HOWTO/Bash-Prompt-HOWTO/x329.html}{Bash Prompt HOWTO, 6.1. Colors},
+ {http://linuxgazette.net/issue51/livingston-blade.html}{Linux Gazette, Tweaking Eterm, Edward Livingston-Blade},
+ {http://www.ecma-international.org/publications/standards/Ecma-048.htm}{Standard ECMA-48, Control Functions for Coded Character Sets, ECMA International},
+ {http://en.wikipedia.org/wiki/ANSI_escape_code}{Wikipedia, ANSI escape code},
+ {http://linuxgazette.net/issue65/padala.html}{Linux Gazette, So You Like Color!, Pradeep Padala}
+ */
+
+/*!
+ \enum ColorOutput::ColorCodeComponent
+ \value BlackForeground
+ \value BlueForeground
+ \value GreenForeground
+ \value CyanForeground
+ \value RedForeground
+ \value PurpleForeground
+ \value BrownForeground
+ \value LightGrayForeground
+ \value DarkGrayForeground
+ \value LightBlueForeground
+ \value LightGreenForeground
+ \value LightCyanForeground
+ \value LightRedForeground
+ \value LightPurpleForeground
+ \value YellowForeground
+ \value WhiteForeground
+ \value BlackBackground
+ \value BlueBackground
+ \value GreenBackground
+ \value CyanBackground
+ \value RedBackground
+ \value PurpleBackground
+ \value BrownBackground
+
+ \value DefaultColor ColorOutput performs no coloring. This typically
+ means black on white or white on black, depending
+ on the settings of the user's terminal.
+ */
+
+/*!
+ Sets the color mapping to be \a cMapping.
+
+ Negative values are disallowed.
+
+ \sa colorMapping(), insertMapping()
+ */
+void ColorOutput::setColorMapping(const ColorMapping &cMapping)
+{
+ d->colorMapping = cMapping;
+}
+
+/*!
+ Returns the color mappings in use.
+
+ \sa setColorMapping(), insertMapping()
+ */
+ColorOutput::ColorMapping ColorOutput::colorMapping() const
+{
+ return d->colorMapping;
+}
+
+/*!
+ Constructs a ColorOutput instance, ready for use.
+ */
+ColorOutput::ColorOutput() : d(new ColorOutputPrivate())
+{
+}
+
+ColorOutput::~ColorOutput() = default; // must be here so that QScopedPointer has access to the complete type
+
+/*!
+ Sends \a message to \c stderr, using the color looked up in colorMapping() using \a colorID.
+
+ If \a color isn't available in colorMapping(), result and behavior is undefined.
+
+ If \a colorID is 0, which is the default value, the previously used coloring is used. ColorOutput
+ is initialized to not color at all.
+
+ If \a message is empty, effects are undefined.
+
+ \a message will be printed as is. For instance, no line endings will be inserted.
+ */
+void ColorOutput::write(const QString &message, int colorID)
+{
+ d->write(colorify(message, colorID));
+}
+
+/*!
+ Writes \a message to \c stderr as if for instance
+ QTextStream would have been used, and adds a line ending at the end.
+
+ This function can be practical to use such that one can use ColorOutput for all forms of writing.
+ */
+void ColorOutput::writeUncolored(const QString &message)
+{
+ d->write(message + QLatin1Char('\n'));
+}
+
+/*!
+ Treats \a message and \a colorID identically to write(), but instead of writing
+ \a message to \c stderr, it is prepared for being written to \c stderr, but is then
+ returned.
+
+ This is useful when the colored string is inserted into a translated string(dividing
+ the string into several small strings prevents proper translation).
+ */
+QString ColorOutput::colorify(const QString &message, int colorID) const
+{
+ Q_ASSERT_X(colorID == -1 || d->colorMapping.contains(colorID), Q_FUNC_INFO,
+ qPrintable(QString::fromLatin1("There is no color registered by id %1").arg(colorID)));
+ Q_ASSERT_X(!message.isEmpty(), Q_FUNC_INFO, "It makes no sense to attempt to print an empty string.");
+
+ if (colorID != -1)
+ d->currentColorID = colorID;
+
+ if (d->coloringEnabled && colorID != -1)
+ {
+ const int color(d->colorMapping.value(colorID));
+
+ /* If DefaultColor is set, we don't want to color it. */
+ if (color & DefaultColor)
+ return message;
+
+ const int foregroundCode = (int(color) & ForegroundMask) >> ForegroundShift;
+ const int backgroundCode = (int(color) & BackgroundMask) >> BackgroundShift;
+ QString finalMessage;
+ bool closureNeeded = false;
+
+ if (foregroundCode)
+ {
+ finalMessage.append(ColorOutputPrivate::escapeCode(QLatin1String(ColorOutputPrivate::foregrounds[foregroundCode - 1])));
+ closureNeeded = true;
+ }
+
+ if (backgroundCode)
+ {
+ finalMessage.append(ColorOutputPrivate::escapeCode(QLatin1String(ColorOutputPrivate::backgrounds[backgroundCode - 1])));
+ closureNeeded = true;
+ }
+
+ finalMessage.append(message);
+
+ if (closureNeeded)
+ {
+ finalMessage.append(QChar(0x1B));
+ finalMessage.append(QLatin1String("[0m"));
+ }
+
+ return finalMessage;
+ }
+ else
+ return message;
+}
+
+/*!
+ Adds a color mapping from \a colorID to \a colorCode, for this ColorOutput instance.
+
+ This is a convenience function for creating a ColorOutput::ColorMapping instance and
+ calling setColorMapping().
+
+ \sa colorMapping(), setColorMapping()
+ */
+void ColorOutput::insertColorMapping(int colorID, const ColorCode colorCode)
+{
+ d->colorMapping.insert(colorID, colorCode);
+}
diff --git a/tools/qmllint/qcoloroutput_p.h b/tools/qmllint/qcoloroutput_p.h
new file mode 100644
index 0000000000..710bf5db74
--- /dev/null
+++ b/tools/qmllint/qcoloroutput_p.h
@@ -0,0 +1,110 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the tools applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//
+// 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.
+
+#ifndef QCOLOROUTPUT_P_H
+#define QCOLOROUTPUT_P_H
+
+#include <QtCore/QtGlobal>
+#include <QtCore/QHash>
+#include <QScopedPointer>
+
+class ColorOutputPrivate;
+
+class ColorOutput
+{
+ enum
+ {
+ ForegroundShift = 10,
+ BackgroundShift = 20,
+ SpecialShift = 20,
+ ForegroundMask = 0x1f << ForegroundShift,
+ BackgroundMask = 0x7 << BackgroundShift
+ };
+
+public:
+ enum ColorCodeComponent
+ {
+ BlackForeground = 1 << ForegroundShift,
+ BlueForeground = 2 << ForegroundShift,
+ GreenForeground = 3 << ForegroundShift,
+ CyanForeground = 4 << ForegroundShift,
+ RedForeground = 5 << ForegroundShift,
+ PurpleForeground = 6 << ForegroundShift,
+ BrownForeground = 7 << ForegroundShift,
+ LightGrayForeground = 8 << ForegroundShift,
+ DarkGrayForeground = 9 << ForegroundShift,
+ LightBlueForeground = 10 << ForegroundShift,
+ LightGreenForeground = 11 << ForegroundShift,
+ LightCyanForeground = 12 << ForegroundShift,
+ LightRedForeground = 13 << ForegroundShift,
+ LightPurpleForeground = 14 << ForegroundShift,
+ YellowForeground = 15 << ForegroundShift,
+ WhiteForeground = 16 << ForegroundShift,
+
+ BlackBackground = 1 << BackgroundShift,
+ BlueBackground = 2 << BackgroundShift,
+ GreenBackground = 3 << BackgroundShift,
+ CyanBackground = 4 << BackgroundShift,
+ RedBackground = 5 << BackgroundShift,
+ PurpleBackground = 6 << BackgroundShift,
+ BrownBackground = 7 << BackgroundShift,
+ DefaultColor = 1 << SpecialShift
+ };
+
+ typedef QFlags<ColorCodeComponent> ColorCode;
+ typedef QHash<int, ColorCode> ColorMapping;
+
+ ColorOutput();
+ ~ColorOutput();
+
+ void setColorMapping(const ColorMapping &cMapping);
+ ColorMapping colorMapping() const;
+ void insertColorMapping(int colorID, const ColorCode colorCode);
+
+ void writeUncolored(const QString &message);
+ void write(const QString &message, int color = -1);
+ QString colorify(const QString &message, int color = -1) const;
+
+private:
+ QScopedPointer<ColorOutputPrivate> d;
+ Q_DISABLE_COPY(ColorOutput)
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(ColorOutput::ColorCode)
+
+#endif
diff --git a/tools/qmllint/qmljstypedescriptionreader.cpp b/tools/qmllint/qmljstypedescriptionreader.cpp
new file mode 100644
index 0000000000..542cdf99eb
--- /dev/null
+++ b/tools/qmllint/qmljstypedescriptionreader.cpp
@@ -0,0 +1,704 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the tools applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qmljstypedescriptionreader.h"
+
+#include <private/qqmljsparser_p.h>
+#include <private/qqmljslexer_p.h>
+#include <private/qqmljsengine_p.h>
+
+#include <QDir>
+
+#define QTC_ASSERT_STRINGIFY_HELPER(x) #x
+#define QTC_ASSERT_STRINGIFY(x) QTC_ASSERT_STRINGIFY_HELPER(x)
+#define QTC_ASSERT_STRING(cond) qDebug() << (\
+ "\"" cond"\" in file " __FILE__ ", line " QTC_ASSERT_STRINGIFY(__LINE__))
+#define QTC_ASSERT(cond, action) if (Q_LIKELY(cond)) {} else { QTC_ASSERT_STRING(#cond); action; } do {} while (0)
+
+using namespace QQmlJS;
+using namespace QQmlJS::AST;
+using namespace LanguageUtils;
+
+QString toString(const AST::UiQualifiedId *qualifiedId, QChar delimiter = QLatin1Char('.'))
+{
+ QString result;
+
+ for (const UiQualifiedId *iter = qualifiedId; iter; iter = iter->next) {
+ if (iter != qualifiedId)
+ result += delimiter;
+
+ result += iter->name;
+ }
+
+ return result;
+}
+
+TypeDescriptionReader::TypeDescriptionReader(const QString &fileName, const QString &data)
+ : _fileName (fileName), _source(data), _objects(0)
+{
+}
+
+TypeDescriptionReader::~TypeDescriptionReader()
+{
+}
+
+bool TypeDescriptionReader::operator()(
+ QHash<QString, FakeMetaObject::ConstPtr> *objects,
+ QList<ModuleApiInfo> *moduleApis,
+ QStringList *dependencies)
+{
+ Engine engine;
+
+ Lexer lexer(&engine);
+ Parser parser(&engine);
+
+ lexer.setCode(_source, /*line = */ 1, /*qmlMode = */true);
+
+ if (!parser.parse()) {
+ _errorMessage = QString::fromLatin1("%1:%2: %3").arg(
+ QString::number(parser.errorLineNumber()),
+ QString::number(parser.errorColumnNumber()),
+ parser.errorMessage());
+ return false;
+ }
+
+ _objects = objects;
+ _moduleApis = moduleApis;
+ _dependencies = dependencies;
+ readDocument(parser.ast());
+
+ return _errorMessage.isEmpty();
+}
+
+QString TypeDescriptionReader::errorMessage() const
+{
+ return _errorMessage;
+}
+
+QString TypeDescriptionReader::warningMessage() const
+{
+ return _warningMessage;
+}
+
+void TypeDescriptionReader::readDocument(UiProgram *ast)
+{
+ if (!ast) {
+ addError(SourceLocation(), tr("Could not parse document."));
+ return;
+ }
+
+ if (!ast->headers || ast->headers->next || !AST::cast<AST::UiImport *>(ast->headers->headerItem)) {
+ addError(SourceLocation(), tr("Expected a single import."));
+ return;
+ }
+
+ UiImport *import = AST::cast<AST::UiImport *>(ast->headers->headerItem);
+ if (toString(import->importUri) != QLatin1String("QtQuick.tooling")) {
+ addError(import->importToken, tr("Expected import of QtQuick.tooling."));
+ return;
+ }
+
+ ComponentVersion version;
+ const QString versionString = _source.mid(import->versionToken.offset, import->versionToken.length);
+ const int dotIdx = versionString.indexOf(QLatin1Char('.'));
+ if (dotIdx != -1) {
+ version = ComponentVersion(versionString.leftRef(dotIdx).toInt(),
+ versionString.midRef(dotIdx + 1).toInt());
+ }
+ if (version.majorVersion() != 1) {
+ addError(import->versionToken, tr("Major version different from 1 not supported."));
+ return;
+ }
+
+ if (!ast->members || !ast->members->member || ast->members->next) {
+ addError(SourceLocation(), tr("Expected document to contain a single object definition."));
+ return;
+ }
+
+ UiObjectDefinition *module = AST::cast<UiObjectDefinition *>(ast->members->member);
+ if (!module) {
+ addError(SourceLocation(), tr("Expected document to contain a single object definition."));
+ return;
+ }
+
+ if (toString(module->qualifiedTypeNameId) != QLatin1String("Module")) {
+ addError(SourceLocation(), tr("Expected document to contain a Module {} member."));
+ return;
+ }
+
+ readModule(module);
+}
+
+void TypeDescriptionReader::readModule(UiObjectDefinition *ast)
+{
+ for (UiObjectMemberList *it = ast->initializer->members; it; it = it->next) {
+ UiObjectMember *member = it->member;
+ UiObjectDefinition *component = AST::cast<UiObjectDefinition *>(member);
+
+ UiScriptBinding *script = AST::cast<UiScriptBinding *>(member);
+ if (script && (toString(script->qualifiedId) == QStringLiteral("dependencies"))) {
+ readDependencies(script);
+ continue;
+ }
+
+ QString typeName;
+ if (component)
+ typeName = toString(component->qualifiedTypeNameId);
+
+ if (!component || (typeName != QLatin1String("Component") && typeName != QLatin1String("ModuleApi"))) {
+ continue;
+ }
+
+ if (typeName == QLatin1String("Component"))
+ readComponent(component);
+ else if (typeName == QLatin1String("ModuleApi"))
+ readModuleApi(component);
+ }
+}
+
+void TypeDescriptionReader::addError(const SourceLocation &loc, const QString &message)
+{
+ _errorMessage += QString::fromLatin1("%1:%2:%3: %4\n").arg(
+ QDir::toNativeSeparators(_fileName),
+ QString::number(loc.startLine),
+ QString::number(loc.startColumn),
+ message);
+}
+
+void TypeDescriptionReader::addWarning(const SourceLocation &loc, const QString &message)
+{
+ _warningMessage += QString::fromLatin1("%1:%2:%3: %4\n").arg(
+ QDir::toNativeSeparators(_fileName),
+ QString::number(loc.startLine),
+ QString::number(loc.startColumn),
+ message);
+}
+
+void TypeDescriptionReader::readDependencies(UiScriptBinding *ast)
+{
+ ExpressionStatement *stmt = AST::cast<ExpressionStatement*>(ast->statement);
+ if (!stmt) {
+ addError(ast->statement->firstSourceLocation(), tr("Expected dependency definitions"));
+ return;
+ }
+ ArrayPattern *exp = AST::cast<ArrayPattern *>(stmt->expression);
+ if (!exp) {
+ addError(stmt->expression->firstSourceLocation(), tr("Expected dependency definitions"));
+ return;
+ }
+ for (PatternElementList *l = exp->elements; l; l = l->next) {
+ //StringLiteral *str = AST::cast<StringLiteral *>(l->element->initializer);
+ StringLiteral *str = AST::cast<StringLiteral *>(l->element->initializer);
+ *_dependencies << str->value.toString();
+ }
+}
+
+void TypeDescriptionReader::readComponent(UiObjectDefinition *ast)
+{
+ FakeMetaObject::Ptr fmo(new FakeMetaObject);
+
+ for (UiObjectMemberList *it = ast->initializer->members; it; it = it->next) {
+ UiObjectMember *member = it->member;
+ UiObjectDefinition *component = AST::cast<UiObjectDefinition *>(member);
+ UiScriptBinding *script = AST::cast<UiScriptBinding *>(member);
+ if (component) {
+ QString name = toString(component->qualifiedTypeNameId);
+ if (name == QLatin1String("Property"))
+ readProperty(component, fmo);
+ else if (name == QLatin1String("Method") || name == QLatin1String("Signal"))
+ readSignalOrMethod(component, name == QLatin1String("Method"), fmo);
+ else if (name == QLatin1String("Enum"))
+ readEnum(component, fmo);
+ else
+ addWarning(component->firstSourceLocation(),
+ tr("Expected only Property, Method, Signal and Enum object definitions, not \"%1\".")
+ .arg(name));
+ } else if (script) {
+ QString name = toString(script->qualifiedId);
+ if (name == QLatin1String("name")) {
+ fmo->setClassName(readStringBinding(script));
+ } else if (name == QLatin1String("prototype")) {
+ fmo->setSuperclassName(readStringBinding(script));
+ } else if (name == QLatin1String("defaultProperty")) {
+ fmo->setDefaultPropertyName(readStringBinding(script));
+ } else if (name == QLatin1String("exports")) {
+ readExports(script, fmo);
+ } else if (name == QLatin1String("exportMetaObjectRevisions")) {
+ readMetaObjectRevisions(script, fmo);
+ } else if (name == QLatin1String("attachedType")) {
+ fmo->setAttachedTypeName(readStringBinding(script));
+ } else if (name == QLatin1String("isSingleton")) {
+ fmo->setIsSingleton(readBoolBinding(script));
+ } else if (name == QLatin1String("isCreatable")) {
+ fmo->setIsCreatable(readBoolBinding(script));
+ } else if (name == QLatin1String("isComposite")) {
+ fmo->setIsComposite(readBoolBinding(script));
+ } else {
+ addWarning(script->firstSourceLocation(),
+ tr("Expected only name, prototype, defaultProperty, attachedType, exports, "
+ "isSingleton, isCreatable, isComposite and exportMetaObjectRevisions "
+ "script bindings, not \"%1\".").arg(name));
+ }
+ } else {
+ addWarning(member->firstSourceLocation(), tr("Expected only script bindings and object definitions."));
+ }
+ }
+
+ if (fmo->className().isEmpty()) {
+ addError(ast->firstSourceLocation(), tr("Component definition is missing a name binding."));
+ return;
+ }
+
+ // ### add implicit export into the package of c++ types
+ fmo->addExport(fmo->className(), QStringLiteral("<cpp>"), ComponentVersion());
+ fmo->updateFingerprint();
+ _objects->insert(fmo->className(), fmo);
+}
+
+void TypeDescriptionReader::readModuleApi(UiObjectDefinition *ast)
+{
+ ModuleApiInfo apiInfo;
+
+ for (UiObjectMemberList *it = ast->initializer->members; it; it = it->next) {
+ UiObjectMember *member = it->member;
+ UiScriptBinding *script = AST::cast<UiScriptBinding *>(member);
+
+ if (script) {
+ const QString name = toString(script->qualifiedId);
+ if (name == QLatin1String("uri")) {
+ apiInfo.uri = readStringBinding(script);
+ } else if (name == QLatin1String("version")) {
+ apiInfo.version = readNumericVersionBinding(script);
+ } else if (name == QLatin1String("name")) {
+ apiInfo.cppName = readStringBinding(script);
+ } else {
+ addWarning(script->firstSourceLocation(),
+ tr("Expected only uri, version and name script bindings."));
+ }
+ } else {
+ addWarning(member->firstSourceLocation(), tr("Expected only script bindings."));
+ }
+ }
+
+ if (!apiInfo.version.isValid()) {
+ addError(ast->firstSourceLocation(), tr("ModuleApi definition has no or invalid version binding."));
+ return;
+ }
+
+ if (_moduleApis)
+ _moduleApis->append(apiInfo);
+}
+
+void TypeDescriptionReader::readSignalOrMethod(UiObjectDefinition *ast, bool isMethod, FakeMetaObject::Ptr fmo)
+{
+ FakeMetaMethod fmm;
+ // ### confusion between Method and Slot. Method should be removed.
+ if (isMethod)
+ fmm.setMethodType(FakeMetaMethod::Slot);
+ else
+ fmm.setMethodType(FakeMetaMethod::Signal);
+
+ for (UiObjectMemberList *it = ast->initializer->members; it; it = it->next) {
+ UiObjectMember *member = it->member;
+ UiObjectDefinition *component = AST::cast<UiObjectDefinition *>(member);
+ UiScriptBinding *script = AST::cast<UiScriptBinding *>(member);
+ if (component) {
+ QString name = toString(component->qualifiedTypeNameId);
+ if (name == QLatin1String("Parameter"))
+ readParameter(component, &fmm);
+ else
+ addWarning(component->firstSourceLocation(), tr("Expected only Parameter object definitions."));
+ } else if (script) {
+ QString name = toString(script->qualifiedId);
+ if (name == QLatin1String("name"))
+ fmm.setMethodName(readStringBinding(script));
+ else if (name == QLatin1String("type"))
+ fmm.setReturnType(readStringBinding(script));
+ else if (name == QLatin1String("revision"))
+ fmm.setRevision(readIntBinding(script));
+ else
+ addWarning(script->firstSourceLocation(), tr("Expected only name and type script bindings."));
+
+ } else {
+ addWarning(member->firstSourceLocation(), tr("Expected only script bindings and object definitions."));
+ }
+ }
+
+ if (fmm.methodName().isEmpty()) {
+ addError(ast->firstSourceLocation(), tr("Method or signal is missing a name script binding."));
+ return;
+ }
+
+ fmo->addMethod(fmm);
+}
+
+void TypeDescriptionReader::readProperty(UiObjectDefinition *ast, FakeMetaObject::Ptr fmo)
+{
+ QString name;
+ QString type;
+ bool isPointer = false;
+ bool isReadonly = false;
+ bool isList = false;
+ int revision = 0;
+
+ for (UiObjectMemberList *it = ast->initializer->members; it; it = it->next) {
+ UiObjectMember *member = it->member;
+ UiScriptBinding *script = AST::cast<UiScriptBinding *>(member);
+ if (!script) {
+ addWarning(member->firstSourceLocation(), tr("Expected script binding."));
+ continue;
+ }
+
+ QString id = toString(script->qualifiedId);
+ if (id == QLatin1String("name"))
+ name = readStringBinding(script);
+ else if (id == QLatin1String("type"))
+ type = readStringBinding(script);
+ else if (id == QLatin1String("isPointer"))
+ isPointer = readBoolBinding(script);
+ else if (id == QLatin1String("isReadonly"))
+ isReadonly = readBoolBinding(script);
+ else if (id == QLatin1String("isList"))
+ isList = readBoolBinding(script);
+ else if (id == QLatin1String("revision"))
+ revision = readIntBinding(script);
+ else
+ addWarning(script->firstSourceLocation(), tr("Expected only type, name, revision, isPointer, isReadonly and isList script bindings."));
+ }
+
+ if (name.isEmpty() || type.isEmpty()) {
+ addError(ast->firstSourceLocation(), tr("Property object is missing a name or type script binding."));
+ return;
+ }
+
+ fmo->addProperty(FakeMetaProperty(name, type, isList, !isReadonly, isPointer, revision));
+}
+
+void TypeDescriptionReader::readEnum(UiObjectDefinition *ast, FakeMetaObject::Ptr fmo)
+{
+ FakeMetaEnum fme;
+
+ for (UiObjectMemberList *it = ast->initializer->members; it; it = it->next) {
+ UiObjectMember *member = it->member;
+ UiScriptBinding *script = AST::cast<UiScriptBinding *>(member);
+ if (!script) {
+ addWarning(member->firstSourceLocation(), tr("Expected script binding."));
+ continue;
+ }
+
+ QString name = toString(script->qualifiedId);
+ if (name == QLatin1String("name"))
+ fme.setName(readStringBinding(script));
+ else if (name == QLatin1String("values"))
+ readEnumValues(script, &fme);
+ else
+ addWarning(script->firstSourceLocation(), tr("Expected only name and values script bindings."));
+ }
+
+ fmo->addEnum(fme);
+}
+
+void TypeDescriptionReader::readParameter(UiObjectDefinition *ast, FakeMetaMethod *fmm)
+{
+ QString name;
+ QString type;
+
+ for (UiObjectMemberList *it = ast->initializer->members; it; it = it->next) {
+ UiObjectMember *member = it->member;
+ UiScriptBinding *script = AST::cast<UiScriptBinding *>(member);
+ if (!script) {
+ addWarning(member->firstSourceLocation(), tr("Expected script binding."));
+ continue;
+ }
+
+ const QString id = toString(script->qualifiedId);
+ if (id == QLatin1String("name")) {
+ name = readStringBinding(script);
+ } else if (id == QLatin1String("type")) {
+ type = readStringBinding(script);
+ } else if (id == QLatin1String("isPointer")) {
+ // ### unhandled
+ } else if (id == QLatin1String("isReadonly")) {
+ // ### unhandled
+ } else if (id == QLatin1String("isList")) {
+ // ### unhandled
+ } else {
+ addWarning(script->firstSourceLocation(), tr("Expected only name and type script bindings."));
+ }
+ }
+
+ fmm->addParameter(name, type);
+}
+
+QString TypeDescriptionReader::readStringBinding(UiScriptBinding *ast)
+{
+ QTC_ASSERT(ast, return QString());
+
+ if (!ast->statement) {
+ addError(ast->colonToken, tr("Expected string after colon."));
+ return QString();
+ }
+
+ ExpressionStatement *expStmt = AST::cast<ExpressionStatement *>(ast->statement);
+ if (!expStmt) {
+ addError(ast->statement->firstSourceLocation(), tr("Expected string after colon."));
+ return QString();
+ }
+
+ StringLiteral *stringLit = AST::cast<StringLiteral *>(expStmt->expression);
+ if (!stringLit) {
+ addError(expStmt->firstSourceLocation(), tr("Expected string after colon."));
+ return QString();
+ }
+
+ return stringLit->value.toString();
+}
+
+bool TypeDescriptionReader::readBoolBinding(AST::UiScriptBinding *ast)
+{
+ QTC_ASSERT(ast, return false);
+
+ if (!ast->statement) {
+ addError(ast->colonToken, tr("Expected boolean after colon."));
+ return false;
+ }
+
+ ExpressionStatement *expStmt = AST::cast<ExpressionStatement *>(ast->statement);
+ if (!expStmt) {
+ addError(ast->statement->firstSourceLocation(), tr("Expected boolean after colon."));
+ return false;
+ }
+
+ TrueLiteral *trueLit = AST::cast<TrueLiteral *>(expStmt->expression);
+ FalseLiteral *falseLit = AST::cast<FalseLiteral *>(expStmt->expression);
+ if (!trueLit && !falseLit) {
+ addError(expStmt->firstSourceLocation(), tr("Expected true or false after colon."));
+ return false;
+ }
+
+ return trueLit;
+}
+
+double TypeDescriptionReader::readNumericBinding(AST::UiScriptBinding *ast)
+{
+ QTC_ASSERT(ast, return qQNaN());
+
+ if (!ast->statement) {
+ addError(ast->colonToken, tr("Expected numeric literal after colon."));
+ return 0;
+ }
+
+ ExpressionStatement *expStmt = AST::cast<ExpressionStatement *>(ast->statement);
+ if (!expStmt) {
+ addError(ast->statement->firstSourceLocation(), tr("Expected numeric literal after colon."));
+ return 0;
+ }
+
+ NumericLiteral *numericLit = AST::cast<NumericLiteral *>(expStmt->expression);
+ if (!numericLit) {
+ addError(expStmt->firstSourceLocation(), tr("Expected numeric literal after colon."));
+ return 0;
+ }
+
+ return numericLit->value;
+}
+
+ComponentVersion TypeDescriptionReader::readNumericVersionBinding(UiScriptBinding *ast)
+{
+ ComponentVersion invalidVersion;
+
+ if (!ast || !ast->statement) {
+ addError((ast ? ast->colonToken : SourceLocation()), tr("Expected numeric literal after colon."));
+ return invalidVersion;
+ }
+
+ ExpressionStatement *expStmt = AST::cast<ExpressionStatement *>(ast->statement);
+ if (!expStmt) {
+ addError(ast->statement->firstSourceLocation(), tr("Expected numeric literal after colon."));
+ return invalidVersion;
+ }
+
+ NumericLiteral *numericLit = AST::cast<NumericLiteral *>(expStmt->expression);
+ if (!numericLit) {
+ addError(expStmt->firstSourceLocation(), tr("Expected numeric literal after colon."));
+ return invalidVersion;
+ }
+
+ return ComponentVersion(_source.mid(numericLit->literalToken.begin(), numericLit->literalToken.length));
+}
+
+int TypeDescriptionReader::readIntBinding(AST::UiScriptBinding *ast)
+{
+ double v = readNumericBinding(ast);
+ int i = static_cast<int>(v);
+
+ if (i != v) {
+ addError(ast->firstSourceLocation(), tr("Expected integer after colon."));
+ return 0;
+ }
+
+ return i;
+}
+
+void TypeDescriptionReader::readExports(UiScriptBinding *ast, FakeMetaObject::Ptr fmo)
+{
+ QTC_ASSERT(ast, return);
+
+ if (!ast->statement) {
+ addError(ast->colonToken, tr("Expected array of strings after colon."));
+ return;
+ }
+
+ ExpressionStatement *expStmt = AST::cast<ExpressionStatement *>(ast->statement);
+ if (!expStmt) {
+ addError(ast->statement->firstSourceLocation(), tr("Expected array of strings after colon."));
+ return;
+ }
+
+ ArrayPattern *arrayLit = AST::cast<ArrayPattern *>(expStmt->expression);
+ if (!arrayLit) {
+ addError(expStmt->firstSourceLocation(), tr("Expected array of strings after colon."));
+ return;
+ }
+
+ for (PatternElementList *it = arrayLit->elements; it; it = it->next) {
+ StringLiteral *stringLit = AST::cast<StringLiteral *>(it->element->initializer);
+ if (!stringLit) {
+ addError(arrayLit->firstSourceLocation(), tr("Expected array literal with only string literal members."));
+ return;
+ }
+ QString exp = stringLit->value.toString();
+ int slashIdx = exp.indexOf(QLatin1Char('/'));
+ int spaceIdx = exp.indexOf(QLatin1Char(' '));
+ ComponentVersion version(exp.mid(spaceIdx + 1));
+
+ if (spaceIdx == -1 || !version.isValid()) {
+ addError(stringLit->firstSourceLocation(), tr("Expected string literal to contain 'Package/Name major.minor' or 'Name major.minor'."));
+ continue;
+ }
+ QString package;
+ if (slashIdx != -1)
+ package = exp.left(slashIdx);
+ QString name = exp.mid(slashIdx + 1, spaceIdx - (slashIdx+1));
+
+ // ### relocatable exports where package is empty?
+ fmo->addExport(name, package, version);
+ }
+}
+
+void TypeDescriptionReader::readMetaObjectRevisions(UiScriptBinding *ast, FakeMetaObject::Ptr fmo)
+{
+ QTC_ASSERT(ast, return);
+
+ if (!ast->statement) {
+ addError(ast->colonToken, tr("Expected array of numbers after colon."));
+ return;
+ }
+
+ ExpressionStatement *expStmt = AST::cast<ExpressionStatement *>(ast->statement);
+ if (!expStmt) {
+ addError(ast->statement->firstSourceLocation(), tr("Expected array of numbers after colon."));
+ return;
+ }
+
+ ArrayPattern *arrayLit = AST::cast<ArrayPattern *>(expStmt->expression);
+ if (!arrayLit) {
+ addError(expStmt->firstSourceLocation(), tr("Expected array of numbers after colon."));
+ return;
+ }
+
+ int exportIndex = 0;
+ const int exportCount = fmo->exports().size();
+ for (PatternElementList *it = arrayLit->elements; it; it = it->next, ++exportIndex) {
+ NumericLiteral *numberLit = cast<NumericLiteral *>(it->element->initializer);
+ if (!numberLit) {
+ addError(arrayLit->firstSourceLocation(), tr("Expected array literal with only number literal members."));
+ return;
+ }
+
+ if (exportIndex >= exportCount) {
+ addError(numberLit->firstSourceLocation(), tr("Meta object revision without matching export."));
+ return;
+ }
+
+ const double v = numberLit->value;
+ const int metaObjectRevision = static_cast<int>(v);
+ if (metaObjectRevision != v) {
+ addError(numberLit->firstSourceLocation(), tr("Expected integer."));
+ return;
+ }
+
+ fmo->setExportMetaObjectRevision(exportIndex, metaObjectRevision);
+ }
+}
+
+void TypeDescriptionReader::readEnumValues(AST::UiScriptBinding *ast, LanguageUtils::FakeMetaEnum *fme)
+{
+ if (!ast)
+ return;
+ if (!ast->statement) {
+ addError(ast->colonToken, tr("Expected object literal after colon."));
+ return;
+ }
+
+ ExpressionStatement *expStmt = AST::cast<ExpressionStatement *>(ast->statement);
+ if (!expStmt) {
+ addError(ast->statement->firstSourceLocation(), tr("Expected object literal after colon."));
+ return;
+ }
+
+ ObjectPattern *objectLit = AST::cast<ObjectPattern *>(expStmt->expression);
+ if (!objectLit) {
+ addError(expStmt->firstSourceLocation(), tr("Expected object literal after colon."));
+ return;
+ }
+
+ for (PatternPropertyList *it = objectLit->properties; it; it = it->next) {
+ PatternProperty *assignement = AST::cast<PatternProperty *>(it->property);
+ if (assignement) {
+ StringLiteralPropertyName *propName = AST::cast<StringLiteralPropertyName *>(assignement->name);
+ NumericLiteral *value = AST::cast<NumericLiteral *>(assignement->initializer);
+ UnaryMinusExpression *minus = AST::cast<UnaryMinusExpression *>(assignement->initializer);
+ if (minus)
+ value = AST::cast<NumericLiteral *>(minus->expression);
+ if (!propName || !value) {
+ addError(objectLit->firstSourceLocation(), tr("Expected object literal to contain only 'string: number' elements."));
+ continue;
+ }
+
+ double v = value->value;
+ if (minus)
+ v = -v;
+ fme->addKey(propName->id.toString(), v);
+ continue;
+ }
+ PatternPropertyList *getterSetter = AST::cast<PatternPropertyList *>(it->next);
+ if (getterSetter)
+ addError(objectLit->firstSourceLocation(), tr("Enum should not contain getter and setters, but only 'string: number' elements."));
+ }
+}
diff --git a/tools/qmllint/qmljstypedescriptionreader.h b/tools/qmllint/qmljstypedescriptionreader.h
new file mode 100644
index 0000000000..df215af8d2
--- /dev/null
+++ b/tools/qmllint/qmljstypedescriptionreader.h
@@ -0,0 +1,103 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the tools applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QMLJSTYPEDESCRIPTIONREADER_H
+#define QMLJSTYPEDESCRIPTIONREADER_H
+
+#include <private/qqmljsastfwd_p.h>
+#include "fakemetaobject.h"
+
+// for Q_DECLARE_TR_FUNCTIONS
+#include <QCoreApplication>
+
+QT_BEGIN_NAMESPACE
+class QIODevice;
+class QBuffer;
+
+namespace QQmlJS {
+
+class ModuleApiInfo
+{
+public:
+ QString uri;
+ LanguageUtils::ComponentVersion version;
+ QString cppName;
+};
+
+
+class TypeDescriptionReader
+{
+ Q_DECLARE_TR_FUNCTIONS(QQmlJS::TypeDescriptionReader)
+
+public:
+ explicit TypeDescriptionReader(const QString &fileName, const QString &data);
+ ~TypeDescriptionReader();
+
+ bool operator()(
+ QHash<QString, LanguageUtils::FakeMetaObject::ConstPtr> *objects,
+ QList<ModuleApiInfo> *moduleApis,
+ QStringList *dependencies);
+ QString errorMessage() const;
+ QString warningMessage() const;
+
+private:
+ void readDocument(AST::UiProgram *ast);
+ void readModule(AST::UiObjectDefinition *ast);
+ void readDependencies(AST::UiScriptBinding *ast);
+ void readComponent(AST::UiObjectDefinition *ast);
+ void readModuleApi(AST::UiObjectDefinition *ast);
+ void readSignalOrMethod(AST::UiObjectDefinition *ast, bool isMethod, LanguageUtils::FakeMetaObject::Ptr fmo);
+ void readProperty(AST::UiObjectDefinition *ast, LanguageUtils::FakeMetaObject::Ptr fmo);
+ void readEnum(AST::UiObjectDefinition *ast, LanguageUtils::FakeMetaObject::Ptr fmo);
+ void readParameter(AST::UiObjectDefinition *ast, LanguageUtils::FakeMetaMethod *fmm);
+
+ QString readStringBinding(AST::UiScriptBinding *ast);
+ bool readBoolBinding(AST::UiScriptBinding *ast);
+ double readNumericBinding(AST::UiScriptBinding *ast);
+ LanguageUtils::ComponentVersion readNumericVersionBinding(AST::UiScriptBinding *ast);
+ int readIntBinding(AST::UiScriptBinding *ast);
+ void readExports(AST::UiScriptBinding *ast, LanguageUtils::FakeMetaObject::Ptr fmo);
+ void readMetaObjectRevisions(AST::UiScriptBinding *ast, LanguageUtils::FakeMetaObject::Ptr fmo);
+ void readEnumValues(AST::UiScriptBinding *ast, LanguageUtils::FakeMetaEnum *fme);
+
+ void addError(const AST::SourceLocation &loc, const QString &message);
+ void addWarning(const AST::SourceLocation &loc, const QString &message);
+
+ QString _fileName;
+ QString _source;
+ QString _errorMessage;
+ QString _warningMessage;
+ QHash<QString, LanguageUtils::FakeMetaObject::ConstPtr> *_objects;
+ QList<ModuleApiInfo> *_moduleApis = nullptr;
+ QStringList *_dependencies = nullptr;
+};
+
+} // namespace QQmlJS
+QT_END_NAMESPACE
+
+#endif // QMLJSTYPEDESCRIPTIONREADER_H
diff --git a/tools/qmllint/qmllint.pro b/tools/qmllint/qmllint.pro
index 91ab2f8afc..76363a7cd8 100644
--- a/tools/qmllint/qmllint.pro
+++ b/tools/qmllint/qmllint.pro
@@ -2,8 +2,22 @@ option(host_build)
QT = core qmldevtools-private
-SOURCES += main.cpp
+SOURCES += main.cpp \
+ componentversion.cpp \
+ fakemetaobject.cpp \
+ findunqualified.cpp \
+ qmljstypedescriptionreader.cpp \
+ qcoloroutput.cpp \
+ scopetree.cpp
QMAKE_TARGET_DESCRIPTION = QML Syntax Verifier
load(qt_tool)
+
+HEADERS += \
+ componentversion.h \
+ fakemetaobject.h \
+ findunqualified.h \
+ qmljstypedescriptionreader.h \
+ qcoloroutput_p.h \
+ scopetree.h
diff --git a/tools/qmllint/scopetree.cpp b/tools/qmllint/scopetree.cpp
new file mode 100644
index 0000000000..b064117dd4
--- /dev/null
+++ b/tools/qmllint/scopetree.cpp
@@ -0,0 +1,255 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the tools applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "scopetree.h"
+
+#include "qcoloroutput_p.h"
+
+#include <QQueue>
+
+ScopeTree::ScopeTree(ScopeType type, QString name, ScopeTree *parentScope)
+ : m_parentScope(parentScope), m_name(name), m_scopeType(type) {}
+
+ScopeTree *ScopeTree::createNewChildScope(ScopeType type, QString name) {
+ Q_ASSERT(type != ScopeType::QMLScope|| !m_parentScope || m_parentScope->m_scopeType == ScopeType::QMLScope || m_parentScope->m_name == "global");
+ auto childScope = new ScopeTree{type, name, this};
+ m_childScopes.push_back(childScope);
+ return childScope;
+}
+
+ScopeTree *ScopeTree::parentScope() {
+ return m_parentScope;
+}
+
+void ScopeTree::insertJSIdentifier(QString id, QQmlJS::AST::VariableScope scope)
+{
+ Q_ASSERT(m_scopeType != ScopeType::QMLScope);
+ if (scope == QQmlJS::AST::VariableScope::Var) {
+ auto targetScope = this;
+ while (targetScope->scopeType() != ScopeType::JSFunctionScope) {
+ targetScope = targetScope->m_parentScope;
+ }
+ targetScope->m_currentScopeJSIdentifiers.insert(id);
+ } else {
+ m_currentScopeJSIdentifiers.insert(id);
+ }
+}
+
+void ScopeTree::insertQMLIdentifier(QString id)
+{
+ Q_ASSERT(m_scopeType == ScopeType::QMLScope);
+ m_currentScopeQMLIdentifiers.insert(id);
+}
+
+void ScopeTree::insertSignalIdentifier(QString id, LanguageUtils::FakeMetaMethod method, QQmlJS::AST::SourceLocation loc)
+{
+ Q_ASSERT(m_scopeType == ScopeType::QMLScope);
+ m_injectedSignalIdentifiers.insert(id, {method, loc});
+}
+
+void ScopeTree::insertPropertyIdentifier(QString id)
+{
+ this->insertQMLIdentifier(id);
+ LanguageUtils::FakeMetaMethod method( id + QLatin1String("Changed"), "void");
+ this->addMethod(method);
+}
+
+bool ScopeTree::isIdInCurrentScope(const QString &id) const
+{
+ return isIdInCurrentQMlScopes(id) || isIdInCurrentJSScopes(id);
+}
+
+void ScopeTree::addIdToAccssedIfNotInParentScopes(const QPair<QString, QQmlJS::AST::SourceLocation> &id_loc_pair) {
+ if (!isIdInCurrentScope(id_loc_pair.first)) {
+ m_accessedIdentifiers.push_back(id_loc_pair);
+ }
+}
+
+bool ScopeTree::isVisualRootScope() const
+{
+ return m_parentScope && m_parentScope->m_parentScope && m_parentScope->m_parentScope->m_parentScope == nullptr;
+}
+
+QString ScopeTree::name() const
+{
+ return m_name;
+}
+
+struct IssueLocationWithContext
+{
+ IssueLocationWithContext(const QString& code, QQmlJS::AST::SourceLocation location) {
+ int before = std::max(0,code.lastIndexOf('\n', location.offset));
+ beforeText = code.midRef(before+1, location.offset - (before+1) );
+ issueText = code.midRef(location.offset, location.length);
+ int after = code.indexOf('\n', location.offset + location.length);
+ afterText = code.midRef(location.offset+location.length, after - (location.offset+location.length));
+ }
+
+ QStringRef beforeText;
+ QStringRef issueText;
+ QStringRef afterText;
+};
+
+bool ScopeTree::recheckIdentifiers(const QString& code, const QHash<QString, LanguageUtils::FakeMetaObject::ConstPtr> &qmlIDs, const ScopeTree *root, const QString& rootId, ColorOutput& colorOut) const
+{
+ bool noUnqualifiedIdentifier = true;
+
+ // revisit all scopes
+ QQueue<const ScopeTree*> workQueue;
+ workQueue.enqueue(this);
+ while (!workQueue.empty()) {
+ const ScopeTree* currentScope = workQueue.dequeue();
+ for (auto idLocationPair : currentScope->m_accessedIdentifiers) {
+ if (qmlIDs.contains(idLocationPair.first))
+ continue;
+ if (currentScope->isIdInCurrentScope(idLocationPair.first)) {
+ continue;
+ }
+ noUnqualifiedIdentifier = false;
+ colorOut.write("Warning: ", Warning);
+ auto location = idLocationPair.second;
+ colorOut.write(QString::asprintf("unqualified access at %d:%d\n", location.startLine, location.startColumn), Normal);
+ IssueLocationWithContext issueLocationWithContext {code, location};
+ colorOut.write(issueLocationWithContext.beforeText.toString(), Normal);
+ colorOut.write(issueLocationWithContext.issueText.toString(), Error);
+ colorOut.write(issueLocationWithContext.afterText.toString() + QLatin1Char('\n'), Normal);
+ int tabCount = issueLocationWithContext.beforeText.count(QLatin1Char('\t'));
+ colorOut.write(QString(" ").repeated(issueLocationWithContext.beforeText.length() - tabCount) + QString("\t").repeated(tabCount) + QString("^").repeated(location.length) + QLatin1Char('\n'), Normal);
+ // root(JS) --> program(qml) --> (first element)
+ if (root->m_childScopes[0]->m_childScopes[0]->m_currentScopeQMLIdentifiers.contains(idLocationPair.first)) {
+ ScopeTree *parentScope = currentScope->m_parentScope;
+ while (parentScope && parentScope->scopeType() != ScopeType::QMLScope) {
+ parentScope = parentScope->m_parentScope;
+ }
+ bool directChild = parentScope && parentScope->isVisualRootScope();
+ colorOut.write("Note: ", Info);
+ colorOut.write( idLocationPair.first + QLatin1String(" is a meber of the root element\n"), Normal );
+ if (directChild) {
+ colorOut.write(QLatin1String(" As the current element is a direct child of the root element,\n you can qualify the access with parent to avoid this warning:\n"), Normal);
+ } else {
+ colorOut.write(QLatin1String(" You can qualify the access with its id to avoid this warning:\n"), Normal);
+ if (rootId == QLatin1String("<id>")) {
+ colorOut.write("Note: ", Warning);
+ colorOut.write(("You first have to give the root element an id\n"));
+ }
+ }
+ colorOut.write(issueLocationWithContext.beforeText.toString(), Normal);
+ colorOut.write( (directChild ? QLatin1String("parent") : rootId) + QLatin1Char('.'), Hint);
+ colorOut.write(issueLocationWithContext.issueText.toString(), Normal);
+ colorOut.write(issueLocationWithContext.afterText + QLatin1Char('\n'), Normal);
+ } else if (currentScope->isIdInjectedFromSignal(idLocationPair.first)) {
+ auto qmlScope = currentScope->getCurrentQMLScope();
+ MethodUsage methodUsage = qmlScope->m_injectedSignalIdentifiers[idLocationPair.first];
+ colorOut.write("Note:", Info);
+ colorOut.write(idLocationPair.first + QString::asprintf(" is accessible in this scope because you are handling a signal at %d:%d\n", methodUsage.loc.startLine, methodUsage.loc.startColumn), Normal);
+ colorOut.write("Consider using a function instead\n", Normal);
+ IssueLocationWithContext context {code, methodUsage.loc};
+ colorOut.write(context.beforeText + QLatin1Char(' '));
+ colorOut.write("function(", Hint);
+ const auto parameters = methodUsage.method.parameterNames();
+ for (int numParams = parameters.size(); numParams > 0; --numParams) {
+ colorOut.write(parameters.at(parameters.size() - numParams), Hint);
+ if (numParams > 1) {
+ colorOut.write(", ", Hint);
+ }
+ }
+ colorOut.write(")", Hint);
+ colorOut.write(" {...", Normal);
+ }
+ colorOut.write("\n", Normal);
+ }
+ for (auto const& childScope: currentScope->m_childScopes) {
+ workQueue.enqueue(childScope);
+ }
+ }
+ return noUnqualifiedIdentifier;
+}
+
+QMap<QString, LanguageUtils::FakeMetaMethod>const &ScopeTree::methods() const
+{
+ return m_methods;
+}
+
+bool ScopeTree::isIdInCurrentQMlScopes(QString id) const
+{
+ auto qmlScope = getCurrentQMLScope();
+ return qmlScope->m_currentScopeQMLIdentifiers.contains(id);
+}
+
+bool ScopeTree::isIdInCurrentJSScopes(QString id) const
+{
+ auto jsScope = this;
+ while (jsScope) {
+ if (jsScope->m_scopeType != ScopeType::QMLScope && jsScope->m_currentScopeJSIdentifiers.contains(id))
+ return true;
+ jsScope = jsScope->m_parentScope;
+ }
+ return false;
+}
+
+bool ScopeTree::isIdInjectedFromSignal(QString id) const
+{
+ auto qmlScope = getCurrentQMLScope();
+ return qmlScope->m_injectedSignalIdentifiers.contains(id);
+}
+
+const ScopeTree *ScopeTree::getCurrentQMLScope() const
+{
+ auto qmlScope = this;
+ while (qmlScope && qmlScope->m_scopeType != ScopeType::QMLScope) {
+ qmlScope = qmlScope->m_parentScope;
+ }
+ return qmlScope;
+}
+
+ScopeTree *ScopeTree::getCurrentQMLScope()
+{
+ auto qmlScope = this;
+ while (qmlScope && qmlScope->m_scopeType != ScopeType::QMLScope) {
+ qmlScope = qmlScope->m_parentScope;
+ }
+ return qmlScope;
+}
+
+ScopeType ScopeTree::scopeType() {return m_scopeType;}
+
+void ScopeTree::addMethod(LanguageUtils::FakeMetaMethod method)
+{
+ m_methods.insert(method.methodName(), method);
+}
+
+void ScopeTree::addMethodsFromMetaObject(LanguageUtils::FakeMetaObject::ConstPtr metaObject)
+{
+ if (metaObject) {
+ auto methodCount = metaObject->methodCount();
+ for (auto i = 0; i < methodCount; ++i) {
+ auto method = metaObject->method(i);
+ this->addMethod(method);
+ }
+ }
+}
diff --git a/tools/qmllint/scopetree.h b/tools/qmllint/scopetree.h
new file mode 100644
index 0000000000..cb495584c1
--- /dev/null
+++ b/tools/qmllint/scopetree.h
@@ -0,0 +1,105 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the tools applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef SCOPETREE_H
+#define SCOPETREE_H
+
+#include "fakemetaobject.h"
+#include "private/qqmljsast_p.h"
+#include "private/qqmljssourcelocation_p.h"
+
+#include <QSet>
+#include <QString>
+#include <QMap>
+
+enum MessageColors{
+ Error,
+ Warning,
+ Info,
+ Normal,
+ Hint
+};
+
+enum class ScopeType
+{
+ JSFunctionScope,
+ JSLexicalScope,
+ QMLScope
+};
+
+struct MethodUsage
+{
+ LanguageUtils::FakeMetaMethod method;
+ QQmlJS::AST::SourceLocation loc;
+};
+
+class ColorOutput;
+
+class ScopeTree {
+public:
+ ScopeTree(ScopeType type, QString name="<none given>", ScopeTree* parentScope=nullptr);
+ ~ScopeTree() {qDeleteAll(m_childScopes);}
+
+ ScopeTree* createNewChildScope(ScopeType type, QString name);
+ ScopeTree* parentScope();
+
+ void insertJSIdentifier(QString id, QQmlJS::AST::VariableScope scope);
+ void insertQMLIdentifier(QString id);
+ void insertSignalIdentifier(QString id, LanguageUtils::FakeMetaMethod method, QQmlJS::AST::SourceLocation loc);
+ void insertPropertyIdentifier(QString id); // inserts property as qml identifier as well as the corresponding
+
+ bool isIdInCurrentScope(QString const &id) const;
+ void addIdToAccssedIfNotInParentScopes(QPair<QString, QQmlJS::AST::SourceLocation> const& id_loc_pair);
+
+ bool isVisualRootScope() const;
+ QString name() const;
+
+ bool recheckIdentifiers(const QString &code, const QHash<QString, LanguageUtils::FakeMetaObject::ConstPtr>& qmlIDs, const ScopeTree *root, const QString& rootId, ColorOutput &colorOut) const;
+ ScopeType scopeType();
+ void addMethod(LanguageUtils::FakeMetaMethod);
+ void addMethodsFromMetaObject(LanguageUtils::FakeMetaObject::ConstPtr metaObject);
+ QMap<QString, LanguageUtils::FakeMetaMethod>const & methods() const;
+
+private:
+ QSet<QString> m_currentScopeJSIdentifiers;
+ QSet<QString> m_currentScopeQMLIdentifiers;
+ QHash<QString, MethodUsage> m_injectedSignalIdentifiers; // need iteration in insertion order for hints, rarely more than 4 parameters needed
+ QMap<QString, LanguageUtils::FakeMetaMethod> m_methods;
+ QVector<QPair<QString, QQmlJS::AST::SourceLocation>> m_accessedIdentifiers;
+ QVector<ScopeTree*> m_childScopes;
+ ScopeTree *m_parentScope;
+ QString m_name;
+ ScopeType m_scopeType;
+
+ bool isIdInCurrentQMlScopes(QString id) const;
+ bool isIdInCurrentJSScopes(QString id) const;
+ bool isIdInjectedFromSignal(QString id) const;
+ const ScopeTree* getCurrentQMLScope() const;
+ ScopeTree* getCurrentQMLScope();
+};
+#endif // SCOPETREE_H